软件开发概览
学习的标准
思维缜密 逻辑清晰 知识点能够通俗易懂的复述和编码
软件开发的分类
按照职责的不同,需求量比较大的常见的软件开发类型有:
移动开发(Andriod、IOS、Harmony)
- Andriod:Java、Kotlin
- IOS:Objective-C、Swift
前端开发(HTML、CSS、JavaScript、TypeScript)
后台开发(Java、C++、PHP、.NET、Python、Go)
嵌入式开发(C、C++、汇编)
……
软件开发的职责分工
C语言简介
电子计算机的发展史
第1代:电子管数字机(1946 - 1958年)
第2代:晶体管数字机(1958 - 1964年)
第3代:集成电路数字机(1946 - 1970年)
第4代:大规模集成电路机(1970年至今)
电路的逻辑状态只有0和1两个状态,0表示低电平,1表示低电平
因此,当代的电子计算机只能识别0和1
注意:计算机除了电子计算机,还有光子计算机、量子计算机、生物计算机、纳米计算机等
C语言的发展简史
C语言于1972年诞生于美国AT&T公司的贝尔实验室
- 由Dennis MacAlistair Ritchie(丹尼斯.里奇)发明,被称为是C语言之父
- C语言之所以命名为C,是因为它以B语言为基础发展而来
- B语言由Kenneth Thompson(肯.汤普森)发明
Thompson和Ritchie用C语言完全重写了UNIX操作系统(以前是用汇编语言)
- 随着UNIX的发展,C语言也得到了不断的完善
C语言的标准
为了利于C语言的全面推广,许多专家学者和硬件厂商联合组成了C语言标准委员会(美国国家标准协会,ANSI)
- 1989年,诞生了第一个完备的C标准,简称C89,也就是ANSI C
1990年,ANSI C被国际标准化组织ISO采纳,C语言在ISO有了一个官方名称ISO/IEC 9889:1990
- 9899是C语言在ISO标准中的代号,C++在ISO标准中的代号是14882
- 冒号后面的1990表示当前修订好的版本是在1990年发布的
- 对于ISO/IEC 9889:1990,有人称为C90或C89,是最初的C语言国际标准
1999年,正式发布ISO/IEC 9889:1999,简称为C99标准
2011年,正式发布ISO/IEC 9889:2011,简称为C11标准
C语言的用途
C语言可以说是其他高级编程语言的老祖宗,历史悠久
- 它的性能及其优越,在很多领域是其他编程语言无法取代的
凡是对性能要求极高的领域,基本都少不了C语言
- 操作系统开发(内核、驱动等,UNIX、Linux等著名操作系统就是利用C语言编写的)
- 数据库开发
- 高性能服务器开发
- 嵌入式开发
- 游戏开发
- ……
开发工具
记事本
- 功能单一、体验差、易出错、开发效率低
IDE(Integrated Development Environment): 集成开发环境
- 智能提示、高亮识别、语法检测、开发效率高(功能强大到超乎想象)
- 常见的C语言IDE有:Visual Studio、QT Creator、CLion、Dev C++
基本概念
程序的结构
任何一个C语言程序都有一个或多个函数(Function)构成
- 每个函数都有自己的功能
所以,以后编写的C语言代码,基本都是写在函数中
在有些编程语言中(例如Java),函数也叫做”方法(Method)”
main函数
每一个函数都有自己的名称
每一个函数的名称都是唯一的
默认情况下,C语言程序的运行入口点是main函数(翻译为:主函数,没有main函数,C语言程序是无法运行的
语法须知
C语言源代码(Source Code)文件的文件扩展名是.c
每一条语句(Stasement)后面都要以分号;结尾,是语句结束的标志
括号都是成对出现的
C语言是区分大小写的(大小写敏感,case-sensitive)
代码中用到的符号必须都是英文符号(注释、字符、字符串等的内容除外)
代码风格
该换行就换行
该缩进就缩进(按Tab键缩进、按Shift + Tab键反缩进)
该留空格就留空格(一般就留一个空格)
编译、链接知识
编译:将C语言源代码文件编译成可重定位二进制目标文件(以.o或.obj作为扩展名),由编译器(complier)来完成
链接:将所有目标文件以及所需要的库文件合并成一个可执行文件(executable file),由链接器(linker)来完成
编译、链接的细节
常见的C语言编译器有(已经内置了链接器)
MSVC:微软出品(用在windows中)
GCC:GNU Compiler Collection的缩写,GNU出品
MinGW:Minimalist GNU for Windows的缩写 ,GNU出品(用在Windows中)
LLVM:常用于苹果的开发工具中
……
对于同一份源代码,经过不同的编译器编译出来的目标文件(体积、格式、运行效率等)是不一样的
对于不同平台(操作系统),最后链接产生的可执行文件格式也是不同的
- Windows:PE格式(经常以.exe作为文件扩展名)
- Linux:ELF格式
- Mac:Mach - O格式
注释
什么是注释
- 注释常用来解释某段代码的具体含义、作用
- 注释并不会被当做正常代码进行编译
- 注释再很多IDE中的默认颜色都是偏绿色
C语言的注释有两种书写风格
- 多行注释(也被称为C风格注释)
- 单行注释(C99开始有,也被称为C++风格注释)
注释的嵌套
- 单行注释可以嵌套单行注释、多行注释
- 多行注释不能嵌套多行注释
多写注释的好处
- 方便回忆、检查代码
- 方便程序员之间的团队协作、提高开发效率
- 方便旧项目的交接
注释常用技巧
- 用来检验功能
- 用来定位BUG
变量(Variable)
变量的作用
可以存储程序运行中会变化的数据
如何声明(declare)一个变量
变量类型 变量名;
变量类型决定了变量能够存储什么类型的数据
如何给变量赋值
- 赋值(assign): 将数据交给变量去存储
- 变量名 = 数据;
- 这个等号 = 表示赋值,会将右边的数据赋值给左边的变量
在变量声明完毕后,可以直接通过变量名访问,不用带上变量类型
变量的细节
变量可以被多次赋值,新值会覆盖旧值
变量的第一次赋值,一般叫做初始化(initialize)
变量可以在声明的同时进行初始化
变量在未被初始化之前,它的值是不确定的
变量在使用之前必须要进行初始化
可以同时声明多个同类型的变量
可以将一个变量的值赋值给另一个变量
变量的作用域(scope)
变量的作用域:就是指变量的作用范围、有效使用范围
- 从声明变量的那条语句开始,直到变量所在的大括号结束
int main()
{
printf("%d",age1); //错误
printf("%d",age2); //错误
int age1 = 10;
printf("%d",age1); //正确
printf("%d",age2); //错误
{
int age2 = 20;
printf("%d",age1); //正确
printf("%d",age2); //正确
}
printf("%d",age1); //正确
printf("%d",age2); //错误
return 0;
}
变量的作用域细节
- 在同一个作用域内,不允许有同名的变量
int main()
{
//有歧义(二义性)
int age = 10; //正确
int age = 20; //错误
return 0;
}
int test()
{
int age = 30; //正确
return 0;
}
int main()
{
int age = 10;
{
int age = 20;
{
int age = 30;
printf("3age = %d\n",age);
}
printf("2age = %d\n",age);
}
printf("1age = %d\n",age);
return 0;
}
//result:30 20 10
变量的存储
变量的内存地址是指首字节的内存地址,首字节是指地址值最小的那个字节
越晚定义的变量,内存地址越小
大小端模式
大小端模式:决定了多字节数据的字节存储顺序
大端模式(Big-endian):高低低高
- 高字节放在低地址,低字节放在高地址
小端模式(Little-endian):高高低低
- 高字节放在高地址,低字节放在低地址
不同CPU架构的模式不一样
- 比如x86架构是小端模式
- 有些CPU架构是大端模式
- 目前比较常见的是小端模式
int类型的存储
字符的存储细节
计算机中的数据都是以二进制形式存储的,字符数据也不例外
- 每一个自负都会被转化成对应的整数值进行存储
在1967年,美国发布了ASCII码表,里面规定了128个单字节字符对应的整数值(ASCII码值)
int i =97;
char c1 = 'a';
cahr c2 = 'A';
ASCII码表
ASCII,全称是American Standard Code for Information Interchang,译为”美国信息交换标准码”,是一种标准的单字节字符编码方案
- 共128个字符,码值范围:0-127(也就是0x00-0x7F)
- 有33个是控制字符或通信专用字符,码值范围:0-31、127
- 控制字符:LF(换行)、DEL(删除)、BS(退格)等
- 通信专用字符:SOH(文头)、EOT(文尾)、ACk(确认)等
- 有95个可显示字符,码值范围:32-126
- 48-57:十个阿拉伯数字(0~9)
- 65-90:26个大写英文字母(A~Z)
- 97-122:26个小写英文字母(a~z)
- 其余为一些标点符号、运算符等
#include <stdio.h>
int main ( void )
{
puts ( "Printable ASCII:" ) ;
for ( int i = 32 ; i < 127 ; ++ i ) {
putchar ( i ) ;
putchar ( i % 16 == 15 ? ' \n ' : ' ' ) ;
}
}
/*
Printable ASCII:
! " # $ % & ' ( ) * + , - . /
0 1 2 3 4 5 6 7 8 9 : ; < = > ?
@ A B C D E F G H I J K L M N O
P Q R S T U V W X Y Z [ \ ] ^ _
` a b c d e f g h i j k l m n o
p q r s t u v w x y z { | } ~
*/
字符串 (String)
用双引号包住的内容叫做:字符串(由若干个【字符】组成的一串数据)
和注释类似,字符串里的内容可以随便写
标识符(Identifier)
标识符:由开发者自定义的一些名称(比如变量名、函数名等)
标识符的命名规则大致如下
- 不限长度
- 可以使用数字、下划线、英文字母
- 可以使用以\u及\U转义记号指定的Unicode字符(从C99开始)
- 不能以数字开头
- 不能使用关键字
标识符的命名规范(命名建议)
- 尽量用正确的英文单词命名,见名知意
当名称中包含多个单词时
小驼峰(第一个单词的首字母小写,其它单词的首字母大写)(mHandle)
大驼峰(所有单词的首字母大写)
用下划线连接
关键字(Keyword)
关键字,也叫做保留字(reserved word)
- 是编程语言内部已经定义好的一些有特殊含义的符号
C语言的关键字如下所示
字面量(Literal)
字面量:直接写出来的一个固定值
int age = 20;
double height = 1.68;
char *hody = "code";
char cc = 'm';
上面代码中,等号 = 右边的固定值都叫做字面量
代码中的进制书写形式
C语言标准规定
- 默认是十进制
- 以0开头是八进制
- 以0X或0x开头是十六进制
C语言标准并不支持二进制的书写形式
- 不过有些编译器支持,比如GCC规定以0b或0B开头是二进制
int a = 20;
printf("八进制:0%o\n",a);
printf("十六进制:0x%x\n",a);
有符号数的二进制表示方法
int 类型属于有符号整数类型(signed integer types)
- 可以表示正数、负数
有符号数的二进制有三种表示方法:原码、反码、补码
三种表示方法均有符号位和数值位两部分
- 符号位:最高位作为符号位,用0表示”正”,用1表示”负”
- 数值位:三种表示方法各不相同
正数的原码、反码、补码一致,负数则不一样,计算机用补码表示和存储数值
字符的使用细节
- 可以将char类型当做整数类型来使用
数字整数、数字字符、数字字符串
int i = 9;
char c = '9';
char *s = "9";
//10
printf("%d\n",i + 1);
//58
prinft("%d\n",c + 1);
//4210689
printf("%d\n",s + 1);
中文、日文、韩文等非英文字符是如何存储在计算机中的
- 首先,必然是以二进制的形式存储在计算机中
- 其次,每个字符对应的二进制数值取决于具体的编码方案
GBK主要支持CJK字符(C指中国、J指日本、K指朝鲜),而UTF-8支持几乎世界上所有的文字字符
转义序列(Escape sequences)
转义序列,一般也叫做转义字符,是一些有特殊含义的字符
scanf函数
scanf函数的功能是:输入(input),读取数据(比如读取通过键盘输入的数据)
scanf函数开始执行后,会等待用户输入
- 程序卡在scanf函数那里,不会执行scanf函数后面的代码
- 当用户敲Enter键(回车键)时,表示输入完毕
- 程序才会开始执行scanf函数后面的代码
循环中校验scanf输入
int n = 0;
while(n < 1 || n > 100)
{
printf("请输入1-100之间的正整数:");
scanf("%d",&n);
}
sancf函数 - 匹配的细节
- 当中途有匹配失败时,将结束匹配
当尝试把输入的数字赋值给字符变量时
- scanf把输入的数字当成是数字字符来处理
- 并不会把输入的数字当成是字符的ASCII码值来处理
scanf函数 —— 空白字符
空白字符包括:空格(‘ ‘)、Tab(‘\t’)、Enter(‘\n’)
如果在输入数据的开头,有一段任意长(长度 >= 0)连续空白字符,是不需要与格式化字符串中的字符进行匹配的
在格式化字符串中,任意长(长度 >= 0)连续空白字符能匹配输入的任意长(长度 >= 0)连续空白字符
数据类型
C语言拥有丰富多彩的数据类型,可以分为4大类型
void类型
基本类型(basic types)
- 字符类型(character types)
- 有符号整数类型(signed integer types)
- 无符号整数类型(unsigned integer types)
- 浮点类型(floating types)
枚举类型(enumerate)
派生类型(derived types)
- 数组类型(array types)
- 结构体类型(structure types)
- 联合体类型(union types)
- 函数类型(function types)
- 指针类型(pointer types)
- 原子类型(atomic types)
基本类型(Basic Types)
有符号整数类型(signed integer types)
- char (等价类型:signed char)
- short(等价类型:signed short、short int、signed short int)
- int(等价类型:signed int、signed)
- long(等价类型:signed long、long int、signed long int)(C99起)
- long long(等价类型:signed long long、long long int、signed long long int)(C99起)
无符号整数类型(unsigned integer types)
- unsigned char
- unsigned short(等价类型:unsigned short int)
- unsigned int(等价类型:undigned)
- undigned long(等价类型:unsigned long int)(C99起)
- unsigned long long(等价类型:unsigned long long int)(C99起)
- _Bool(C99起)
字符类型(character types)
char类型属于字符类型(character types)
一个char类型的变量占用一个字节的内存
- 所以它只能存储一个单字节字符
- 26个英文字母的大小写(a
z,AZ)、10个阿拉伯数字(0~9)等都是单字节字符
浮点类型(floating types)
- float、duoble、long double
整数类型的大小
C标准规定
- sizeof(long long) >= sizeof(long) >= sizeof(int) >= sizeof(short) >= sizeof(char) == 1
数据模型(Data Models)
- LP32(2/4/4):int为16位、long、指针为32位
- ILP32(4/4/4):int、long、指针均为32位
- LLP64(4/4/8):int、long为32位,指针为64位(Win64 API)
- LP64(4/4/8):int为32,long、指针为64位(Unix、类Unix系统(Linux、Mac OS X))
char、unsigned char区别
- c1、c2变量在内存中存放的二进制数据是完全一样的
- 对于同一份二进制数据,分别以有符号数形式、无符号数形式解读出来的含义可能是不一样的
整数的取值范围
char、unsigned char都只占用一个字节,能够存放的二进制数据范围都是【0b0000 0000,0b1111 1111】
- 有n个二进制位的有符号数的取值范围是【-2^n-1^,2^n-1^ - 1】
- 有n个二进制位的无符号数的取值范围是【0,2^n^ - 1 】
溢出
当出现溢出时,会优先保留低字节的数据,舍弃高字节的数据
所以在给取值范围小的变量赋值时,要注意防止数据溢出,否则,结果可能会跟预期不符合
无符号数和有符号数溢出时的钟表机制
浮点类型(Floating Types)
浮点类型可以用来表示小数(比如0.5),包括了float、double、long double类型
最常用浮点类型的是float和double,一般在数值后面加上f或者F表示是float类型的数值
float f = 1.45F;
double d = 1.89;
//1.450000 1.890000
printf("%f %f",f,d);
float:单精度(Single)浮点类型,占用32bit,可以保证精确到小数点后6位
- 最小值大约是:-3.4 * 10^38^,最大值大约是:3.4 * 10^38^
double:双精度(Double)浮点类型,占用64bit,可以保证精确到小数点后15位
- 最小值大约是:-1.8 * 10^308^,最大值大约是:1.8 * 10^308^
浮点类型的存储细节
浮点数在计算机中是按照IEEE 754标准存储的
printf中的转换格式指定符
printf中常用的转换格式指定符(conversion format specifier)如下所示
printf("zd\n",sizeof(int));
long long age = 10LL;
printf("%lld\n",age);
unsigend long no =8UL;
printf("lu%\n",no);
printf格式符细节
- 用%%来显示一个%
- 用%6d表示占用6个字符位置,默认靠右对齐
- %-6d中的减号( - )表示靠左对齐
- %+6d中的加号( + )表示显示正负号
- %.2f表示四舍五入保留2位小数
类型转换
强制类型转换
类型1 v1 = xx;
类型2 v2 = (类型2) v1;
隐式类型转换
在进行一些算数运算时,小类型会被隐式转换成大类型
- char < short < int < long < long long < float < double < long double
注意:任何小于int的整数类型,在运算时会隐式转换为int类型
char c = 97;
short s =10;
// 1 2
printf("%zd %zd\n",sizeof(c),sizeof(s));
// 4 4
printf("%zd %zd\n",sizeof(+c),sizeof(-s));
// 4 4
printf("%zd %zd\n",sizeof(c + s),sizeof(c/s));
// 4
printf("%zd \n",sizeof('A'));
运算符(Operators)
C语言常用运算符,如下表所示
算术运算符(Arithemetic Operators)
- 模运算符不能用在浮点数上
- 模运算结果的正负性跟随运算符左边的操作数
printf("%d\n",10%-7);//3
printf("%d\n",-10%7);//-3
printf("%d\n",-10%-7);//-3
位运算符(Bitwise Operators)
位运算符,属于算数运算符,位运算符的运算数只能是整数
- 位移运算符b的值必须为非负整数
- 左移低位补0
- 右移高位用符号位填充
按位逻辑运算符,也叫逐位逻辑运算符,留意下与位运算相关的赋值运算符即可
位运算的实践应用
尽量使用位运算取代乘(*)、除(/)、模(%)运算,因为位运算效率比它们高
用a & 1来判断a的奇偶性
int a = 30;
printf("%s",(a & 1) ? "奇数" : "偶数");
- 不使用第三方变量交换两个整形变量的值
a = a + b; // a = a * b; // a = a - b; // a = a ^ b; //
b = a - b; // b = a / b; // b = a + b; // b = a ^ b; //
a = a - b; // a = a / b; // a = b - a; // a = a ^ b; //
前三种方法可能有溢出产生bug,而异或操作则不用担心,虽然省了空间,但时间增加了
按位亦或的特点
- a ^ 0 = a
- a ^ a = 0
- a ^ b = b ^ a
- (a ^ b) ^ c == a ^ (b ^ c) == (a ^ c) ^ b
运算符的优先级
当一个表达式中同时使用多个运算符时
- 会根据运算符的优先级和结合性,来决定运算符的执行顺序
- 优先级越高(优先级值越小,越先被执行)
- 优先级一样,根据结合性决定执行顺序
- 为了确保优先级和代码可读性,应该多使用小括号
赋值运算符(Assignment Operators)
自增/自减运算符
自增/自减运算符(Increment/Decrement Operators)包括了
前缀(prefix)
- 自增运算符:++a
- 自减运算符:–a
后缀(postfix)
- 自增运算符:a++
- 自减运算符:a–
b = a++; //等效于下面3句代码 tmp = a; a += 1; b = tmp;
int a = 1;
int b = a++ + a++ + a++ + a++;
printf("%d %d\n",a,b);
//MSVC: b = 1 + 1 + 1 + 1 = 4
//MinG: b = 1 + 2 + 3 + 4 = 10
//不容易理解,可读性差,结果具有不确定性
//不建议在实际开发中变编写此类代码
最大吞噬规则(maximal much)
- 当多个运算符紧挨在一起时,编译器会按照最大吞噬规则去解析
int a = 1,b = 2;
int c = a +++ b;
// 2 2 3
printf("%d %d %d\n",a,b,c);
// 等价于int c = (a++) + b;
比较运算符(Comparison Operators)
- 比较运算符,也称为关系运算符(Relational Operators)
- 比较运算符的结果只可能是整数0和1
逻辑运算符(Logical Operators)
在C语言中,任何值都有真假性
- 任何非0的值都为”真”(比如59、1、-17、6.4、0.1、1.0、”123”、’K’等)
- 只有数值0才为”假”(比如0、0.0、’\0’等)
逻辑运算符的运算数可以是任何值,它的运算结果要么是真、要么是假
- 运算结果为真,就返回整数1
- 运算结果为假,就返回整数0
printf("%d\n",'0');// 1
printf("%d\n",'\0');// 0
printf("%d\n",!'666');// 0
在表示范围的时候,逻辑与(&&)是取交集(∩),逻辑或(||)是取并集(∪)
逻辑与的短路现象
a && b
如果a为假,就不会再去执行代码b。因为不管b是真是假,运算结果都为假
如果a为真,就还需要执行代码b。因为得知b是真是假,才知道运算结果
int a = 0; int b = 0; printf("%d\n",a++ && ++b); //0 printf("%d %d\n",a,b); // 1 0
逻辑或的短路现象
a || b
如果a为真,就不会再去执行代码b。因为不管b是真是假,运算结果都为真
如果a为假,就还需要执行代码b。因为得知b是真是假,才知道运算结果
int a = 0; int b = 0; printf("%d\n",++a || b++); //0 printf("%d %d\n",a,b); // 1 0
短路现象可以减少一些不必要的代码的执行,缩短了程序的执行时间
条件运算符(Conditional Operator)
- 条件运算符,一般也叫作三目运算符、三元运算符
- a ? b : c
- 如果a为真,就返回b
- 如果a为假,就返回c
//将整形变量a、b、c中的最大值打印出来
int a = 11, b = 22, c = 33;
// 33
printf("%d\n",(a > b) ? ((a > c) ? a : c)) : ((b > c) ? b : c));
/**
int a = 11, b = 22, c = 33;
int d = (a >b) ? a : b;
d = (c > d) ? c : d;
// 33
printf("%d\n",d);
**/
//如果字符变量c是小写字母,就转成大写字母;否则保持原样
char c = 'g';
c = (c >= 'a' %% c <= 'z') ? (c - 'a' + 'A') : c;
// G
printf("%c\n",c);
//有一个字符变量c,如果它是小写字母,就转成大写字母;如果它是大写字母,就转成小写字母;否则保持原样
char c = 'G';
int diff = 'a' - 'A';
c = (c >= 'a' && c <= 'z') ? (c - diff): ((c >= 'A' && c <= 'Z') ? (c + diff) : c);
// g
printf("%c\n",c);
逗号运算符(Comma Operator)
(a, b, ……)
- 从左到右依次执行表达式
- 返回最后一个表达式的运算结果
int a = (11, 22, 33);
int b = (a += 5, a = a > 0 ? 10 : -10, a++);
// 11 10
printf("%d %d",a,b);
流程控制(Flow Control)
按照执行程序流程的不同,可以将平时编写的代码分成3大结构
顺序结构:默认的流程结构,按照代码的书写顺序执行每一句代码
选择结构:根据表达式的真假性,来决定执行哪一段代码
循环结构:在表达式为真的情况下,重复执行某一段代码
选择结构
if语句
if语句陷阱
- 表达式后面多加分号,变成空语句
- 判断相等时 == 误写成赋值 =
if - else语句
if语句 vs if-else语句
// if else语句
int score = 70;
if(score >= 60)
{
printf("及格");
}
else
{
printf("不及格");
}
// 多个if语句
int score = 70;
if(score >= 60)
{
printf("及格");
}
if(score < 60)
{
printf("不及格");
}
if-else语句能实现的功能,完全也可以用多个if实现,更推荐if-else的写法
- if-else代码更简洁,省掉了不必要的”score < 60”的判断
- if-else的代码执行效率更高,只需要进行1次表达式判断:”score >= 60”
else if语句
输入一个整数代表分数,根据分数输出等级(A-E)
- A:90-100 ——B:80-89——C:70-79——D:60-69——E:0-59
//较复杂的写法
#include<stdio.h>
int main()
{
int score;
scanf("%d",&score);
if(90 <= score && score <= 100)
{
printf("A");
}
else if(80 <= score && score <= 89)
{
printf("B");
}
else if(70 <= score && score <= 79)
{
printf("C");
}
else if(60 <= score && score <= 69)
{
printf("D");
}
else if(0 <= score && score <= 60)
{
printf("E");
}
else
{
printf("非法输入");
}
}
//更简单的写法
#include<stdio.h>
int main()
{
int score;
scanf("%d",&score);
if(score < 0 || score > 100)
{
printf("非法输入");
}
else if(score >= 90)
{
printf("A");
}
else if(score >= 80)
{
printf("B");
}
else if(score >= 70)
{
printf("C");
}
else if(score >= 60)
{
printf("D");
}
else
{
printf("E");
}
}
else-if语句注意点
- else if中在对合法输入作限定后,应该将小范围写在前面,大范围写在后面
- 更推荐下面简单的写法,省掉了不必要的判断,代码执行效率更高
if语句 vs else if语句
//下面两段代码的功能是不一样的
//只有其中一个printf会被执行
int price = 200;
if(++price >= 100)//[100,+∞)
{
printf("太贵了\n");
}
else if(++price >= 50)//[50,100]
{
printf("还行吧\n");
}
else if(++price >= 10)//[10,50]
{
printf("很便宜\n");
}
//有可能三个printf都会被执行
int price = 200;
if(++price >= 100)//[100,+∞)
{
printf("太贵了\n");
}
if(++price >= 50)//[50,+∞)
{
printf("还行吧\n");
}
if(++price >= 10)//[10,+∞)
{
printf("很便宜\n");
}
当多段代码中,只需要选择其中一段来执行时,建议用else if语句
int value = 9;
if(value > 0)
{
printf("正数");
}
else if(value < 0)
{
printf("负数");
}
else
{
printf("0");
}
当多段代码可能都要被执行时,不能用else if语句
int value = 9;
if(value > 0)
{
printf("正数");
}
if(value & 1)
{
printf("奇数");
}
- if、else后可以省略大括号,只会跟其后的第一条语句进行关联
- 多个if出现,else后会跟其前面最接近的if相关联
if语句 ——编译错误
int price = 200;
if(price > 100)
{
printf("太贵了\n");
}
printf("买不起\n"); //夹在if与else中间 编译错误
else
{
printf("不算贵\n");
}
//注意if和else语句中变量的作用域
int a = 10;
if(a > 0)
{
int b = a++;
}
else
{
int c = a + b;//编译错误
}
printf("%d",a);
printf("%d",b);//编译错误
printf("%c",c);//编译错误
if-else语句 vs 条件运算符
有一些简单的if-else语句,可以使用条件运算符来替代,以达到简化代码的目的
表达式的等价性
switch语句
break语句
在switch语句中,break语句的作用:中止switch语句
如果case、default后面没有break语句,会出现”贯穿”现象
- 执行完case、default中的代码后,会继续往下执行其他case、default中的代码
- 直到遇到break语句或switch语句的结尾为止
//利用贯穿
switch(month)
{
case 3:
case 4:
case 5:
printf("春季");
break;
}
case的使用注意
- case后面紧跟的表达式不能带有变量
- 如果想在case后面声明新的变量,那就必须加上大括号,否则编译报错
if和switch之间可以相互替代
if和switch的选择
- 当表示一个范围时,建议使用if
- 当判断一个变量是否等于一些固定值时,if、switch均可使用
循环结构
很多时候,使用while、do-while、for可以完成一样的功能,只是书写格式不一样
在实际开发中,使用频率最多的是for、while
while语句
while固定次数的打印
//1 - 2 + 3 - 4 + 5 - 6 ... + n
int value = 1;
int sum = 0;
while(value <= n)
{
sum += (value & 1) ? value : -value;
value++;
}
do-while语句
int n;
do{
printf("请输入1-100之间的正整数:");
scanf("%d",&n)
}while(n < 1 || n > 100);
printf("%d",n);
for语句
//请从小到大打印出3、5的前10个公倍数
for(int i = 0,count = 0; count < 10;i++)
{
if((i % 3 == 0) && (i % 5 == 0))
{
printf("%d",i);
count++;
}
}
for 语句 vs while语句
break语句
break语句只用在while、do-while、for、switch语句中
break语句的作用:终止其所在的while、do-while、for、switch语句
在有多重循环的情况下,break语句只能终止其所在的那一层循环语句
continue语句
- continue语句只用在while、do-while、for语句中
- continue语句的作用:跳过循环体的剩余部分
- 在有多重循环的情况下,continue语句只能作用于其所在的那一层循环语句
- 很多时候,巧用continue,可以减少大括号、缩进的数量
for (int i = 1,count = 0; count < 10; i++)
{
if(i % 3 != 0 || i % 5 != 0) continue;
printf("%d",i);
count++;
}
goto语句
- goto语句的作用:可以为所欲为地灵活跳转
- goto语句使用起来非常灵活,在有些情况下,还能提高程序的效率
- 但goto语句破坏了结构化的设计风格,容易造成代码执行流程的混乱,导致代码难以调试和维护