C0EEBDA1

在梦中,我是有超能力的。。。

« Notepad++的FunctionList插件的中文版(Unicode版)【MFC应用】使用CRegKey类操作注册表,完成文件关联 »

【随笔】一个很容易迷惑人的问题:“二维数组”和“指针的指针”

今天写程序的时候没注意,犯了一个想当然的错误:二维数组跟指针的指针是一样的!(注意,这个观点是错误的哦!二维数组跟指针的指针完全没有关系!!!)

看起来,二维数组和指针的指针的确有非常大的相似之处:

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这个局部变量是一个二维数组,二维数组又可以看成是一个字符串数组,不仔细想的话,貌似是跟“指针数组”是一样的,但是如果一旦将一个二维数组传递给一个本来需要“指针数组”的函数,那就错了!

来简单看一下二维数组和指针数组(指针的指针,这里不区分二者)在内存中的布局:

image

当strings为一个二维数组的时候,其实内存中保存的数据是实际的字符串内容;而当strings为一个指针数组的时候,内存中保存的是一些地址。也许有人说了,这不是废话吗,是个人都知道。的确,大家都知道这一点。所以,这就是为什么二维数组和指针数组不一样了:

虽然我们说二维数组相当于一个“字符串数组”,但是,注意,“字符串数组”说到底在内存中保存的仍然是字符串,而不是地址!

而“指针数组”,它在内存中需要保存的是地址!!!

 

所以,当一个二维数组被当成指针的指针传参给函数的时候,test_func函数内部本来期望通过strings拿到地址,结果遗憾的是,它拿到了strings字符串的内容!

 

 

其实是一个比较简单的问题,但是相信很多人都会不小心上它的当。

 

这告诫我们,在学习指针和数组的时候,虽然我们可以做这样和那样的类比,可以把指针当成数组也可以把数组当成指针,但是,一定要小心,注意看它们的本质是什么!

 

 

总结一句话:不管是多少维的数组,它只能被当做同类型的指针来用!即:

   1: TYPE value[]...[];       // TYPE是任意类型,[]...[]表示任意维数
   2: TYPE *pval;

上面的第一种形式只能相当于第二种形式来使用,绝对不可以当做  TYPE *...*pval(*...*表示任意个星号)来使用!!!

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

日历

最新评论及回复

最近发表

Powered By Z-Blog 1.8 Spirit Build 80722 Code detection by Codefense  theme by BokeZhuti

Copyright 2008-2009 C0EEBDA1. Some Rights Reserved. 备案号:京ICP备09020681号