当前位置: 首页 > news >正文

【笔记ing】C语言补充、组成原理数据表示与汇编实战、操作系统文件实战(高级阶段)

【第19节 C语言语法进阶】

【19.1 条件运算符与逗号运算符】

1 条件运算符

条件运算符是C语言中唯一的一种三亩运算符。三目运算符代表有三个操作数;双目运算符代表有两个操作数,如逻辑运算符就是双目运算符;弹幕运算符代表有一个操作数,如逻辑非就是单目运算符。运算符也称操作符。三目运算符通过判断问号之前的表示的真假,来确定整体表达式的值,如下例所示,如果a>b为真,那么三目表达式整体的值为a,所以max的值等于a,如果a>b为假,那么三目表达式整体的值为b,所以max的值等于b。

#include <stdio.h>int main(){int a,b,max;while(scanf("%d%d",&a,&b)){max = a > b ? a : b;printf("max = %d\n",max);}return 0;
}

2 逗号运算符

逗号运算符的优先级最低,逗号表达式的整体值是最后一个表达式的值。

#include <stdio.h>
int main(){int i,j;i = 10;j = 1;if(i,--j){  // 不会进入if,逗号表达式整体的值是最后一个表达式的值,  j是-1printf("condition value is:j = %d,if excute\n",j);}if(i,++j){  // 进入if,逗号表达式整体的值是最后一个表达式的值,  j是0printf("condition value is:j = %d,if excute\n",j);}for (i = 0,j = 1; i < 10; i++) {  // 逗号表达式的常见场景,for的表达式1初始化多个变量用的较多}return 0;
}

【19.1 题】

1、条件运算符是C语言唯一的三目运算符,优先级高于赋值运算符。

2、max=a>b?a:b;通过这种方式max可以获取a和b中较大的那个数。

3、逗号运算符的优先级低于赋值运算符,逗号表达式的整体值是最后一个表达式的值。

【19.2 自增自减运算符】

1 自增自减运算符

自增、自减运算符和其他运算符有很大区别,因为其他运算符除赋值运算可以改变变量本身的值外,不会有这种效果。自增、自减就是对变量自身进行加1、减1操作,那么有了加法和减法运算符为啥还要发明这种运算符呢?原因是自增自减来源于B语言,当时ken thompson和dennis M.ritchie(C语言的发明者)为了不改变程序员的编写习惯,在C语言中保留了B语言的自增和自减。因为自增、自减会改变变量的值,所以自增和自减不能用于常量。

下例中的j=i++>-1,对于后++或者后--,需要去掉++或--运算符,也就是首先计算j=j>-1,因为i本身等于-1,所以得到j的值为0,接着单独计算i++,也就是对i加1,所以i从-1加1得到0,因此printf("i=%d,j=%d",i,j);语句的执行结果是0和0。

#include <stdio.h>
int main(){int i,j;i = -1;
//    5++;  // 编译不通,自增自减不能用于常量j = i++ > 1;  // j = i > 1;i++;printf("i = %d,j = %d",i,j);  // i = 0,j = 0return 0;
}

2 自增自减运算符与取值运算符

只有比后增优先级高的操作,才会走位一个整体,如()、[]

#include <stdio.h>
int main(){int a[3] = {2,7,8};int *p;int j;p = a;j = *p++;  // 先把*p的值赋给j,然后对p加1,j = a[0],p = a[1]printf("a[0] = %d,j = %d,*p = %d\n",a[0],j,*p);  // 2,2,7j = p[0]++;  // 先把p[0]的值赋给j,然后对p[0]加1,j = a[1],p = a[2]printf("a[0] = %d,j = %d,*p = %d\n",a[0],j,*p);  // 2,7,8return 0;
}

【19.2 题】

1、a=10,执行b=a++;后,a的值是11,b的值是10。

2、a=10,执行b=a--;后,a的值是9,b的值是10.

3、int a[3] = {2,7,8};int *p = a;执行了j = *p++;后,p指向元素a[1].整型指针变量加1,偏移4个字节,因此指向a[1]。

【19.3 位运算符】

1 位运算符

位运算符<<、>>、~、|、^、&依次是左移、右移、按位取反、按位或、按位异或、按位与。

位运算符只能用于对整型数据进行操作。

左移:高位丢弃,低位补0,相当于乘以2,一半申请内存时会用左移,例如要申请1GB大小的空间,可以使用malloc(1<<30)。

右移:低位丢弃,整数的高位补0(无符号数认为是正数),负数的高位补1,相当于除以2,移位比乘法和除法的效率要高,负数右移,对偶数来说是除以2,但对奇数来说是先减1后除以2。例如,-8>>1,得到的是-4,但-7>>1得到的并不是-3而是-4。另外,对于-1来说,无论右移多少位,值永远为-1.

C语言的左移和右移相当于是算数左移与算数右移。考研中的逻辑左移与右移,左移和右移空位都补0.

异或:相同的数进行异或时,结果为0,任何数和0异或的结果是其本身。

按位取反:数位上的数是1变为0,0变为1.

按位与和按位或:用两个数的每一位进行与和或。

// bit operator
#include <stdio.h>
int main(){short i = 5;short j;j = i << 1;  // j = i*2 = 10,i = 5printf("j = %d\n",j);  // j = 10j = i >> 1;  // j = i/2 = 2,i = 5printf("j = %d\n",j);  // j = 2i = 0x8011;  // 1000 0000 0001 0001unsigned short s = 0x8011;  // 1000 0000 0001 0001unsigned short r = 0;j = i >> 1;  //  i >> 1 = 11000 0000 0001 000 = 1100 0000 0000 1000 = A008r = s >> 1;  // s >> 1 = 01000 0000 0001 000 = 0100 0000 0000 1000 = 4008printf("j = %d,r = %d\n",j,r);i = 5,j = 7;  // 5 = 0000 0101,7 = 0000 0111printf("i & j = %d\n",i & j);  // 0000 0101 = 5printf("i | j = %d\n",i | j);  // 0000 0111 = 7printf("i ^ j = %d\n",i ^ j);  // 0000 0010 = 2printf("~i =  %d\n",~i);  // 按位取反的结果是负数,该负数是原数的补码,需要将补码转换成原数,原数是按位取反加1,再加上负号。return 0;
}

2 异或运算符示例解析

异或运算符有两个特性,一是任何数和零异或得到的是自身,两个相等的数异或得到的是零,通过这两个特性,可以在一堆数中找出出现1次的那个数,其他数是出现2次。异或满足交换律。

#include <stdio.h>// XOR Exclusive OR
int main(){int arr[5] = {8,5,3,5,8};int result = 0;  // 任何数和0异或都是自身for (int i = 0; i < 5; ++i) {result ^= arr[i];  // 两个相等的数异或得到的是零,异或满足交换律}printf("result = %d\n",result);return 0;
}

【19.3 题】

1、5&7得到的值是5.  // 0000 0101 & 0000 0111 = 0000 0101 = 5

2、5<<1得到的值是10,-7>>1得到的值是-4.  // 5左移1位=5*2=10,-7右移1位=(-7-1)/2=-4

3、5^5得到的值是0,7^0得到的值是7. // 数和本身异或结果都为0,相同的数异或结果为0;数和0异或结果都为数本身。

【19.4 switch do-while】

1 switch选择语句讲解

判断一个变量可以等于几个值或几十个值时,使用if和else if语句会导致else if分支非常多,这时可以考虑使用switch语句,switch语句的语法格式如下:

switch(表达式)
{case 常量表达式1:语句1case 常量表达式2:语句2...case 常量表达式n:语句ndefault:语句n+1
}

使用switch语句的例子。输入一个年份和月份,然后打印队医你给月份的天数,如输入一个闰年和2月,则输出为29天。具体代码如下所示,switch语句中case后面的常量表达式的值不是按照1到12的顺序排列的。switch语句匹配并不需要常量表达式的值有序排列,输入值等于哪个常量表达式的值,就执行其后的语句,每条语句后面需要加上break语句,代表匹配成功一个常量表达式时就不再匹配并跳出switch语句。

【例1】switch语句的使用。

#include <stdio.h>// switch
int main(){int year,month;while(scanf("%d%d",&year,&month)){switch (month) {case 1:printf("year = %d,month = %d,have 31 days\n",year,month);break;case 2:printf("year = %d,month = %d,have %d days\n",year,month,28+(year%400==0 || year%100!=0 && year%4==0));break;case 3:printf("year = %d,month = %d,have 31 days\n",year,month);break;case 4:printf("year = %d,month = %d,have 30 days\n",year,month);break;case 5:printf("year = %d,month = %d,have 31 days\n",year,month);break;case 6:printf("year = %d,month = %d,have 30 days\n",year,month);break;case 7:printf("year = %d,month = %d,have 31 days\n",year,month);break;case 8:printf("year = %d,month = %d,have 31 days\n",year,month);break;case 9:printf("year = %d,month = %d,have 30 days\n",year,month);break;case 10:printf("year = %d,month = %d,have 31 days\n",year,month);break;case 11:printf("year = %d,month = %d,have 30 days\n",year,month);break;case 12:printf("year = %d,month = %d,have 31 days\n",year,month);break;default:printf("invalid month\n");}}return 0;
}

​​​​​​​

如果一个case语句后面没有break语句,那么程序会继续匹配下面的case常量表达式。代码优化。原理是只要匹配到1、3、5、7、8、10、12中的任何一个,就不再拿month与case后的常量表达式的值进行比较,而执行语句printf,完毕后执行break语句跳出switch语句,switch语句最后加入default的目的是,在所有case后的常量表达式的值都未匹配时,打印输出错误标志或着一些提醒。

【例2】日期示例改进。

#include <stdio.h>// switch
int main(){int year,month;while(scanf("%d%d",&year,&month)){switch (month) {case 1:case 3:case 5:case 7:case 8:case 10:case 12:printf("year = %d,month = %d,have 31 days\n",year,month);break;case 4:case 6:case 9:case 11:printf("year = %d,month = %d,have 30 days\n",year,month);break;case 2:printf("year = %d,month = %d,have %d days\n",year,month,28+(year%400==0 || year%100!=0 && year%4==0));break;default:printf("invalid month\n");}}return 0;
}

2 do while循环讲解

do while语句的特点是:先执行循环体,后判断循环条件是否成立。其一般形式为

do{循环体语句;
}while(表达式);

执行过程如下:首先执行一次指定的循环语句,然后判断表达式,当表达式的值为非零(真)时,返回重新执行循环体语句,如此反复,直到表达式的值等于0为止。例3是使用do while语句计算1到100之间所有整数之和的例子,do while语句与while语句的差别是,do while语句第一次执行循环体内语句之前不会判断表达式的值,也就是如果i的初值为101,那么依然会进入循环体。实际情况中do while语句应用较少。

【例3】do while语句计算1到100之间的所有整数之和

#include <stdio.h>// do while
int main(){int i = 0,sum=0;do{sum += i;} while (++i <=100);printf("%d\n",sum);i = 0,sum=0;do{sum = sum + i;i++;} while (i <=100);printf("%d\n",sum);i = 101,sum=0;do{sum = sum + i;i++;} while (i <=100);  // 循环体总是会先执行一次printf("%d\n",sum);return 0;
}

【19.4 题】

1、switch的case后只能放常量表达式。常量表达式的值是整型、字符,因为字符也可以是一个整型值。

2、case后如果没有break,那么不会匹配后面的case的表达式,直接执行表达式后的语句。

3、do while循环,如果while()括号内的表达式为假,第一次仍然会进入循环。

【19.5 二维数组、二级指针】

1 二维数组讲解

二维数组定义的一般形式如下:

类型说明符 数组名[常量表达式][常量表达式];

【19.5 题】

————————————

仅用于本人学习

来源:网络


http://www.mrgr.cn/news/91864.html

相关文章:

  • 【精调】LLaMA-Factory 快速开始4 自定义个一个sharegpt数据集并训练
  • DeepSeek掘金——调用DeepSeek API接口 实现智能数据挖掘与分析
  • 机器学习实战(12):项目实战—端到端的机器学习项目Kaggle糖尿病预测
  • 《Keras 2 :使用 RetinaNet 进行对象检测》:此文为AI自动翻译
  • Helix——Figure 02发布通用人形机器人控制的VLA:一组神经网络权重下的快与慢双系统,让两个机器人协作干活
  • qt5实现表盘的旋转效果,通过提升QLabel类
  • go 并发 gorouting chan channel select Mutex sync.One
  • 【OS安装与使用】part6-ubuntu 22.04+CUDA 12.4运行MARL算法(多智能体强化学习)
  • DDD架构实战:用Java实现一个电商订单系统,快速掌握领域驱动设计
  • 一文详解U盘启动Legacy/UEFI方式以及GPT/MBR关系
  • 【工具篇】【深度解析 DeepAI 工具:开启 AI 应用新体验】
  • RNN中远距离时间步梯度消失问题及解决办法
  • Linux----线程
  • 《Keras 3 :使用 Vision Transformers 进行物体检测》:此文为AI自动翻译
  • 《Keras 3 : 使用迁移学习进行关键点检测》:此文为AI自动翻译
  • IO模型与NIO基础--NIO网络传输选择器--字符编码
  • 代码随想录算法训练营第四十五天| 动态规划08
  • JavaScript变量的作用域介绍
  • nodejs运行的坎坷之路
  • 《论系统需求分析方法》写作心得 - 系统分析师