5.12
-
代码中直接出现的"5.0f / 9.0f"、"32"这样的字面量,也就是魔数,是不规范的。一般使用宏定义符号。
-
关于宏函数,也是属于代码的一部分,定义宏函数的同时,也不能有具体数据出现。
-
宏函数:本质还是文本替换 ,和头文件原理类似。
-
预处理阶段就完成替换,这完全不会消耗运行时性能。节省运行时间。
-
原理与函数不同。
-
命名:全大写英文字母 加下划线。
-
函数宏,替换简短代码,一般不替代复杂的代码。
-
5.13
-
太久没有c ,基础语法,scanf多变量输入时%d%d之间是没有逗号的。
-
关于printf字符和数据拼接。以及%的输出,需要用%%来表示%
-
switch中 case后面一般都是具体的值 或者一个常量,所以比大小,要通过简化,比如分数除以10
-
欧几里得算法(也称为辗转相除法)是一种用于计算两个整数的最大公约数的方法。它的基本思想是利用辗转相除的原理,即不断地用较小数去除较大数,直到余数为0为止。此时较大数即为最大公约数。
-
while和for循环中continue的区别在于,跳过的语句是不同的,for循环来说不会跳过最后的i++;
-
5.14
-
关于分数计算:利用最大公约数没错,但是,使用过程中,要更简单是:算出未简化的分数,再去利用最大公约数来进行约分。
-
每一个进程都会得到一个虚拟空间内存,通过硬件和操作系统之间的一个虚拟层,虚拟内存空间,其与真实物理内存存在一种映射。
-
最常操作使用的是堆空间。
-
堆和栈的空间是可以相互伸缩,堆会低到高,栈会高到低。
-
用户区域:用户可以访问乃至可以修改的,所有的非内核区域都是用户区域。和内核区域:用户不能之间访问更不可能修改的内存区域。——虚拟内存空间模型分区。
-
内存地址相关概念(重点)
-
内存地址:内存空间中某个位置的唯一性标识,不是物理内存地址而实虚拟内存空间的地址
-
变量的地址:变量所占内存空间的首字节的地址值。
-
地址==地址值
-
地址值是一个什么样的数值:一定是非负数,最小值是0,最大值需要看平台的位数。目前基本上是32位和64位。
-
2^32 最多是4G,有2^32个地址。 64位 :2^64 /1024/1024/1024 (kb,Mb,GB,) 224TB16EB。也就是前者需要八位 后者需要十六位的十六进制。32兼容性好,63内存空间充足。
-
低地址、高地址:地址值大的区域为高地址,靠近0的区域就是低地址
-
小端存储法:反直觉,数据从低有效位开始存在低地址上。大端存储
- 基本上都是使用小端存储法,现代cpu中
-
大端存储法:低地址位存放高位二进制数
- 只有网络传输的数据
- 只有网络传输的数据
-
-
小段存储法:
- 一个字节 十六进制 两位为一个数的存放在每一个地址中:0000 0000 0000 1010 ——>00 00 00 a0
-
关于地址指针的存储:由于存放的是地址,也就是指针的存放空间大小,是依据系统的32位还是64位。32位就是 八字节 ,64位就是16字节!!!!!!,
-
.i文件 依旧是能读懂的 是预处理之后的文件,一般是处理完头文件和宏定义之后的文件。也就是.c和.h合成一个.i文件
-
声明是可以多次声明,但是定义一定是只能定义一次的。(变量,函数通用)
-
宏定义是任何位置都可以写,无论是宏函数还是宏常量的本质都是文本替换。
-
编译(狭义):
-
语法检查,由.i 变为.s
-
优化以后,由.i变为.s (汇编代码:二进制机器指令助记符)
-
汇编过程:就是将.s文件转为.o 汇编指令转化位二进制文件。不是可执行程序,还需要依赖一些外部的代码,并不知道具体使用的函数的定义,需要链接
-
-
代码中的注释在预处理阶段就会被预处理器忽略丢掉。
5.15
-
关于自增num++,只有在下一行的语句中才是具体的++的值
-
-
关于& 位运算符是在常规运算优先级的后面,以及左移右移后面 且在关系运算符后面但是优于逻辑与以及赋值运算符
-
自增是最优先的,单目运算优先于双目,单目中从左向右优于右向左(按位非,逻辑非、取地址,sizeof
-
反码,补码,原码:概念 为了实现有符号的数据的计算
-
计算机中都是将有符号数据以补码的形式存入,也是以补码的形式计算。
-
反码:最高位是符号位,0是整数,1是负数,后面几位取反,
-
补码:在反码的基础上加上1,
-
正数源码反码补码一致。负数按以上规则改变。
-
补码的出现,也有助于减法的计算,使得其和加法的计算方法是一样的,都是对补码进行计算。
-
n&=(n-1) 可以消除一个最低为的1 为什么我也不知道。。。。 记住吧 通过消除1可以知道每一个数有多少个
-
看两个数符号是否相同直接两数异或是否为负数 是负数那么就是不相同。
-
反过来,对于一个已知他的二进制,求源码,是需要减1,再取反。吧
-
在求绝对值的时候,利用位运算,可以先向右移,找到最高位,通过当前变量类型,sizeof *8 -1 减去一是保留最高位,来确定需要位移的位数,用一个变量接收,然后,让原数与该变量异或再减去该变量,就得到绝对值了。为什么:想象不到,但是能理解一点。。。。
- 简化:求一个数的绝对值:sign=num>>(sizeof(typedef)*8-1) num = (num^sign)-sign;<num是最后结果>
-
这也是C语言语法比较奇特的地方,
{}
复合语句具有自身新的、独立的作用域,又和外层共享作用域。 -
5.16
-
局部变量,未定义时,数组内存放的值是随机值,存放在栈中。栈的内存比较小,如果局部数组太大,就会栈溢出。因此在使用比较大的数组时,会设置为全局。或者直接放在堆上。
-
数组越界错误:保证访问的数组是被定义,而非未定义的值。
-
访问冲突,一般都是数据越界修改,因为没有该区域的修改权限。
-
二维数组,行主序。二维数组可以理解为,一维数组中每个元素的类型是一维数组,那么在定义的时候,一维数组的元素类型以及该一维数组中的个数是需要确定的,也就是说,有多少列是需要确定的。因此在定义的时候需要行数可以没有,但是列数必须要有。
-
const常量不能作为数组声明时的常量,因为在编译时不能确定其值。只读变量。只是编译器的一种语法限制,只能影响编译时期,不能影响运行时期可以用指针来修改,也就是该地址下在运行时他的值是可以修改的,只是不能通过变量名来修改。connst int num=10; num=90;//会报错。 但是 int p = # *p = 100;是可以改的。
-
pow、sqrt 传入的参数都是double 类型 返回的参数也是,必须用头文件 math.h