我有以下测试函数来复制和连接可变数量的字符串参数,并自动分配:
char *copycat(char *first, ...) {
va_list vl;
va_start(vl, first);
char *result = (char *) malloc(strlen(first) + 1);
char *next;
strcpy(result, first);
while (next = va_arg(vl, char *)) {
result = (char *) realloc(result, strlen(result) + strlen(next) + 1);
strcat(result, next);
}
return result;
}问题是,如果我这样做:
puts(copycat("herp", "derp", "hurr", "durr"));它应该打印出一个16字节的字符串"herpderphurrdurr"。相反,它会打印出一个42字节的字符串,即正确的16字节加上另外26字节的垃圾字符。
我还不是很确定为什么。有什么想法吗?
发布于 2010-11-07 18:46:43
变量参数列表函数不会神奇地知道有多少个参数,所以您很可能会遍历堆栈,直到碰巧遇到NULL。
您要么需要一个参数numStrings,要么在字符串列表后提供一个显式的空终止符参数。
发布于 2010-11-07 18:50:02
你需要在你的列表上有一个标记:
puts(copycat("herp", "derp", "hurr", "durr", NULL));否则,va_arg实际上不知道何时停止。你得到垃圾的事实纯粹是偶然的,因为你调用了未定义的行为。例如,当我按原样运行你的代码时,我得到了一个分段错误。
可变参数函数,如printf,需要某种形式的指示,说明传入了多少项:printf本身预先使用格式字符串来解决这个问题。
这两个通用方法是count (或格式字符串),当您不能使用其中一个可能的值作为标记(末尾的标记)时,此方法非常有用。
如果您可以使用标记(如指针中的NULL,或非负有符号整数中的-1 ),这通常会更好,这样您就不必计算元素的数量(并且有可能使元素计数和元素列表不同步)。
请记住,puts(copycat("herp", "derp", "hurr", "durr"));是一个内存泄漏,因为您正在分配内存,然后丢失指向它的指针。使用:
char *s = copycat("herp", "derp", "hurr", "durr");
puts(s);
free (s);是解决这个问题的一种方法,您可能想放入错误检查代码,以防分配失败。
发布于 2010-11-07 18:59:23
我从你的代码中理解的是,你假设一旦每个参数都被“弹出”,va_next就会返回NULL。这是错误的,因为va_next完全没有办法确定参数的数量: while循环将一直运行,直到随机命中一个NULL。
解决方案:提供参数的数量,或者使用附加的"NULL“参数调用函数。
PS:如果你想知道为什么printf不需要这样一个额外的参数,那是因为预期参数的数量是从格式字符串中推导出来的(‘%flag’的数量)
https://stackoverflow.com/questions/4117355
复制相似问题