今天写代码的时候遇到一个大坑,顺便把以前的东西捋一捋。
在C/C++、Unix最早设计的语言哲学里,变量就对应内存空间。一个内存空间有两部分信息,手里的内容和脚下的地址,于是有了间接寻址,有了链式数据结构,有了计算机。
而对于一个数组而言,它由两部分构成,数组的数据部分和控制部分,控制部分包括记录数组的首地址,长度,数据步长等。
之前一直把数据当成一个头节点,里面存的是数据地址,这样理解非常方便,比如传参时,参数为数组其实就是指这个头节点,内容是数据地址,相当于参数变量a,传的是a的内容,即右值。问题就在这,因为这个头节点的内存空间并不在用户的使用空间中,它是编译器编译生成,肯定放在不同权限的地方,用户无法操作,以免发生一些混乱的情况。所以不能对其取地址运算&,而如果对一个数组作&,和没写&直接写变量是一样的,都表示首地址,都只能显示头节点本身的内容而无法取真实地址。
于是我想为什么不一开始就设计成用户态的一个头节点呢?可能是为了节省空间,防止碎片产生,因为不是所有数组都要间接操作,节约了开销。如果用户想用就自己定义一个*指针,指向数据自己操作。
二维数组时,实际的数据又多了一层,一个头结点,指向一个N个结点的数组,每个数组里的指针再指向真实数组。同样这个头结点的内容是第一波索引的地址,作参数时加上&和没加一样,只表示索引数组的地址,有时遇到一个参数为char **的调用,想当然的对字符串char [] 做 &,结果报错,根本原因就是&并不真正的&,真正的&权限不允许。所以想真正做成&作参数,只能自己定义一个**再指向,然后把定义的指针传进去。
题外话,二维数组每一级的数组步长都不同,步长是当前指向的内容的步长。比如二维数组里头结点指向地址数组,++的步长就是4字节地址的长度,指针数组里的指针作++,步长就是其指向最终内容的步长,如果是int就是4,等等,所以不论几维数组,都一一层层叠起来的,每级指针都只对当前级的信息有了解,只管理当前级,社会学里层级关系也是这样,所以要明确当前指针是在哪一级上。
原文地址:https://www.cnblogs.com/lector/p/10798472.html