我很抱歉这么说,但你的代码几乎所有东西都是错误的。
首先,不完整的代码。
你说你的t_var
类型有两个成员,name
并且value
.
但是您的代码引用了一个nombre
成员。发布代码的时候是忘记提还是忘记重命名了?
二是误用sizeof
。
你使用一个sizeof(int)
表达式。你知道你在这里实际做什么吗?!
显然您尝试计算打印int
值的长度。唉,运算符sizeof
检索有关参数在内存中占用的字节数的信息。因此,例如,对于 32 位整数,其结果sizeof(int)
为 4(32 位适合 4 个字节),但最大有符号 32 位整数值为 power(2,31)-1,即2147483647
十进制。十位数,而不是四位数。
您可以使用(int)(2.41 * sizeof(any_unsigned_int_type)+1)
来确定打印 的值可能需要的字符数any_unsigned_int_type
。在有符号整数类型的情况下,为前面的减号添加一个。
魔术常数2.41
是256
(在第 3 位十进制数字处四舍五入)的十进制对数,因此它将以字节为单位的长度缩放为以十进制数字为单位的长度。
如果您希望避免浮点运算,您可以使用另一个近似值 29/12=2.41666...,然后计算(sizeof(any_unsigned_int_type)*29/12+1)
.
第三,sizeof(char)
。
您将结果strlen
乘以sizeof(char)
。
实际上,这不是一个错误,但完全没用,就像定义上的sizeof(char)
平等一样1
。
第四,realloc
。
正如其他人已经解释的那样,您必须存储返回值:
data = realloc(data, size);
否则,您可能会丢失重新分配的数据并继续在先前的位置写入,这可能会导致覆盖(因此破坏)堆上的其他一些数据。
第五,offset
。
您使用该值来确定要到达的位置sprintf()
。但是,在打印之后,您用 offset
最后打印输出的长度代替而不是增加它。结果连续sprintf
的 s 将覆盖以前的输出!
做:
offset += strlen(data);
第六:strlen
的sprintf
。
您根本不需要strlen
在这里调用,因为 family 的所有函数都会printf
返回打印的字符数。你可以使用它:
int outputlen = sprintf(data+offset, "%s=%d\n", var->name, var->value);
offset += outputlen;
第七:realloc
。严重地。
这是相当昂贵的功能。它可能需要对malloc
新大小的数据进行内部操作,将数据复制到新位置和free
旧块中。你为什么要强迫它?如果有一天它需要打印五千个字符串,它会对你的程序产生什么影响......?
这也是相当危险的。真的。假设您需要打印 5,000 个字符串,但只有 2,000 个空间。你会NULL
从realloc()
. 打印到该点的所有数据都还在当前data
指针处,但是接下来要做什么呢?
你怎么能告诉list_iterate
停止迭代......?
您如何通知上面的例程list_iterate
该字符串不完整...?
没有好的答案。幸运的是,您不需要解决问题——您可以避免解决问题!
解决方案。
首先遍历您的列表并计算您需要的缓冲区大小。然后分配缓冲区——只需一次!- 并继续填充它。只有一个地方分配可能会失败,如果发生这种情况,您根本无法解决问题:
int totaloutputlength = 0;
char *outputbuffer = NULL;
char *currentposition = NULL;
void add_var_length(t_var *var){
const int numberlength = sizeof(var->value)*29/12 + 1;
totaloutputlength += strlen(var->name) + 2 + numberlength;
}
void calculate_all_vars_length(t_list *aList){
totaloutputlength = 0;
list_iterate(aList, (void *)add_var_length);
}
void sprint_var_value(t_var *var){
int outputlen = sprintf(currentposition, "%s=%d\n", var->name, var->value);
currentposition += outputlen; // advance the printing position
}
int sprint_all_vars(t_list *aList){
calculate_all_vars_length(aList);
outputbuffer = malloc(totaloutputlength + 1); // +1 for terminating NUL char
// did allocation succeed?
if(outputbuffer == NULL) { // NO
// possibly print some error message...
// possibly terminate the program...
// or just return -1 to inform a caller something went wrong
return -1;
}
else { // YES
// set the initial printing position
currentposition = outputbuffer;
// go print all variables into the buffer
list_iterate(aList, (void *)sprint_var_value);
// return a 'success' status
return 0;
}
}