指针和数组小记
Posted lyrich
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了指针和数组小记相关的知识,希望对你有一定的参考价值。
搬运自我的CSDN https://blog.csdn.net/u013213111/article/details/88710076
DSAA in C 看到hash table的建立,对Figure5.8的程序中二级指针、一级指针和数组下标的用法有些疑惑,梳理一下指针和数组的关系。
写段代码看看:
1 int main() 2 { 3 int a0 = 0; 4 int a1 = 1; 5 6 int a[2]; //a is the name of an int array, also a int const pointer 7 a[0] = a0; 8 a[1] = a1; 9 int *pa; //pa is a pointer to int 10 pa = a; //since the name of an array is a const pointer, pointer = pointer, don‘t use "pa = &a" 11 int (*p)[2]; //p is a pointer to an int array 12 p = &a; //pointer to an int array = &(an int array)! 13 int **ppa; //ppa is a pointer to (a pointer to int) 14 ppa = &pa; //ppa = &(a pointer to int) 15 16 int *p1[2]; //p1 is a pointer array, elements in p1 are pointers 17 p1[0] = &a0; 18 p1[1] = &a1; 19 int **p2; //p2 is a pointer to pointer 20 p2 = p1; //use "p2 = p1" rather than "p2 = &p1" 21 22 return 0; 23 }
在GDB中看看几个值:&a
是0xbfffef7c,pa
也是0xbfffef7c,而a
是{0, 1}。
1 (gdb) p &a 2 $1 = (int (*)[2]) 0xbfffef7c 3 (gdb) p pa 4 $2 = (int *) 0xbfffef7c 5 (gdb) p a 6 $3 = {0, 1}
但是在程序中却写的是pa = a;
?若写成pa = &a
则编译告警,运行出错。如何理解呢?
参考数组名和数组名取地址的区别这篇文章以及《C和指针》:
首先引用《C和指针》p141中的理论:在C中, 在几乎所有使用数组的表达式中,数组名的值是个指针常量,也就是数组第一个元素的地址。 它的类型取决于数组元素的类型: 如果它们是int类型,那么数组名的类型就是“指向int的常量指针“。而在《C和指针》p142中说到,在以下两中场合下,数组名并不是用指针常量来表示,就是当数组名作为sizeof操作符和单目操作符&的操作数时。 sizeof返回整个数组的长度,而不是指向数组的指针的长度。 取一个数组名的地址所产生的是一个指向数组的指针,而不是一个指向某个指针常量的指针。所以&a后返回的指针便是指向数组的指针,跟a(一个指向a[0]的指针)在指针的类型上是有区别的。
由于pa是一个int型指针,所以它可以幅值为a(一个指向a[0]的指针,a[0]是int),即pa = a;但是&a是一个指向数组的指针,因此不能pa = &a。
那么&a可以赋值给谁呢?当然是一个指向数组的指针,比如int (*p)[2];,定义了一个指向数组的指针p(也称为数组指针),指向一个int型一维数组,这个数组的长度为2,然后就可以p = &a;了。在GDB中看一下:
1 (gdb) p p 2 $4 = (int (*)[2]) 0xbfffef7c 3 ... 4 (gdb) p &a[0] 5 $10 = (int *) 0xbfffef7c
发现pa
、&a[0]
、&a
和p
的值均为0xbfffef7c,但是要注意它们的含义:&a[0]
和pa
是a[0]的地址,&a
和p
则是整个数组a的地址,虽然地址相同,但含义不同。在K&R的5.3节中也有这样的说法:
因为数组名所代表的就是该数组最开始的一个元素的地址,所以赋值语句 pa = &a[0] 也可以写成下列形式:pa = a;
补充一下,虽然在含义上可以说a
和&a[0]
是相同的,但是&a
不能写成&(&a[0])
:
1 (gdb) p &(&a[0]) 2 Attempt to take address of value not located in memory. 3 (gdb) p &a 4 $11 = (int (*)[2]) 0xbfffef7c
从下标运算的角度来看,K&R的5.3节中说:
对数组元素a[i]的引用也可以写成*(a+i)这种形式。
&a[i]和a+i的含义也是相同的。如果pa是个指针,那么在表达式中也可以在它的后面加下标。pa[i]与*(pa+i)是等价的。
所以可以看到,虽然上面说到&a[0]
和&a
的值相同(但含义不同),而对于指针pa来说,&pa
和&pa[0]
的值不同(含义也不同),&pa[0]
即&(*(pa+0))
即为pa
:
1 (gdb) p &a 2 $12 = (int (*)[2]) 0xbfffef7c 3 (gdb) p &a[0] 4 $13 = (int *) 0xbfffef7c 5 (gdb) p &pa 6 $14 = (int **) 0xbfffef6c 7 (gdb) p &pa[0] 8 $15 = (int *) 0xbfffef7c 9 (gdb) p pa 10 $16 = (int *) 0xbfffef7c
以上是关于指针和数组小记的主要内容,如果未能解决你的问题,请参考以下文章