以下是某次考试中的一段话(1%顶尖大学)。
我失败了,因为我的答案与 "认可 "的答案不同。
我有一种预感,他(教授,著名的C语言专家)的答案不正确。
下面,是 "认可 "答案后的问题。
下面的函数中存在一个潜在的bug。是什么,如何修复?
提示:这与realloc()函数的使用有关。请找出你要更改的行号,以及用什么来代替它们。
BOOLEAN lengthen_string(char* string, const char newcontents[]) { int newlen = strlen(string) + strlen(newcontents) + 1; string = realloc(string, newlen); if (!string) { perror("malloc"); return FALSE; } strcat(string, newcontents); return TRUE; }
教授提供的 "正确 "答案是。
第4行:当分配失败时,realloc会返回一个NULL指针。这意味着在失败时,原来的数据会丢失。
要解决这个问题,可以将realloc的结果分配给一个临时变量,先测试一下。
即:第4行。
char * temp=realloc(string, newlen); if(!temp) ... (all remains the same)
在旧的第9行之后,
string = temp
;
有什么想法吗?
另外,我的答案是@string是一个局部变量,函数的原型应该是 char **string
,其中调用者将一个指针传递给它的字符串指针,然后被调用者将把任何realloc()返回值分配给 *string
有什么想法吗?
教授是正确的,因为 realloc()
在失败时,不会改变传入的内存,因此留下输入的 string
指针完好无损,但如果失败时的NULL返回值被立即赋值给 string
那么原来的数据就会丢失和泄露。所以在将新指针值赋给 string
.
你是对的,在这一点上 string
需要通过指针来传递,以便在遇到 realloc()
返回一个不同的内存地址。
正确的解决方案应该是这样的。
BOOLEAN lengthen_string(char** string, const char newcontents[])
{
if (!string)
{
errno = EINVAL;
perror("bad input");
return FALSE;
}
size_t newsize = strlen(*string) + strlen(newcontents) + 1;
char *temp = realloc(*string, newsize);
if (!temp)
{
perror("realloc failed");
return FALSE;
}
strcat(temp, newcontents);
*string = temp;
return TRUE;
}
另外,还有一些优化的空间,例如:
BOOLEAN lengthen_string(char** string, const char newcontents[])
{
if (!string)
{
errno = EINVAL;
perror("bad input");
return FALSE;
}
char *temp;
if (!*string)
{
temp = strdup(newcontents);
if (!temp)
{
perror("strdup failed");
return FALSE;
}
}
else
{
size_t offset = strlen(*string);
size_t size = strlen(newcontents) + 1;
temp = realloc(*string, offset + size);
if (!temp)
{
perror("realloc failed");
return FALSE;
}
memcpy(temp + offset, newcontents, size);
}
*string = temp;
return TRUE;
}