内容提要
- 回顾
- 运算符(细节)
- 流程控制
回顾
变量
概念:程序执行过程中可以改变的量就是变量。
- 变量代表的是内存中的一块存储单元,用来存放数据。
- 变量都有一个别名,一般称之为变量名,变量名的作用是引用变量。
语法:
// 声明变量的同时给变量赋值(变量的初始化)
// 如果不给变量赋初始值,系统会随机分配
int a = 10;
//先声明再赋值
int b;
b = 10;
//对变量的初始值进行覆盖式赋值
//基本数据类型(整型,浮点型,字符型):创建的变量,对应的内存中的存储区域是栈区。
// 栈区的特点:访问速度快 ,由系统自动申请自动释放,申请的内存单元的大小是固定值
int c = 10; // c:10
c = 20; // c:20
//同一类型的变量可以连续申请,使用逗号分隔
int a1,a2,a3;
a1 = 12;
a2 = 14;
a3 = 13;
int b1 = 12,b2 = 13,b3 = 14;
命令:
标识符:C语言中的标识符,包括变量名,函数名,数组名,结构体名,共用体名,枚举名等。
规则:
①必须以字母(a~z, A~Z)或者下划线(-)开头,只能包含字母,数字,下划线
②c编译系统对大小写敏感(区分大小写)
③不能使用 c提供的关键字和预处理指令作为自定义标识符
分类:
①小写字母+下划线命名:一般用于变量和函数,举例:_int,set_user,set()
②大写字母+下划线命名:一般用于符号常量和枚举,举例:_INT,SET_USER
基本类型数据
分类:
整型:short(2字节)int(4字节) long(32位系统:4字节 ,64位系统:8字节) longlong
浮点型:float(4字节) double(8字节 ) long double(gcc编译器:16字节)
字符型:char(1字节)
与内存的关系:
基本类型数据都是运行在内存中,他们在内存中是以二进制的方式存储的。(整型是以二进制补码的形式存在,浮点型针对指数部分和尾数部分分开存储,字符型在内存中存放的是字符对应的ASCII码的二进制形式)
关于原码,反码,补码:
①原码:我们程序中正常的数值转换出来的二进制就是原码
②反码:反码的作用就是实现原码到补码的转换,转换规则:原码除符号位取反产生反码 ,反码+1产生补码。
③补码:我们程序中的数据在内存中是以二进制补码形式存储的。
正数的原码,反码,补码一致;负数的原码,反码,补码不同
计算机底层没有减法运算 ,只有加法运算:比如:5-3,底层会进行转换:(5+(-3))
关于符号位:0代表正数,1代表负数
运算符
混合运算
①自动类型转换(隐式转换)
转换规则:由低到高,直接转换
1>(低)int →unsigned →long →double(高)
2>(低)char或者short→int(高)
3>(低)float→ double(高)
举例:int a = 10,double b = a + 12.3
注意:同一个表达式中,不同数据类型是无法参与运算的,运算的时候需要转换为同一数据类型,才能参与运算,这里的类型提升只是临时性的提升,并不会改变其原本的数据类型。
②强制类型转换(显示转换)
语法:(type)表达式
举例:(double)a,(int)(x+y),(int)x+y,(flloat)(5/3)
注意:强制类型转换的时候,也只是临时提升,并不会改变其在内存中的 存储大小,同时强制类型转换有风险,可能会丢失精度。最常见的转换是,小数转整数,会丢失小数部分。举例:double a = 12.5;int b = (int )a;输出后a = 12.5,b = 12.
运算符

表达式
表达式 = 运算数 + 运算符

