二维字符数组与二维整型数组在内存中的分配及指针的问题

来源:互联网 发布:淘宝刷销量商品可信么 编辑:程序博客网 时间:2024/05/14 23:21

今天在写二维字符数组初始化的学习日志时,想到一个问题,就是字符串在内存中如何存储。然后想起昨天的那个问题:为什么二维数组名,其实它也是一个指针,他的存储地址跟他的内容是一样的呢?(详细见这里:http://student.csdn.net/space.php?uid=37718&do=blog&id=3505)于是我又对整形的二维数组做了一个小实验。

先分享一下这个测试程序吧:

Code:
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. char *chararray[30] = {"jo","vicent","tom","honey","gigi","lily","susan","peter","bob","ron",  
  5.                             "jason","henry","kiki","ken","auscar","vivian","yiyi","peace","iron","lotus",  
  6.                             "andy","arta","ophone","denial","pipe","wade","james","kobe","kent","angel"};  
  7.   
  8. int intarray[3][2] = {{0,0},{1,1},{23,2}};  
  9.   
  10.   
  11. //Main Function  
  12. void main(){  
  13.       
  14.     printf ("---------------/n");  
  15.     printf ("**intarray=%x/n",**intarray);  
  16.     printf ("*intarray=%x/n",*intarray);  
  17.     printf ("intarray=%x/n",intarray);  
  18.     printf ("&intarray=%x/n",&intarray);  
  19.     printf ("---------------/n");  
  20.       
  21.     char **pt = chararray;  
  22.       
  23.     printf ("&pt=%x/n",&pt);  
  24.     printf ("pt=%x/n",pt);  
  25.     printf ("*pt=%x/n",*pt);  
  26.     printf ("**pt=%c/n",**pt);  
  27.       
  28.     printf ("---------------/n");  
  29.       
  30.     printf ("**chararray=%c/n",**chararray);  
  31.     printf ("*chararray=%x/n",*chararray);  
  32.     printf ("chararray=%x/n",chararray);  
  33.     printf ("&chararray=%x/n",&chararray);  
  34.       
  35.     printf ("------------------/n");  
  36.     printf ("see the intarray pointer addresses:/n");  
  37.     int i;  
  38.     for (i=0;i<=2;i++) printf ("*(pt+%d)=%x/n",i,*(intarray+i));  
  39.   
  40.     printf ("------------------/n");  
  41.     printf ("see the chararray pointer addresses:/n");  
  42.     for (i=0;i<=29;i++) printf ("*(pt+%d)=%x/n",i,*pt++);  
  43.   
  44.       
  45. }     

输出的结果是:

---------------
**intarray=0
*intarray=422aa8
intarray=422aa8
&intarray=422aa8
---------------
&pt=12ff44
pt=422a30
*pt=4200f4
**pt=j
---------------
**chararray=j
*chararray=4200f4
chararray=422a30
&chararray=422a30
------------------
see the intarray pointer addresses
*(pt+0)=422aa8
*(pt+1)=422ab0
*(pt+2)=422ab8
------------------
see the chararray pointer addresse
*(pt+0)=4200f4
*(pt+1)=4200ec
*(pt+2)=4200e8
*(pt+3)=421104
*(pt+4)=4200dc
*(pt+5)=4200d4
*(pt+6)=4200cc
*(pt+7)=4200c4
*(pt+8)=4200bc
*(pt+9)=4200b8
*(pt+10)=4210fc
*(pt+11)=4200ac
*(pt+12)=4200a4
*(pt+13)=42009c
*(pt+14)=4210c4
*(pt+15)=420090
*(pt+16)=420088
*(pt+17)=420080
*(pt+18)=420078
*(pt+19)=420070
*(pt+20)=420064
*(pt+21)=42005c
*(pt+22)=420054
*(pt+23)=42004c
*(pt+24)=420044
*(pt+25)=42003c
*(pt+26)=420034
*(pt+27)=42002c
*(pt+28)=420024
*(pt+29)=42001c

-----------------------------------------------分割线------------------------------------------------------------------

我们就这些 结果来说事儿:

(1)数组名与指针

&pt=12ff44
pt=422a30
*pt=4200f4
**pt=j
---------------
**chararray=j
*chararray=4200f4
chararray=422a30
&chararray=422a30
------------------

这里pt是一个char**,chararray是一个*char[],当然从某种意义上他们是完全相等的,而且在代码中我也是直接将chararray赋值给了ptpt=chararray。只有一点不同,也就是我昨天写的日志提到的问题,为什么&pt跟&chararray不同呢?而且&chararray跟chararray是完全一样的。基于这个问题,我现在的想法是,数组名其实本身就是一个指针,但是这个指针在内存中是不占位置的,它跟pt不同,当定义pt:即char**pt的时候,内存中有4个字节被占用了了,来存放一个指向二维数组的指针,它的地址是12ff44,而内容是,跟chararray一样,是422a30。但是chararray这个指针呢?其(实理论上它也是一个指针)但是你看它的内容是422a30,而地址呢?也是422a30。这就奇怪了。我们知道地址就好比是门派号,现在可以确认的是门牌号为422a30的屋子里面装的是4200f4,那就不可能说还有一间同样门牌号的屋子,装了422a30了。我认为C的编译器对数组名采取特殊的存储实现方式,但是具体怎么实现,我就只能YY了(存在寄存器里?不大可能)。我感觉比较靠谱的一个猜测是,这个指针存放在栈了,但是不能通过求地址运算求得(编译器限制了)

(2)整形二维数组跟字符二维数组的地址对比

**intarray=0
*intarray=422aa8
intarray=422aa8
&intarray=422aa8
---------------
**chararray=j
*chararray=4200f4
chararray=422a30
&chararray=422a30
------------------

上面的对比一目了然了。整型二维数组更强悍了。有三个是一样的?这咋回事呢?首先我们可以肯定的是门牌号为422aa8的屋子里,装的是一个整型变量0。那这两个怎么解释呢?:

intarray=422aa8
&intarray=422aa8

基于对二维字符数组的猜想,我们先不讨论这个求地址运算的&intarray=422aa8。(反正就认为数组名指针的地址,C编译器是不想让我们知道了)那么intarray=*intarray=422aa8怎么理解?我想说,这就是整型二维数组跟字符二维数组的区别了。整型二维数组从头到尾就只有一个指针,指向目标是:422aa8(它的内存地址我们不知道)因为整型一维也好,二维也好,数组都是连续存放的,知道头指针就可以知道后面每个元素的位置。但是字符二维数组就不只一个指针了,它是真正地实现二维的指针,即一个根指针指向一个指针数组,然后数组的每个元素(都是字符指针)分别对应各自的字符串首个字符的地址。

为了证明这个观点,来看看(3)

(3)二维字符数组和二维整型数组的存放地址:

------------------
see the intarray pointer addresses
*(pt+0)=422aa8
*(pt+1)=422ab0
*(pt+2)=422ab8
------------------
see the chararray pointer addresse
*(pt+0)=4200f4
*(pt+1)=4200ec
*(pt+2)=4200e8
*(pt+3)=421104
*(pt+4)=4200dc
*(pt+5)=4200d4
*(pt+6)=4200cc
*(pt+7)=4200c4
*(pt+8)=4200bc
*(pt+9)=4200b8
*(pt+10)=4210fc
*(pt+11)=4200ac
*(pt+12)=4200a4
*(pt+13)=42009c
*(pt+14)=4210c4
*(pt+15)=420090
*(pt+16)=420088
*(pt+17)=420080
*(pt+18)=420078
*(pt+19)=420070
*(pt+20)=420064
*(pt+21)=42005c
*(pt+22)=420054
*(pt+23)=42004c
*(pt+24)=420044
*(pt+25)=42003c
*(pt+26)=420034
*(pt+27)=42002c
*(pt+28)=420024
*(pt+29)=42001c

其中pt的定义是int **或char**。对int**的pt来说,*(pt+i)对应的是各个一维子数组的首地址,而对char**的pt来说,*(pt+i)对应的是各个字符串的首地址。我们明显发现,整型数组的地址排布是线性有序的,而字符串的首地址是无序的。正是由于这个原因,二维字符数组需要一个指针数组来分别记录各个字符串的首地址,而当然,对线性有序的整型数组来说,这些指针自然是不需要的了。

原创粉丝点击