C 结构内部数组的声明有时会失败
是什么导致以下代码在某些Linux/gcc环境中失败?我声明一个结构,然后创建这个结构的“实例”。问题在于数组,它应该包含单独的字符串并且可以调整大小。详情:C 结构内部数组的声明有时会失败,c,arrays,struct,segmentation-fault,C,Arrays,Struct,Segmentation Fault,是什么导致以下代码在某些Linux/gcc环境中失败?我声明一个结构,然后创建这个结构的“实例”。问题在于数组,它应该包含单独的字符串并且可以调整大小。详情: typedef struct { char (*pointer)[256]; int used; int size; } Array; Array *createArray(int start_size) { Array *array = malloc(sizeof( *array)); arra
typedef struct {
char (*pointer)[256];
int used;
int size;
} Array;
Array *createArray(int start_size) {
Array *array = malloc(sizeof( *array));
array->used = 0;
array->size = start_size;
array->pointer = malloc(start_size * sizeof *array->pointer); // <--- here
return array;
}
Valgrind显示,上面标有
的行上有一个错误,需要根据Pablo的评论修复解析
逻辑并改进realloc
!如上所述,当malloc
或realloc
返回时,检查NULL
这是一个用于进一步改进的MCVE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_SIZE 256
typedef struct {
char (*pointer)[256];
int used;
int size;
} Array;
Array *createArray(int start_size) {
Array *array = malloc(sizeof(*array));
array->used = 0;
array->size = start_size;
array->pointer = malloc(start_size * sizeof * array->pointer); //
return array;
}
void append(Array *array, char* elem) {
if (array->used >= array->size) {
// expand table
array->pointer = realloc(array->pointer, array->size * 2 * sizeof * array->pointer);
array->size *= 2;
}
// append new arg
strcpy(array->pointer[array->used] , elem); // <-- here
array->used++;
}
Array *parse(char* command) {
// split command by space and store each arg in array
char *args_str;
Array *args_list = createArray(DEFAULT_SIZE); // expandable array holding arguments
args_str = strtok(command, " ");
append(args_list, args_str);
args_str = strtok(NULL, " ");
append(args_list, args_str);
return(args_list);
}
int main(void)
{
char str[] = { '1', '2', '3', ' ', '5', '6', '7', ' ', 0 };
Array *p = parse(str);
printf("%s\n",p->pointer[0]);
printf("%s\n",p->pointer[1]);
return 0;
}
我将引用我自己的评论:
在append中,您应该声明char(*tmp)[256]代码>并像这样调用realloc:tmp=realloc(数组->指针,…)代码>
然后检查tmp==NULL
并处理错误情况,如果不是NULL
,array->pointer=tmp代码>。
如果源字符串elem的长度超过255个字符,也可能导致指针溢出,
这将导致未定义的行为。使用
strncpy(array->pointer[array->used] , elem, sizeof *array->pointer[array->used]);
array->pointer[array->used][sizeof(array->pointer[array->used]) - 1] = 0;
相反
append
函数有一个小问题,它不会返回
任何东西我将其修改为:
Array *parse(char* command) {
// split command by space and store each arg in array
char *args_str;
Array *args_list = createArray(DEFAULT_SIZE); // expandable array holding arguments
args_str = strtok(command, " ");
do {
append(args_list, args_str);
} while(args_str = strtok(NULL, " "));
return args_list;
}
我获取了您的代码并修复了parse
函数,并从我的main
功能
int main(void)
{
Array *array;
char cmd[] = "ls -alh --color /tmp";
array = parse(cmd);
if(array == NULL)
return 0;
printf("Array->used: %d, array->size: %d\n", array->used, array->size);
for(int i = 0; i < array->used; ++i)
puts(array->pointer[i]);
free(array->pointer);
free(array);
}
代码运行正常,问题可能是由于未定义的
调用parse
之前的行为。我已将测试代码放在这里:
正如您在ideone上看到的,代码也会产生正确的结果。问题在于您没有显示的代码。Valgrind告诉你内存分配的位置。它还告诉您在哪里使用了分配给那里的未初始化值。查看该行。请参见@MattS no,Array*Array=malloc(sizeof(*Array))代码>是正确的sizeof*array
返回array
对象需要的字节数sizeof(array)
返回指向array
的指针需要存储的字节数。似乎您不理解malloc
。在append
中,您应该声明char(*tmp)[256]
并像这样调用realloc
:tmp=realloc(数组->指针,…)
然后检查tmp==NULL
并处理错误情况,如果不是NULL
,array->pointer=tmp
;。如果源字符串elem
长度超过255个字符,也可能导致指针溢出,这将导致未定义的行为。使用strncpy(数组->指针[数组->使用]、元素、大小*数组->指针[数组->使用];数组->指针[数组->已用][sizeof(数组->指针[数组->已用])-1]=0改为code>。@MattS OP正在为维度为256的数组->大小数组分配空间。如果OP有char**指针
,那么OP必须malloc
大小array->size*sizeof(char*)
,并且for everyi
必须再次执行malloc
大小为256的操作。
123
567
strncpy(array->pointer[array->used] , elem, sizeof *array->pointer[array->used]);
array->pointer[array->used][sizeof(array->pointer[array->used]) - 1] = 0;
Array *parse(char* command) {
// split command by space and store each arg in array
char *args_str;
Array *args_list = createArray(DEFAULT_SIZE); // expandable array holding arguments
args_str = strtok(command, " ");
do {
append(args_list, args_str);
} while(args_str = strtok(NULL, " "));
return args_list;
}
int main(void)
{
Array *array;
char cmd[] = "ls -alh --color /tmp";
array = parse(cmd);
if(array == NULL)
return 0;
printf("Array->used: %d, array->size: %d\n", array->used, array->size);
for(int i = 0; i < array->used; ++i)
puts(array->pointer[i]);
free(array->pointer);
free(array);
}