#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”。对于'p','sizeof'返回8(每个指针2x4个字节),'pp'只返回4个字节。为什么我能够分配'pp [2]',即使它只应拥有8个字节的已分配内存(应该只能存储2个指针地址)?另外,'sizeof'如何确定两种情况下的实际内存大小?
答案 0 :(得分:4)
p
有两个元素,因此p[2]
不存在 - 因此是段错误。由于p
是一个本地数组(指针),sizeof(p)
给出了元素类型的大小(元素类型为char *
,其大小为4)乘以元素数(2)。另一方面,pp
是指针(指针),而不是数组,因此sizeof(p)
只是char **
的大小,与大小相同对32位机器上的任何其他指针,即4.对pp[2]
的赋值似乎成功是纯粹的机会 - 你在分配的内存之外写入(只包含两个char *
元素的空间)。
顺便说一句,指向字符串文字的指针应为const char *
。
答案 1 :(得分:2)
使用char *p[2];
,您可以在堆栈上分配2 char*
。访问p[2]
时,您有缓冲区溢出并可能访问属于当前方法的堆栈帧的任何其他fings(某些编译器在调试模式下检查它)。
使用calloc
,您可以在堆中分配内存。访问pp[2]
是(可能)可用内存,这里没有段错误。但是这个内存也可以被其他对象使用,所以这绝对不行!
对于大小计算:sizeof(char**)
为4,与每个32位指针一样。 sizeof(char*[2])
是8,因为它是2x4字节。
答案 2 :(得分:1)
正如Aasmund Eldhuset所说,p [2]不存在。 p [0]和p [1]是数组的两个元素。
p [2]而不是pp [2]的段错误的原因是,据我所知,因为p存储在堆栈中而pp存储在堆上。因此,虽然你没有在pp [2]中拥有记忆,但它并没有出错。相反,它只是覆盖了上帝知道什么,并可能导致你的程序以不可预测的方式行为不端。
一般情况下,如果超出边界,动态分配的内存(例如示例中的pp)将不会始终发生段错误,而静态分配的内存(例如.p)将会出现段错误。