Valgrind对两行代码抛出两个警告,每一行旁边的注释中都提到了。
警告1 :
大小为8的无效写入,地址...在大小为一个块的内部为8个字节 9已分配
data[size] = NULL;
警告2 :
有条件的跳跃或移动取决于未初始化的值
for (char **ptr = data; *ptr; ptr++) { // warning -> Conditional jump or move depends on uninitialized values(s)
free(*ptr);
}
这是完整的代码,
被叫方
char **getList() {
char **list = (char *[]) {"John", "Jane", NULL};
int size = 0;
for (char **ptr = list; *ptr; ptr++) {
size++;
}
char **data = malloc(sizeof(char *) * size + 1);
if (data == NULL) goto exception;
for (int i = 0; *list; list++, i++) {
data[i] = malloc(sizeof(char) * (strlen(*list) + 1));
if (data[i] == NULL) goto exception;
strcpy(data[i], *list);
}
data[size] = NULL; // this line gives warning
// warning -> invalid write of size 8, Address ... is 8 bytes inside a block of size 9 alloc'd
return data;
exception:
fprintf(stderr, "data allocation failed.\n");
return NULL;
}
呼叫者不同的文件/范围
char **data = getList();
for (char **ptr = data; *ptr; ptr++) { // warning -> Conditional jump or move depends on uninitialized values(s)
free(*ptr);
}
free(data);
答案 0 :(得分:1)
根据新的建议撰写。
编辑已根据评论进行了更新。
char **getList(void) {
const char * const list[] = {"John", "Jane", NULL};
unsigned int size = 0;
const char * const *ptr;
for (ptr = list; *ptr != NULL; ptr++) {
size++;
}
char **data = malloc(sizeof(char *) * (size + 1));
if (data == NULL) goto exception;
ptr = list;
for (unsigned int i = 0; *ptr != NULL; ptr++, i++) {
const size_t cache = strlen(*ptr) + 1;
data[i] = malloc(cache);
if (data[i] == NULL) goto exception;
memcpy(data[i], *ptr, cache);
}
data[size] = NULL;
return data;
exception:
fprintf(stderr, "Allocation failed.\n");
return NULL;
}
版本2
const char * const *getList(void) {
static const char * const list[] = {"John", "Jane", NULL};
return list;
}
答案 1 :(得分:0)
以下代码未经测试。我的建议是
尝试避免使用goto
char ** getList(){ char ** list =(char * []){“ John”,“ Jane”,NULL};
// this size is a compile time constant, no need to
calculate it at runtime
size_t size = sizeof(list)/sizeof(list[0]);
// using calloc initializes everything to 0/NULL
// -> no need to set the last element then
char **data = calloc(sizeof(char *), size);
// don't use goto
if (data != NULL)
{
for (size_t i = 0U; i < size; i++)
{
if (list[i] != NULL)
{
// don't re-invent the wheel with strlen/memcpy
// just use strdup
data[i] = strdup(list[i]);
if (data[i] == NULL) goto exception;
}
}
return data;
}
exception:
// you need to do more cleanup here
// for instance if the 'data' calloc succeeds, the "John" strdup succeeds
// but the "Jane" strdup fails then you have two leaks. That said fixing
// small leaks when you are out of memory usually isn't your biggest issue.
fprintf(stderr, "data allocation failed.\n");
return NULL;
}