ToB企服应用市场:ToB评测及商务社交产业平台

标题: C进阶总结一 -- <<C语言深度解剖>> [打印本页]

作者: 玛卡巴卡的卡巴卡玛    时间: 2024-5-18 07:03
标题: C进阶总结一 -- <<C语言深度解剖>>
C进阶总结 --



程序的本质:二进制文件

运行程序,即将程序中的数据加载到内存中运行
为什么要加载到内存? 1.冯诺依曼体系决定 2.快
变量

1.变量:内存上的某个位置开辟的空间

由于变量都是程序运行起来才开辟的
2.变量的初始化:

变量的空间被开辟后,就应当具有对应的数据,即必须要初始化.表示该变量与生俱来的属性就是该初始值
3.为什么要有变量

盘算机是为了解决人盘算能力不足的问题而诞生的.即,盘算机是为了盘算的.
而盘算,就需要数据
而要盘算,任何时刻,不是全部的数据都要立马被盘算,因此有的数据需要暂时被保存起来,等待后续处理. 以是需要变量
4.局部变量与全局变量

5.变量的大小由范例决定

6.任何一个变量,内存赋值都是从低地址开始往高地址

以是首地址和取地址永久都是低地址
1.1 关键字auto

默认情况下,编译器默认全部的局部变量都是auto的,auto一般只能用来修饰局部变量,不能修饰全局变量.ju'bu也叫自动变量.一般情况下都是省略auto关键字的.基本永不使用
1.2 关键字register

建议性关键字,建议编译器将该变量优化到寄存器上,详细情况由编译器决定
(不建议大量使用,由于寄存器数量有限)
什么样的变量可以采用register?

寄存器变量是不能被取地址的,由于不在内存中,就没有内存地址
register不会影响变量的生命周期,只有static会影响变量的生命周期
1.3.1 多文件(extern):

具有一定规模的项目是需要文件与文件之间进行交互的.如果不能直接跨文件调用,则项目在这方面一定需要很大成本解决.因此C默认是支持跨文件的

1.03.2 static

static给项目维护给提供了安全保证,像封装一样,隐藏实现
功能:

历程地址空间


1.4范例

例如: 登记成绩,成绩只要0-100分,那使用一1个字节int8_t/char就足够. 如果带浮点,则需要浮点型.
1.5 关键字sizeof

sizeof是函数还是关键字?
  1. int a = 10;
  2. printf("%d\n",sizeof(a));    //正确用法
  3. printf("%d\n",sizeof(int));  //正确用法
  4. printf("%d\n",sizeof a );    //正确用法,证明sizeof不是函数
  5. printf("%d\n",sizeof int );  //不存在
复制代码
1.6关键字unsigned和signed

数据在盘算机中的存储

原码 与 补码的转化与硬件关系
  1. 例: int b = -20; //20 = 16+4 = 2^4^ (10000)~2~+ 2^2^(100)~2~  
  2. //有符号数且负数 原码转成补码:
  3. 1000 0000 0000 0000 0000 0000 0001 0100  原码
  4. 1111 1111 1111 1111 1111 1111 1111 1011  反码 = 原码取反
  5. 1111 1111 1111 1111 1111 1111 1111 1100  补码 = 反码+1
  6. //补码转原码
  7. 方法一: 原理
  8. 1111 1111 1111 1111 1111 1111 1111 1100  补码
  9. 1111 1111 1111 1111 1111 1111 1111 1011  反码 = 补码-1
  10. 1000 0000 0000 0000 0000 0000 0001 0100  原码 = 反码取反
  11. 方法二: 计算机硬件使用的方式, 可以使用一条硬件电路,完成原码补码互转
  12. 1111 1111 1111 1111 1111 1111 1111 1100  补码
  13. 1000 0000 0000 0000 0000 0000 0000 0011  补码取反
  14. 1000 0000 0000 0000 0000 0000 0000 0100  +1
复制代码
原,反,补的原理:

原反补的概念从时钟引入, 8点+2 = 10点. 而8点-10也等于10点.即2是-10以12为模的补码.
-10要转化成2 ,可以用模-10来得到,但硬件中位数是固定的,模数为1000...,最高位会溢出舍弃.即全0.无法做差.
引入反码转换盘算:即2 == 模-10 == 模-1+1-10 == 1111... -10 +1 == 反码+1; 这个111...-10就是反码,即反码+1==补码的由来
在二进制中,全1减任何数都是直接去掉对应的1.以是反码就是原码符号位不变,其余位全部取反
整型存储的本质

定义unsigned int b = -10; 可否正确运行? 答案是可以的.
定义的过程是开辟空间,而空间只能存储二进制,并不关心数据的内容
数据要存储到空间里,必须先转成二进制补码.而在写入空间时,数据已经转化成补码
变量存取的过程

范例目前的作用

特定数据范例能表示多少个数据,取决于本身全部比特位分列组合的个数
十进制与二进制快速转换
  1. (前置知识:需要熟记2^0到2^10的十进制结果)
  2.     1 -> 2^0
  3.    10 -> 2^1
  4.   100 -> 2^2
  5. 1000 -> 2^3  //1后面跟3个比特位就是2^3
  6. 规律: 1后n个0就是2^n,即n等于几1后面就跟几个0 --- 十进制转二进制
  7.         反过来就是1后面跟几个0,就是2的几次方 --- 二进制转十进制
  8. 因此:2^9 -> 10 0000 0000 // n
  9. 例: 67 = 64+2+1 -> 2^6+2^1+2^0 -> 1000000 + 10 + 1
  10.        = 0000 0000 .... 0100 0011
  11. 同理,二进制转十进制逆过程即可
复制代码
大小端字节序

