当先锋百科网

首页 1 2 3 4 5 6 7

室友编写了关于一个二级指针与二维字符串数组的程序,但是老是报段错误,不明就里,让我帮忙调试。我根据他的程序出理的问题,写了另外一个简单一点的程序,来了解问题所在,程序如下:


运行gcc  -W  b.c -o  b,会产生警告信息:


运行: ./b,果断报段错误了。

之所以会报警告错误,原因在于c语言的多维数组实际上是数组的数组,a与b的类型并不匹配,a是一个具有两个元素的数组,数组的元素是具有两个char元素的数组;而b是一个二级指针,它只是一个指向一维数组的指针,数组的元素都为char*。但是b是一个指针,它需要一个地址来赋值,而a刚好能提供一个地址值,因此编译器只是提出了警告而没有报错。

在运行程序报了段错误后,果断地用gdb进行调试,结果出现了令人费解的问题:

gcc  -W  b.c -o  b

gdb  ./b


当我输出*b时,输出了0x64636261;而输出**b时,则报出不能访问;更让我感到神奇的是,输出*(*(b+1))时,居然输出了我输出**b想输出的’a’。这确实让我吃惊不小。

为了了解这段代码的内存分配,我又果断地运行gcc  -S  b.c来查看汇编代码,得如下:


又果断地运行objdump  -d  b查看运行的反编译代码,择大要如下:


根据上面的两个汇编代码,可分析出内存分配图如下:


由上图的内存分布图可知,数组a分配的空间地址为0xbfd288a8,指针b的地址为0xbfd288ac,指针b的值为0xbfd288a8。这也就解释了gdb中出现的各种怪异情况:

当输出*b时,实际上,取的是b的值所代码的地址里面的内容,也就是以地址0xbfd288a8开始的内容,*b是一个char*类型,因此取四个字节,以地址形式输出,也就是0x64636261,其中a、b、c、d的ascii码分别为0x61,0x62,0x63,0x64。将*b的值解释为地址,再对其取值,也就是输出**b的值,这时取的是以地址0x64636261开始的内容, **b的类型是char,因此取一个字节,但是地址0x64636261中的内容不可访问,因此会报段错误。

从内存分配中可知,因为b是一个指针,所以b+1的值为0xbfd288ac,取值*(b+1),输出为一个字符串,然后再对*(b+1)取值,*(*(b+1)),取的是字符串*(b+1)的第一个,也就是“a”;由此也可知*(*(b+1)+1)将输出“b”。这里的*(*(b+1))输出“a”只是一种巧合,当我在其中加入了些其它的数据后,输出的结果就不一样了。