今天写程序的时候没注意,犯了一个想当然的错误:二维数组跟指针的指针是一样的!(注意,这个观点是错误的哦!二维数组跟指针的指针完全没有关系!!!)
看起来,二维数组和指针的指针的确有非常大的相似之处:
char string[2][8];
上面的是二维数组,有些教科书上说,二维数组可以看成是一个n行m列的矩阵,同时,每一行都相当于是一个指针,即:
string[0]和string[1]相当于是char *类型的指针。
的确,在对数组进行操作的时候,string[0]和string[1]就好像是一个指针数组的两个成员一样。
再来看指针的指针:
char *string[2];
char **string;
上面两种形式基本上是一致的。一般情况下,指针的指针又可以看做是指针数组,也就是说,上面的两种形式下,不管哪种,都可以使用:string[0]和string[1]来表示两个指向字符串的指针。
乍一看起来,这不是跟二维数组一样一样的么?
OK,问题来了,假设有下面的函数:
1: void test_func(char *strings[])
2: {3: //......
4: }在这个函数中,strings参数是一个指针的指针,也可以看做是指针数组,那么,下面的调用方式是否是正确的呢?
1: char strings[2][8];
2: //......
3: test_func(strings); 4: //......看起来,strings这个局部变量是一个二维数组,二维数组又可以看成是一个字符串数组,不仔细想的话,貌似是跟“指针数组”是一样的,但是如果一旦将一个二维数组传递给一个本来需要“指针数组”的函数,那就错了!
来简单看一下二维数组和指针数组(指针的指针,这里不区分二者)在内存中的布局:

当strings为一个二维数组的时候,其实内存中保存的数据是实际的字符串内容;而当strings为一个指针数组的时候,内存中保存的是一些地址。也许有人说了,这不是废话吗,是个人都知道。的确,大家都知道这一点。所以,这就是为什么二维数组和指针数组不一样了:
虽然我们说二维数组相当于一个“字符串数组”,但是,注意,“字符串数组”说到底在内存中保存的仍然是字符串,而不是地址!
而“指针数组”,它在内存中需要保存的是地址!!!
所以,当一个二维数组被当成指针的指针传参给函数的时候,test_func函数内部本来期望通过strings拿到地址,结果遗憾的是,它拿到了strings字符串的内容!
其实是一个比较简单的问题,但是相信很多人都会不小心上它的当。
这告诫我们,在学习指针和数组的时候,虽然我们可以做这样和那样的类比,可以把指针当成数组也可以把数组当成指针,但是,一定要小心,注意看它们的本质是什么!
总结一句话:不管是多少维的数组,它只能被当做同类型的指针来用!即:
1: TYPE value[]...[]; // TYPE是任意类型,[]...[]表示任意维数
2: TYPE *pval;上面的第一种形式只能相当于第二种形式来使用,绝对不可以当做 TYPE *...*pval(*...*表示任意个星号)来使用!!!