运算符
算术运算符
基本的算术运算符
+,-
:正负值运算符(单目运算符:只有一个运算数 ),举例:+5,-5
+,-,*,/,%
:加减乘除取余运算符(双目运算符:有两个运算数),注意:进行除法运算时,除数不能为0
这些算术运算符的运输算顺序与数学上的运算顺序是相同的。
表达式和运算符的优先级与结核性
算术表达式:是指用算数运算符和括号将运算对象连接起来,符合c语言规范的式子,例如
a * b /c - 1.5 +'a'
-
表达式中各运算的运算顺序,必要时需要添加括号,例如:
(a+b)/(c+d) != a+b/c+d
-
表达式中各运算对象的数据类型,特别是整型相除,C语言规定,两个整数相除,其结果为整数。例如:
7/6的值为1 4/7的值为0 面试题:(1/2) + (1/2) 的结果是多少?正确答案是0
优先级与结核性:在表达式求解的时候,先按运算符的优先级级别的高低次序执行。若一个运算对象两侧的运算符的优先级相同,则按规定的结合方向处理
各种运算符的结合方向:
①算术运算的结合方向:"自左向右"也就是运算对象先于左边的运算符结合,例如:
a - b + c // 先执行a -b ,然后执行 +c运算
②有些运算符的结合方向:“自右向左”,也就是运算对象先与右边的运算符结合,例如:
i++
③若一个运算符两侧的数据类型不同,会自动转换成同类型后进行计算。
自增++,自增–运算符
作用:使变量的值增1或者减1
结合方向:“自右向左”
++i,–i
表示在使用该运算符对象之前,先让运算符自身增1或者减1,然后再使用他,也就是使用增1或者减1后的值,先计算,后使用
例如:
int n = 1; //n:1
int x = ++n; //x:2 ,n:2等价于n = n+1,x = n
i++,i–
表示在使用该运算符对象之后,才让运算符自身增1或者减1, 也就是先使用它的值,再让运算数自身增1或者减1,先使用,后计算
例如:
int n= 1; //n:1
int x = n++; //x:1 n:2等价于x= n,n = n+1
总结:不管是 ++i还是i++,运算数i自身都增1;同理不管是–i还是i–,运算数自身都减1,他们的不同之处在于(整体赋值)的先后顺序。
注意:
①增1与减1运算符只适用于整型变量或字符型变量,而不能 用于其它类型的变量
②增1与减1运算符不能用于常量或表达式,例如:
--5,(i+j)++
等都是违法的
课堂练习
要求:推导以下表达式的i和n的值
int i = 1;
int n = i++ + (++i) - (--i) + i--;
赋值运算符
“=”称之为赋值运算符,其作用是将一个数据赋值给一个变量。如:int a = 5;
执行赋值运算的结果,是将右边的数据存入左边变量对应的内存单元中,赋值运算顺序:自右向左
赋值规则
如果赋值运算符 两侧的类型不一致,则在赋值时进行 类型转换,转换规则为:
- 实型 -> 整型变量 :舍弃小数部分。例如:int a = 5.5,a的结果是5
- 整型->实型变量:数值不变,以浮点型存储。例如:double a = 5, a 的结果是5.000000
- 字符型->整型变量:放在整形的低8位,保持原值不变规则,例如:int a =‘A’

