堆栈转储访问malloc字符数组

5

gcc 4.4.3 c89

我有以下源代码,并在printf上获得堆栈转储。

char **devices;
devices = malloc(10 * sizeof(char*));

strcpy(devices[0], "smxxxx1");

printf("[ %s ]\n", devices[0]); /* Stack dump trying to print */

我认为这应该创建一个类似于以下的字符数组。
devices[0]
devices[1]
devices[2]
devices[4]
etc

我可以在每个元素中存储我的字符串。

非常感谢任何建议,

== 添加更正 ===

for(i = 0; i < 10; i++)
{
    devices[i] = malloc(strlen("smxxxx1")+1);
}

1
赞一个引发了几乎相同答案的问题。 - sum1stolemyname
堆栈转储还是核心转储? - Matt Curtis
@Matt Curtis:我记得gcc为win32生成的程序在出现某些类型的错误时会在运行它们的dos框中生成堆栈转储。然而,在我的当前设置中(mingw,vista,x86-32),它似乎没有这样做。 - nategoose
6个回答

5

您已经为指针数组分配了内存。您需要为每个元素分配内存以存储字符串。

例如:

#define NUM_ELEMENTS 10
char **devices;
devices = malloc(NUM_ELEMENTS  * sizeof(char*));

for ( int i = 0; i < NUM_ELEMENTS; i++)
{
    devices[i] = malloc( length_of string + 1 );
}

你引入了NUM_ELEMENTS,但在malloc()调用中仍然使用了10。 - sharptooth

4

devices[0]是一个char *,但你还没有为它分配任何存储空间。请改为:

char **devices;
devices = malloc(10 * sizeof(char*));

devices[0] = strdup("smxxxx1");

printf("[ %s ]\n", devices[0]);

最终,你需要释放strdup()分配的内存:

free(devices[0]);

3

您已为存储10个char指针的内存分配了空间。要在这些内存位置存储字符串,您必须为每个指针分配内存。基本上,您需要像device [0] = malloc(stringLen + 1);这样的东西来为每个指针分配内存。


2
你只分配了一个指针数组,用于存储字符数组。你需要为每个要存储的字符串分配内存:
char **devices;
devices = malloc(10 * sizeof(char*));

//Added this line:

devices[0] = (char*)malloc(strlen("smxxxx1")+1);
strcpy(devices[0], "smxxxx1\0");

printf("[ %s ]\n", devices[0]); /* Stack dump trying to print */

2
你的字符串不需要显式地包含\0,它们已经是以空字符结尾的。 - Hasturkun
只是想作为额外的预防措施问一下。实际的字符数组应该以NULL结尾吗?我有10个元素。然而,第10个应该是NULL。这是为了防止在循环显示时停止在NULL处?只是一个想法。谢谢。 - ant2009
1
@robUK:在数组末尾使用NULL作为哨兵值有时是常见的做法(例如argv)。这取决于情况;有时可能没有适当的值可以用作哨兵(如果NULL是数组中合法的元素怎么办?如果您不处理指针数组呢?)。 - jamesdlin

1

你已经为指针(设备)分配了空间,但是你还没有为要存储的字符串分配空间。


0

devices是一个指针数组。你正在将字符串"smxxxx1" 复制到 数组中,但看起来你想要将元素0设置为指向该字符串。

尝试使用以下方法而不是strcpy():

devices[0] = "smxxxx1"

或者

devices[0] = strdup("smxxxx1")

编辑:

在32位系统上,devices [0]由四个字节组成。这四个字节被字符串“smxxxx1”的前四个字符的字节值覆盖。在ascii中,它们是0x73、0x6D、0x78、0x78。假设little-endian寻址,你最终得到的是devices [0]包含指向地址0x78786D73的指针。这个地址几乎肯定不会在进程内有效。当调用printf()尝试解引用这个无效指针时,操作系统会触发一个分段错误并转储核心。

问题在于OP在初始化时错误地将devices变量视为字符串(char数组)。实际上,它是一个指向char的指针数组,而printf()正在解释它。


如果原帖中的数组是指向常量的指针,我会点赞这个回答。 - Matt Curtis
常量性并不重要,它是一种语言概念。堆栈转储是由操作系统触发的。 - Andy Johnson
当然,const 是一种语言概念,但我宁愿编译器阻止我通过指向 const 的指针进行写入,而不是在运行时发生内核陷阱。 - Matt Curtis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接