C语言中的指针详解

最近在创建动态二维数组(数组大小为变量)的时候,遇到了一些关于指针的问题,经过一番试验和研究,将一些比较容易出错的地方进行了归纳整理。

数组名和指针

1
2
3
4
int a[4] = {0};
int *b = new int[4];
cout << sizeof(a) << endl; // 4 * sizeof(int)
cout << sizeof(b) << endl; // sizeof(int*)

对于一个数组,数组名从值上来讲就等于它第一个元素的地址,但它和指针其实是有区别的:

  • 你可以修改指针的内容,但无法修改数组名的指向。
  • 对于sizeof,数组名得到的是整个数组的大小,指针则是指针类型占的内存大小。

数组指针和指针数组

1
2
3
4
5
int a[4] = {0};
int (* b)[4] = &a;
int *c[4];
cout << sizeof(b) << endl; // sizeof(int*)
cout << sizeof(c) << endl; // sizeof(int*) * 4

上述b就是一个数组指针,该指针指向一个长度为4的数组,指针移动1则对应移动4个int。c则是指针数组,b和c千万不要搞混,[]的优先级要高于*, 所以c是一个数组,但该数组储存的都是指针。注意,尽管b是数组指针,但是其占的内存依然是指针类型占的内存大小。

提到数组指针后,就要讲到我的出发点二维数组了。

1
2
int **a = new int[2][4]; // 错
int(*a)[4] = new int[2][4]; // 对

我刚开始就错写成了第一种形式,发现这样会出错。我的想法是对于int[0],int[1], int[2]里面储存的是int[4]数组的值,这个值应该就是一位维组名,我等价得以为是指向首个元素的地址,也就是int *类型,那么a就应该是指向指针的指针。

但事实上,正如之前所说,数组名只是在值上等于指向首个元素的地址,但两者并不等价!只是在参数传递,数组名赋值给指针时两者值相等!仔细去想,如果按照我一开始的这种想法,sizeof(*a)就只是一个指针的内存,无法代表一维数组的大小。

因此,int[0]中存储的就只是一维数组名,然后再对该一维数组名取地址,才是正确的指向int[0]的地址,同样的,这个值也是和二维数组名在值上相同,但是并不等价。

1
2
3
int *a = new int[2];
int (*a)[3] = new int[2][3];
int(* a)[3][4] = new int[2][3][4];

以上才是正确的形式,多维可以类推。

总结

  • 数组指针, 不能因为数组名在值上等于指针,而等价为指向指针的指针。
  • 指针数组,在值上等价与指向指针的指针,可以将数组名赋给指向指针的指针。
  • 讲真,涉及到多维数组,既然用了c++,那还是用vector吧,简单方便,并且函数传递时是值传递,也可以用引用传递来实现实参改变,比c方便太多了!

C语言中的指针详解
http://yoursite.com/2017/06/28/编程开发/C++/C语言中的指针详解/
作者
Wei Lyu
发布于
2017年6月28日
许可协议