征象: vs的内存窗口中,地址从上到下依次增大,从左到右也依次增大
(基本上以小端为主,大端比力少(网络))
大小端存储方案,本质是数据和空间按照字节为单位的一种映射关系
(考虑大小端问题是1字节以上的范例.short,int,double...)
判断当前呆板的字节序

"负零"(-128)的明白
  1. (负零的概念并不存在,只是碰巧相像)
  2. -128实际存入到计算机中是以 1 1000 0000 表示的(计组运算器).但空间只有8位,发生截断,因此得到1000 0000.
  3. 而[1111 1111,1000 0001]~[0000 0000,0111 1111]  
  4. 即[-127,-1]~[0,127] 自然数都已经被使用 .  
  5. 计算机不能浪费每一个空间(最小的成本尽可能解决大量的计算),自然1000 0000也需要有相应的意义. 因此赋予数值为-128.
  6. 因为截断后也不可能恢复,所以这是一种半计算半规定的做法.
复制代码

截断

截断是空间不足以存放数据时,将高位截断.
截断的是高位还是低位? 由于赋值永久都是从低地址赋起(从低到高依次赋值),因此空间不足时高位直接丢弃.
1 0000 0001 0100
1 1111 1110 1100
0 0000 0000 1010
1 1111 1111 0110
1 0000 0000 1010
建议在无符号范例的数值后带上u,

默认的数值是有符号的,在数值后加u更加严格,unsigned int a = 10u;
1.7 if-else组合

if的执行顺序

操纵符的执行顺序测试方法

printf("1   ") && printf("2   ");
printf("1   ") || printf("2   ");
C语言的布尔范例

浮点数与"零值"比力

  1. 1. x - y == 0的条件是 |x - y| < 精度.
  2. 即 x - y > -精度 && x - y < 精度
  3. 2.还可以使用fabs函数,C90,<math.h>, double fabs(double x); 返回x的绝对值.
  4. 即 fabs(x-y) < 精度
复制代码
  1. //--------------------------------------------------------------
  2. //方法1,自定义精度
  3. #include<stdio.h>
  4. #include<math.h>
  5. #define EPSILON 0.0000000000000001 //自定义精度
  6. int main()
  7. {
  8.     double x = 1.0;
  9.     double y = 0.1;
  10.     //验证x - 0.9 是否等于 0.1
  11.     if(fabs((x-0.9)- y) < EPSILON ) printf("aaaa\n");
  12.     else printf("bbbb\n");
  13.     puts("hello world!");
  14.     return 0;
  15. }
复制代码
  1. //方法2:使用C语言提供的精度
  2. #include<stdio.h>
  3. #include<math.h>
  4. #include<float.h>
  5. int main()
  6. {
  7.     double x = 1.0;
  8.     double y = 0.1;
  9.     //验证x - 0.9 是否等于 0.1
  10.     //<float.h> 内置最小精度值 DBL_EPSILON 和 FLT_EPSILON ,1.0+DBL_EPSILON != 1.0 ,EPSILON是改变1.0的最小的值,数学概念,略
  11.     if(fabs((x-0.9)- y) < DBL_EPSILON ) printf("aaaa\n");
  12.     else printf("bbbb\n");
  13.    
  14.     return 0;
  15. }
复制代码

  1. int main()
  2. {
  3.     double x = 0.0;
  4.     // double x  = 0.00000000000000000000000000001; //很小也可以认为等于0
  5.     if(fabs(x) < DBL_EPSILON ) printf("等于0\n");
  6.     else printf("不等于0\n");
  7.    
  8.     return 0;
  9. }
复制代码
补充:怎样明白逼迫范例转化

逼迫范例转化:不改变数据本身,只改变数据的范例
  1. 字符串"123456"如何转化成整型值123456,能强转吗? 答案是不能,只能通过算法进行转化
  2. 因为"123456"的空间至少占了7个,而整型int只占4个字节.
复制代码
  1. printf("%d\n",0);
  2. printf("%d\n",'\0');
  3. printf("%d\n",NULL); //(void*)0
复制代码

1.8switch case组合

  1. //switch只能对整数进行判定
  2. switch(整型变量/常量/整型表达式){
  3.     case var1:
  4.         break;
  5.     case var2:
  6.         break;
  7.     case var3:
  8.         break;
  9.     default:
  10.         break;
  11. }
  12. 推荐使用switch的场景:只能用于整数判定且分支很多的情况下
复制代码
(补充) 屏蔽警告的方法
  1. error C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
  2. 方法1:
  3. #pragma warning(disable:4996)
  4. 方法2:
  5. #define _CRT_SECURE_NO_WARNINGS //该宏定义必须写在文件的首行(头文件的前面)才有效
  6. (如果宏没有宏值,则只能用在#ifdef等条件编译语句中,即只用于标识)
复制代码
  1. int main()
  2. {
  3.     int n = 0 ;
  4.     scanf("%d",&n);
  5.     switch (n)
  6.     {
  7.         case 1: case 2: case 3: case 4: case 5:
  8.             puts("周内");
  9.             break;
  10.         case 6:
  11.             puts("周六");
  12.             break;
  13.         case 7:
  14.             puts("周日");
  15.             break;
  16.         default:
  17.             break;
  18.     }
  19.     return 0;
  20. }
复制代码
1.9 do、while、for

循环的基本结构

(死循环除外)
  1. int main()
  2. {
  3.     int count = 10; //1.循环条件初始化
  4.     while (count > 10) //2.循环条件判定
  5.     {
  6.         printf("%d\n", count); //3.业务逻辑
  7.         count--; //4.循环条件更新
  8.     }
  9.     return 0;
  10. }
复制代码
[code]使用样例:for(int i = 0; i




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4