C语言中有个数组,一维数组还好不会有什么问题,二维就有很大问题了,其中,多级指针与“多维”数组更是让很多人云里雾里 。写下此篇,一步一步剖析多维数组。
首先,一维数组都知道:
char a[3];
a:是数组名,会转化为数组的起始地址;
a + n: 表示数组的起始地址偏移 对象的n个长度;
*(a + n): 获取数组的第n个对象的内容;
a[n]: 等价于*(a+n);
&a:获取数组指针的地址,此处为char[3]的指针类型;
&a[0]:获取数组第一个对象的地址,此处为char* 类型;
&a + 1: 偏移一个char[3]的长度的指针;
&a[0] + 1: 偏移一个char*的长度;
那么理解a+1,&a+1,&a[0]+1,sizeof(a),sizeof(&a)应该就不难了吧。
如果理解了上面,尤其是理解数组的成员对象这个概念那么就不难理解多维数组了。
下面来看二维数组:
char a[3][2];
看图片应该理解了吧,这里的对象不再是一个char, 而是一个char [2]的数组
那么如何进入对象里面呢,答案是*;
*(a+n):获取第n个对象, 此时*(a+n)表示第n个对象的首地址,可以把它看成是一个数组名;
*(a + n) + m: 表示数组第n个对象中的第m个对象;
*(*(a + n) + m): 获取数组的第n个对象第m个对象的内容;
&(*(a+n)):获取第n个对象的地址,是char[2]长度的指针,等价于(a+n);
有时会有(a[3] + m)这样的形式让我们无所适从,但我们知道a[3] = (a + 3)那么*( *(a+ 3) + m)就知道*(a+ 3)是首先进入第三个对象;
第三个对象时个一维数组,+m表示偏移n位,解引用表示获取第n个对象;
下面三维的就不难理解了,每解一次引用就递归进入一个对象。
关于数组指针赋值的问题:
1.我们经常要把一个数组指针赋给一个新的指针,指针必须要是匹配的,先看一个简单的例子:
char a[3];
char * p = &a[0];
这种相信是没问题的,下面这种酒比较难理解了
char * p = a;
这里是因为数组名会转换为第一个对象的起始地址;
那么下面的就是错误的了
char * p = &a;
因为&a是一个char[]的指针,指针不匹配,不能赋给char*;
所以终究会让我们迷茫的就是数组名会转换为第一个对象的起始地址。
话不多说,直接上代码,系统ubuntu14, 64位,g++编辑器:
#include<iostream>
using std::cout;
using std::endl;
int main()
{
int a[4][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
cout << a << " " << a + 1 << " " << a + 2 << " " << a + 3 << endl;
cout << *a << " " << *(a + 1) << " " << *(a + 2) << " " << *(a + 3 )<< endl;
cout << *a << " " << *(a + 1 ) + 1<< " " << *(a + 2)+1 << " " << *(a + 3) + 1 << endl;
cout << **a << " " << *(*(a + 1) + 1) << " " << *(*(a + 2) + 1) << " " <<*( *(a + 3) + 1) << endl;
cout << sizeof (a) << " " << sizeof (a[0]) << " " << sizeof (&a) << endl;
return 0;
}
结果如下:
0x7ffc80693570 0x7ffc8069357c 0x7ffc80693588 0x7ffc80693594
0x7ffc80693570 0x7ffc8069357c 0x7ffc80693588 0x7ffc80693594
0x7ffc80693570 0x7ffc80693580 0x7ffc8069358c 0x7ffc80693598
1 5 8 11
48 12 8
注意一个点:
第一行偏移12个字节,3个int;
第二行与第一行是一样的, 但是指针的范围不一样了;
第三行比第二行偏移4个字节, 1个int,照应上一行,范围缩小了;
参考:
1.图解c/c++多级指针与“多维”数组 - 陈洋Cy - 博客园 http://www.cnblogs.com/chenyangyao/p/5222696.html
2.《C和指针 》