指针和数组小记

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]&ap的值均为0xbfffef7c,但是要注意它们的含义:&a[0]pa是a[0]的地址,&ap则是整个数组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

 

以上是关于指针和数组小记的主要内容,如果未能解决你的问题,请参考以下文章

C和C指针小记(十七)-使用结构和指针

C和C指针小记

Java学习小记 3

PHP-数组小记

C++虚函数表小记

Java学习小记 4