x210-2021-09-02
1、char buf[10] = "abc",编译器执行这句以后,会出现两段内存,一段内存存放buf数组(内容为拷贝的"abc"),另一段内存存放字符串"abc"常量本身,而char *p = "abc",这句执行完以后,得到的是一个指针变量和字符串"abc"常量本身,并且指针变量指向的是"abc"的首地址,也就是说后者并没有大块内存产生,所以当后续执行*(p+1) = 'd',这种语句时,相当于告诉编译器要修改常量字符串"abc"的内容,这时就会导致报段错误,也就是编译器的阻拦。
2、strcpy()因为没有指定拷贝的个数容易导致无法预料的错误,而strncpy()虽说情况可能会好一些,但是如果碰到被拷贝范围内的源数据中存在'\0',那么也会出现错误,所以更好的解决办法是使用memcpy()。
3、一个一维数组int a[10],可以用一级指针来指向,也就是int *p = a,那二维数组b[10][20],是不是按理来推测也能够通过二级指针来指向呢?也就是写成int **p = b,但是经过编译器一编译就会发现是通过不了的,因为二维数组是一行里包括了20个int元素,明显地,二维指针一次指向也只能读回一个int,而不是20个int,那写成int *p[20]行吗?还是不行,因为[]已经和()是同一级的,而*也才排到了二级,所以int *p[20]说明p首先和[20]结合成为了一个数组,然后里面的每一个元素都是指向int的指针,所以最终结果还是只能一次读回一个int,而不是全部20个int,那既然这样,把p用小括号修饰起来,写成int (*p)[20],这时p首先和*结合,成为一个指针,然后int和后面的[20]都成为了(*p)的修饰,这时可以理解成int x[20],这就和普通的int a[20]形式一样了,所以它这时就能够通过一次指向读回20个int了,如果再拓展一下,如果有一个三维数组int c[2][10][20],如果也使用上面的方式来表达,就应该写成int (*p)[10][20],可以理解成,相当于有两个10行20列的二维数组,只是这两个二维数组分布在两片内存空间中,指向一次要能够把一整个二维数组给读回来。
4、内存分布:
0xffff_ffff(4G) -----------------------------------------------------------
内核空间
3G--------------------------------------------------------------------------
栈:局部变量
------------------------------------------------------------------------------
堆:malloc
------------------------------------------------------------------------------
全局数据段(RW):global_var、static_var >>.data&.bss
只读数据段(R):string >>.text
代码段(R):code >>.text
0x0800_0000-----------------------------------------------------------
系统保留空间
0x0000_0000------------------------------------------------------------
5、一般链接成.o的过程只是对全局数据段、只读数据段、代码段这三者的内容进行分别打包链接,因为堆栈都属于运行时分配的,另外,因为只读数据段和代码段都属于.text,而全局数据段又细分为.data(初始化变量存放于此)和.bss(未初始化变量存放于此),所以每个.c源文件生成.o时都包含这三个段,链接的工作就是负责将其中属于.text的段都链接成一个.text的.o(其余两个段也依次类推)。
6、首先在命令行中使用size查看源文件经过编译之后得到的最终可执行文件,如下图一,此时.text段只有1126个字节,这时再在printf语句引入"the ",即三个字母加空格共4个char字符,看三个段中哪个段的容量发生了变化,结果发现.text段变为了1130个字节,如下图二,这就是只读数据段为什么会是.text段的原因,但是需要注意,如果存在两个或以上完全一样的字符串时,系统会自己优化掉,结果就是只存一份,所以再次编译查看.text段时会发现,即使多加了一条一样的打印输出,容量还是没有发生变化,如下图三。
7、局部变量在函数退出的时候被释放,其实际含义就是出栈。
8、一个函数中的局部变量一旦使用static进行修饰,它将在编译之后被编译器分配在全局数据段,而不再是原来的栈区,从图一和图二对比可以看到,如果只在函数中增加一个局部变量int a = 10时,三个段的容量都还没有发生什么变化,这时,再对变量a使用static进行修饰,发现在全局数据段中的初始化段.data增加了4个字节(因为变量a是int类型),如图三,如果这时又有一个子函数func2,在它的内部也有一个static修饰的变量a,那么这时就会出现有两个变量a都存在于全局数据段的情况,那这时的系统会不会分不清、访问错呢?实际并不会,如果使用nm命令对编译出来的可执行文件进行查看,可以看到两个变量a后面都跟有一个数字1826和1830(实际上相当于索引),因此系统在访问时并不会访问错,从这里也可以看出,虽然存放的位置带有全局属性(因为被放到了全局数据段),但实际访问时也只是各访问各的(这也就说明本质上还是属于局部属性的)。