c语言编程基础细节(1)——内存地址、编译运行过程、位运算(反码补码)

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 = &num; *p = 100;是可以改的。

  • pow、sqrt 传入的参数都是double 类型 返回的参数也是,必须用头文件 math.h

  • 13
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值