赋值表达式
主要实现赋值运算的表达式。
语法:
变量 = 表达式;
案例:
a = 5;
y = 2 * x +3;
a = a + 1;
作用:将右边表达式的值赋值给左边的变量。赋值表达式的取值取自左边变量的值。
复合赋值运算符
+=,-=,*=,/=,%=...(&=,|=,>>=,<<=,~=,^=)
左右两侧操作完毕后,赋值给左侧的变量,例如:
a += 3;等价于a = a + 3;
int c = 2;
c /= c; 等价于c = c/=c;
// ...其他复合赋值运算符类似
注意:
①在运算时,不能将 (=) 写作( ==)
②赋值运算符的优先级属于最低(除了逗号运算符以外)一般都是最后运算
关系运算符
表达式 = 运算数 + 运算符
定义:
>,<,>=,<=,==,!==
- 所有的关系运算符都是二目运算符(二元运算符,双目运算符),运算符的左侧和右侧可以是变量,可以是常量,,还可以是表达式。举例:a > b,5 > 6,a+b>c
- 关系运算符运算的结果是布尔类型,要么为真(非0,true-需要引入stdbool.h),要么为假(0,flase-需要引入stdbool.h)
说明:
1.标准c中没有布尔类型的,非0代表真,实际操作中使用数字1,0代表假
while(0)循环一次都不执行
while(1)死循环,无限循环
2.真在输出的结果为1,假在输出的结果为0
printf(“%d\n”,3<2);结果为0
printf(“%d\n”,3>2);结果为1
用作条件判断的时候,非0代表真,但是系统输出真的结果为1
注意:
①算术运算符的优先级高于关系运算符,例如:2 + 3 > 1 + 1等价于(2+3)>(1+1)
②关系运算符是二元(双目)运算符,不要连用,例如:
/*************************************************************************
> File Name: demo01.c
> Author: FPF
> Description:
> Created Time: 2025年02月08日 星期六 14时27分25秒
************************************************************************/
#include <stdio.h>
int main(int argc,char *argv[])
{
// 测试两个横等于
int score = 80;
printf("%d\n",0<score<=100);// 恒等于1
printf("%d\n",100>=score>0);// 恒等于1
printf("%d\n",60>=score>0); // 恒等于0
printf("%d\n",0<score<=60); // 恒等于1
return 0;
}
经过测试发现,不会报错,但是没有意义,程序中千万不能这么写!!!
正确得到写法:score> 0&&score <= 100
③不能将==
写成=
,==
:关系运算符,=
:赋值运算符
④一般浮点型进行比较,建议将两个数相减,结果和0进行比较,如果等于0,表示两个浮点数相等
举例1:
float a = 22.2;
float b = 22.2;
a == b; 不推荐这种写法
a - b == 0; 推荐这种写法
举例2:
float x = 2.0;
float y =11.1; //近似存储:11.099995
float z = x*y; //实际:22.199999,我们看到的是22.2
z == 22.2 //此时结果为假,所以这种写法不靠谱
两个浮点数的比较:两个浮点数相减跟0比 double a = 10; int b = 10; a == b;此时
a - b ==0; 结果为真,说明a等于b ,如果为假,a不等于b
a - b >0;结果为真,说明a大于b
a - b < 0;结果为真,说明a小于b
a - b == 0.000001:结果是真,人为的认为0.000001的误差能够接受,我们也认为a = b
逻辑运算符
运算结果要么为真(非0)要么为假(0)
!
:非(逻辑非)单目(一元)运算符,并且只能在操作数的左侧;非真即为假,非假即为真。(取反)
- 对一个数或者表达式去非奇数次,结果与原值相反,!(a%2!=0)取偶数次
- 对一个数或者表达式去非偶数次,结果与原值相反,!(a%2==0)取奇数次
&&
:与(逻辑与)双目(二元 )运算符,当左右两侧的数据都为真时,最终结果才为真(有假则为假)当逻辑与运算时,左侧为假,右侧结果不会影响最终的结果,因为右侧压根就不会执行,最终的结果就是左侧的结果,这种现象称之为短路效果(短路与),这是c语言中提供的一种惰性运算,就是减少运算次数。
案例:
5 > 6 && 6 > 5; // 0
||
:或(逻辑或)双目(二元)运算符,当左右两侧的数据都为假时,最终结果才会为假(有真则为真)当逻辑或运算时,==左侧为真,右侧结果不会影响最终的结果,右侧压根不再执行,最终结果就是左侧的结果,这种现象称之为短路效果(短路或),这是c语言中提供的一种惰性运算,就是减少运算次数。
案例:
5 > 6 || 6 > 5; //1
逗号运算符
作用:将若干个表达式“产量起来”,如:3+5,6+8;
别称:顺序求值运算符
逗号表达式
语法:
表达式1,表达式2,...,表达式n
求解过程:按从左到右的顺序分别计算各个表达式的值,其中最后一个表达式n的值就是整个逗号表达式的值
位运算
说明:按位(bit)来进行操作的运算符
语法:~,&,|,^,<<,>>
~:按位取反
说明:单目运算符,数据的每一个比特位取反,也就是二进制数位上0变1,1变0
演示:
0000 1010
1111 0101
举例:
unsigned char ret = ~0x05; // 0000 0101 ---> 1111 1010
printf("%d\n",~5); // -6
&:按位与
说明:双目运算符, 对于运算符左右的两个数,对应二进制数据位都为1时,结果为1,否则为0
演示:
0000 1010
1010 1000
0000 1000
举例:
5 & 6 = 4;// 0000 0101 & 0000 0110 = 0000 0100
|:按位或
说明:双目运算符,对于运算符左右的两个数,对应的二进制数据位有一个1,结果为1,否则为0
演示:
0000 1010
1010 1000
1010 1010
举例:
5|6=7; // 0000 0101 | 0000 0110 = 0000 0111
^:按位异或
说明:双目运算符,对于运算数左右的两个数,对应二进制数据位数据相同,结果为0,不同为1
演示:
0000 1010
1010 1000
1010 0010
举例:
5 ^ 6 = 3 //0000 0101 ^ 0000 0110 = 0000 0011
0000 0011 = 1 ∗ 2 1 1* 2^1 1∗21 + 1 ∗ 2 0 1* 2^0 1∗20 =3
<<:左移,按位往左偏移
说明:原操作数所有的二进制位数向左移动指定位
无符号左移:
-
语法:
操作数 << 移动位数
-
举例:
unsigned int a = 3 << 3; //计算规则:3 * 2 ^ 3 unsigned int b = 5 << 4; //计算规则:5 * 2 ^ 4
原数据3:00000000 00000000 00000000 00000011
左移3位:00000000 00000000 00000000 00011000
有符号左移:
-
语法:
操作数 << 移动位数
-
举例:
int a = 3 << 3; //-24 计算规则:-3 * 2 ^ 3 char b = 240 << 2; //960 计算规则: 240 * 2 ^ 2,很明显,此时计算结果有误。
-
注意;
- 如果移出的高位都是0,我们可以这样理解:a << n,可以看作是:$ a * 2^n$
- 如果移出的高位都是1,我们是不能使用上面的计算公式的。
>>:右移,按位往右偏移
说明:源操作数的所有的二进制操作数向右移动指定位,移出的数据舍弃。
如果操作数是无符号数:左边用0补齐
如果操作数是有符号数:左边用什么补全,取决于计算机系统;
- 逻辑右移:用0补全
- 算术右移:用1不全
大部分情况下,系统遵循“算术右移”
无符号右移:
语法:
操作数 >> 移动位数
举例:
unsigned char a = 3 >> 3 ; // 0
有符号右移:
语法:
操作数 >> 移动位数
举例:
char a = -3 >> 3; // -1