2011-06-17 149 views
4
#include <stdio.h> 
#include <stdlib.h> 


int main(int argc, char * argv[]) 
{ 
    char *p[2]; 
    char **pp = calloc(2, 4); 

    p[0] = "ab"; 
    p[1] = "cd"; 
// p[2] = "ef"; 

    pp[0] = "ab"; 
    pp[1] = "cd"; 
    pp[2] = "ef"; 

    printf("pp: %s, %s, %s\n", pp[0], pp[1], pp[2]); 
    printf("size_p: %d\nsize_pp: %d\n", sizeof p, sizeof pp); 
} 

如果'p [2]'被定义并赋值 - 结果行为是段错误。如果分配了“pp [2]”,则输出如下:“ab,cd,ef”。 'sizeof'对于'p'返回8(每个指针2×4字节),对'pp'只返回4个字节。为什么我能够分配'pp [2]',尽管它应该只拥有8字节的分配内存(应该只能存储2个指针地址)?另外,'sizeof'在两种情况下如何确定实际的内存大小?指针malloc和操作指针

+0

在哪个平台/ OS上运行此程序?你用什么libc? – levu 2011-06-17 09:40:02

+1

@levu Ubuntu,x86_64 GNU/Linux,glibc'2.7-10ubuntu7' – XXL 2011-06-17 09:41:11

回答

2

With char *p[2];您在堆栈上分配2 char*。当访问p[2]时,你有一个缓冲区溢出,并且可能访问属于当前方法的栈帧的其他任何fings(一些编译器在调试模式下检查这个)。

随着calloc,你在堆中分配内存。访问pp[2](可能)是空闲的内存,在这里你没有段错误。但是这个内存也可以被其他对象使用,所以这绝对不行!

对于大小计算:sizeof(char**)为4,与每32位指针一样。 sizeof(char*[2])是8,因为它是2×4字节。

+0

这似乎是最好的答案,因为它涵盖了内存分配的技术方面。谢谢。 – XXL 2011-06-17 10:01:08

4

p被声明为有两个元素,所以p[2]不存在 - 因此segfault。由于p是一个本地数组(指针),因此sizeof(p)给出元素类型的大小(元素类型为char *,大小为4)乘以元素数(2)。另一方面,pp是指针(指针),而不是数组,因此sizeof(p)只是char **的大小,它与32位机器上任何其他指针的大小相同,即4 。pp[2]的分配似乎成功是纯粹的机会 - 你正在写入分配的内存之外(其中只包含两个char *元素的空间)。

顺便指出,字符串文字的指针应该是const char *

1

正如Aasmund Eldhuset所说,p [2]不存在。 p [0]和p [1]是数组的两个元素。

据我所知,p [2]而不是pp [2]的段错误原因是因为p存储在堆栈中,pp存储在堆中。因此,尽管您没有在pp [2]上拥有内存,但它不会造成故障。相反,它只是覆盖神知道什么,可能会导致你的程序以不可预知的方式行事不端。

一般来说,动态分配的内存(例如pp中的pp)不会总是出现段错误,如果超出了界限,而静态分配的内存(例如.p)将会出现段错误。

+0

我不知道为什么人们不断重复关于p [2]的段落错误的事情:)我从来不问为什么会发生这种情况,因为这很明显。感谢你对king_nak的帖子稍微有些细致的补充。 – XXL 2011-06-17 10:00:33