c语言取地址符与数组之间联系
大家都知道在c语言中,“&”放在在变量前有取得该变量内存地址的意思,那如果将“&”符号放在数组之前又会有怎样的变化呢?
数组名与指针的关系
在c语言中,数组名为该数组首元素的地址,如:
int a[3]={1,2,3},a的值为0x7ffee86cbaec,该值与a[0]的地址相同。
int a[3]={1,2,3};
printf("the array adress is %p.\n",a); //the array adress is 0x7ffee86cbaec
printf("the a[0] is %p.\n",&a[0]); //the a[0] is 0x7ffee022daec
在对a[0]时用到了取址符“&”,因为a[0]是特定的值。
而在二维数组中,数组名虽然还是数组首元素的指针,但是在指针偏移单位及解引用上有着不同。
假设b数组为有4个子数组,每个数组又内含了3个数值,
int b[4][3]={{1,2,3},{4,5,6},{7,8,9},{11,12,13}};
此时数组名b的值为0x7ffee8b32ab0,虽然仍与b[0][0]的地址相同,但是在编译器看来,这两个仍然存在不同。
数组名b实际上是子数组{1,2,3}的地址,b+1相当于指针增加3(size of int)个 单位*,也就是下个子数组{7,8,9}的内存地址。
如果将二维数组名作为实参,代入到形参中,需要将形参设置为 int (* pt) [3],也就是说pt是指向含有三个元素数组的指针,该指针指向的内存大小为 3*(size of int)。
在对数组名解引用时,*b意味着对数组首元素b[0]取值,但是b[0]是子数组,所以b[0]值就是含3个元素数组的内存地址,所以需要再解引用一次,才能取到b[0]中第一个元素的值1。
printf("%p.\n",*b); // 0x7ffeeb3acab0
printf("%d.\n",**b); // 1
如果想取到第三个子数组中第二个值,需要先将数组名(地址)向右偏移两个单位,解引用第一次,取得第三个子数组中的首元素地址。然后在该子数组中再向右偏移一个单位,取得第二个值的内存地址,最后再解引用该地址,得到值8.
printf("%d.\n",*(*(b+2)+1)); // 8
printf("%d.\n",b[2][1]); // 8
虽然两个方法取得的值都一样,第二种更简便,但是用指针来思考多维数组,能够更加深理解。
数组与取值符
在说明数组名和指针的关系后,现在来说一下如果在数组名前使用取址符会怎么样。
还是用b数组。
int b[4][3]={{1,2,3},{4,5,6},{7,8,9},{11,12,13}};
对于指针变量来说。如 int * pt,pt=b[0],我们可以说pt是指向int类型数组b[0]中首元素1的内存地址。pt自身的内存地址与b并不一致,指针长度为4字节,在64位操作系统下那么就都是8字节,长度与系统的寻址能力有关。pt储存的值即为b[0]的内存地址。
int * pt;
pt=b[0];
printf("%p.\n",pt); //数组地址 0x7ffee9202ab0
printf("%p.\n",&pt); // 指针自身的地址 0x7ffee33a3aa0
现在在数组前加一个取值符
printf("%p.\n",&b); //0x7ffeee45aab0
printf("%p.\n",&b[0]); // 0x7ffeee45aab0
printf("%p.\n",b); // 0x7ffeee45aab0
可以看到三个内存地址都是一致的,也就是说数组、数组名与&数组名 都是同一个值。c语言中,数组名是常量,编译器没有为数组名分配空间,但编译器对数组名做了特殊处理,所以数组名是不能作为左值,不能自增自减。在c编译器中,将 &+数组 视为取数组区域的地址,这里做一个实验验证一下
i nt * pt;
int (* pr) [3];
pt=&b[0];
pr=&b[0];
编译时报了错,错误原因为 “不匹配指针类型”,问题就在于&b[0]虽然是数组首元素的地址,但要把整个数组内存区域看作一个单位,这个区域包含三个元素,所以pr=&b[0]这个是对的。pr是指向三个int类型元素内存地址的指针。
再用指针偏移实验一下:
printf("%d.\n",**(&b[0]+1)); // 4
可以看到这个值与用 **(b+1)相同,所以印证了&+数组,是将该数组内存区域看作一个单位。&b[0]+1,向右偏移一个单位到了下个数组b[1],解引用1次取得数组中首元素的地址(一个int类型),然后再解引用取得该值。
概括的来说&(b[i])其实与b+i相同,都是子数组首元素地址,但是占用了一个数组单位的区域。
以上内容大多为为本人手打,部分引用了https://blog.csdn.net/lerenceray/article/details/8983290内容,因为是本人第一次发博客,可能也会有错误,请大家指出