C语言 - 运算符和控制语句

算数运算符:

算术运算符

n++等价于n=n+1

n–等价于n=n-1

++i:先加减,后使用

i++:先使用,后加减

赋值运算符:

  • 符号=:把右边的值赋给左边的

赋值运算符

比较运算符(关系运算符):

比较运算符

  • 比较运算的结果只有两个取值,要么是真(非0 表示,默认使用1),要么是假(0 表示)。
  • 比较运算符“==”不能误写成“=

逻辑运算符:

逻辑运算符

  • 逻辑运算符提供逻辑判断功能,用于构建更复杂的表达式。
  • 对于逻辑运算符来说,任何非零值都表示真,零值表示假。比如, 5 || 0 会返回 1 , 5 && 0 会返回0 。

位运算符:

  • 位运算符的运算过程都是基于二进制的补码运算。

位运算符

  • 结合赋值运算符的经验,这里有:<<= 、 >>= 、 &= 、 ^= 等
  • 左移(<<):
    • 运算规则:在一定范围内,数据每向左移动一位,相当于原数据*2。(正数、负数都适用)
    • 当左移的位数n超过该数据类型的总位数时,相当于左移(n-总位数)位
    • 3<<4 类似于 32的4次幂 => 316 => 48
    • -3<<4 类似于 -32的4次幂 => -316 => -48
  • 右移(>>):
    • 运算规则:在一定范围内,数据每向右移动一位,相当于原数据/2。(正数、负数都适用)
    • 如果不能整除,向下取整
    • 右移运算符最好只用于无符号整数,不要用于负数。因为不同系统对于右移后如何处理负数的符号位,有不同的做法,可能会得到不一样的结果。
    • 69>>4 类似于 69/2的4次幂 = 69/16 =4
    • 69>>4 类似于 69/2的4次幂 = 69/16 =4
  • 异或(^):相同为0,不同为1
  • 对于一个二进制数a,使第 n 位不论是几都变成0,其它位不变:a=a&(~(1<<n));表示1左移n位,然后取反
  • 对于一个二进制数a,使第 n 位不论是几都变成1,其它位不变:a=a|(1<<n)

条件运算符:

  1. ()?():()
  2. 格式:(条件表达式)? 表达式1:表达式2
  3. 说明:条件表达式是如果为 true (非0值),就执行表达式1,否则执行表达式2。

sizeof运算符:

  1. 使用方法:sizeof(参数)

    • 参数可以是数据类型的关键字,也可以是变量名或某个具体的值
    • 返回某种数据类型或某个值占用的字节数量。
    1
    2
    3
    4
    5
    6
    int x = sizeof(int);  //通常是 4 或 8
    int i;
    sizeof(i); //通常是 4 或 8

    // 参数为数值
    sizeof(3.14); //浮点数的字面量一律存储为double类型,故返回 8
  2. sizeof返回值的类型说明:

    1. 不同的系统中,返回值的类型有可能是 unsigned int ,也有可能是unsigned long ,甚至是 unsigned long long ,对应的 printf() 占位符分别是 %u 、 %lu和 %llu 。
    2. C 语言提供了一个解决方法,创造了一个类型别名 size_t ,用来统一表示 sizeof 的返回值类型。该别名定义在 stddef.h 头文件里面,对应当前系统的 sizeof 的返回值类型,可能是 unsigned int ,也可能是 unsigned long 。
    3. printf() 有专门的占位符 %zd%zu ,用来处理 size_t 类型的值。
    1
    2
    size_t a=sizeof(int);
    printf("%zd\n", a);
    • 上面代码中,不管 sizeof 返回值的类型是什么, %zd 占位符(或 %zu )都可以正确输出。
    • 如果当前系统不支持 %zd 或 %zu ,可使用 %u (unsigned int)或 %lu (unsigned long int)代替。

运算符的优先级:

运算符优先级

  • 分不清优先级的时候,可以采用()来解决
  • 逗号运算符:(),() 输出结果是后面表达式的结果

if-else语句:

  1. if语句是互斥的
  2. if语句可以嵌套新的if语句

switch语句:

  1. switch 语句用于判断条件有多个常量结果的情况。
  2. 执行过程:
    • 第1步:根据switch中表达式的值,依次匹配各个case。如果表达式的值等于某个case中的常量值,则执行对应case中的执行语句。
    • 第2步:执行完此case的执行语句以后,如果遇到break,则执行break并跳出当前的switch-case结构,如果没有遇到break,则会继续执行当前case之后的其它case中的执行语句。—>case穿透,直到遇到break关键字或执行完所有的case及default的执行语句,跳出当前的switch-case结构
  3. 使用注意点:
    • case句中的值必须是常量,不能是变量名或不确定的表达式值或范围。
    • 同一个switch语句,所有case子句中的常量值互不相同。
    • 如果没有break,程序会顺序执行到switch结尾;从使用频率说,一般switch-case结构中,都需要编写break。
    • default子句是可选的。同时,位置也是灵活的。当没有匹配的case时,执行default语句。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
switch(表达式){
case 常量值1: //常量只能是字符型或整型的常量
语句块1;
break; //如果没有break,会继续执行下一个
case 常量值2:
语句块2;
break;
.......
case 常量值n:
语句块n;
break;
default: //都没有匹配到 执行这个
语句块n+1;
}
switch(表达式){
case 常量值1:
语句块1;
break;
case 常量值2:
case 常量值3:
case 常量值4:
case 常量值5://当上下输出结果相同时,上边可以省略不写
语句;
break;
.......
case 常量值n:
语句块n;
break;
default: //都没有匹配到 执行这个
语句块n+1;
}

for循环语句:

  1. 循环语句具有在某些条件满足的情况下,反复执行特定代码的功能

  2. 语法格式:

    1
    2
    3
    for (①初始化部分; ②循环条件部分; ④迭代部分){
    ③循环体部分;

    • for(;;)中的两个;不能多也不能少,而其他部分可以不写
    • ①初始化部分,用于初始化循环变量,只执行一次。可以声明多个变量,但必须是同一个类型,用逗号分隔
    • ②循环条件部分,只要为 true ,就会不断执行循环体;当值为false时,退出循环
    • ④迭代部分,每轮循环结束后执行,使得循环变量发生变化。可以有多个变量更新,用逗号分隔

while循环语句:

  1. 语法格式:

    1
    2
    3
    4
    5
    ①初始化部分
    while(②循环条件部分){
    ③循环体部分;
    ④迭代部分;
    }
  2. 说明:

    • while(循环条件部分)中循环条件为非零值,表示true、真;为零值,表示false、假。
    • 注意不要忘记声明④迭代部分。否则,循环将不能结束,变成死循环。
    • for循环和while循环可以相互转换。二者没有性能上的差别。实际开发中,根据具体结构的情况,选择哪个格式更合适、美观。
    • for循环与while循环的区别:初始化条件部分的作用域不同

do-while循环语句:

  1. do-while 结构是 while 的变体,它会先执行一次循环体,然后再判断是否满足条件。如果满足的话,就继续执行循环体,否则跳出循环。

  2. 语法格式:

    1
    2
    3
    4
    5
    ①初始化部分;
    do{
    ③循环体部分
    ④迭代部分
    }while(②循环条件部分); //分号不要忘记
  3. 说明:

    • do{}while();最后有一个分号
    • do-while结构的循环体语句是至少会执行一次,这个和for和while是不一样的
    • 循环的三个结构for、while、do-while三者是可以相互转换的。

三种循环结构对比:

  • 三种循环结构都具有四个要素:
    • 初始化部分—–>只执行一次
    • 循环条件部分—>一定是布尔类型的结果
    • 循环体部分——>反复执行的代码
    • 迭代部分———>相关的变量会做更新、迭代
  • 从循环次数角度分析:
    • do-while循环至少执行一次循环体语句。
    • for和while循环先判断循环条件语句是否成立,然后决定是否执行循环体。
  • 如何选择:
    • 遍历有明显的循环次数(范围)的需求,选择for循环
    • 遍历没有明显的循环次数(范围)的需求,选择while循环
    • 如果循环体语句块至少执行一次,可以考虑使用do-while循环
    • 本质上:三种循环之间完全可以互相转换,都能实现循环的功能

break和continue关键字:

  1. 使用说明:

break-continue

goto关键字:

  1. 使用goto,可以实现无条件的语句的转移。

  2. 格式:

    1. goto 标号(标签);
    2. 其中,标号,属于标识符,以“:”为标记,位于某语句前面。
    3. 执行 goto 语句后,程序将跳转到指定标号处执行。这样可以随意将控制转移到程序中的任意一条语句上,然后执行它。
  3. 举例:

    1
    2
    3
    4
    5
    6
    7
    int main() {

    loop_label:printf("Hello, world!\n");
    goto loop_label;

    return 0;
    }
    • loop_label是一个标签名,可以放在正常语句的前面。程序执行到 goto 语句,就会跳转到它指定的标签名位置继续执行。因此,上面的代码会产生无限循环。
    • 实际使用中,goto语句通常与条件语句配合。可用来实现条件转移,跳出循环体等功能。

参考链接: