我正在尝试执行一个函数,它将在char数组中存储一些要在其上打印的信息:
int offset = 0;
size_t size = 1;
char *data = NULL;
data = malloc(sizeof(char));
void create(t_var *var){
size_t sizeLine = sizeof(char)*(strlen(var->nombre)+2)+sizeof(int);
size = size + sizeLine;
realloc(data, size);
sprintf(data+offset,"%s=%d\n",var->name,var->value);
offset=strlen(data);
}
list_iterate(aList, (void *)create);
t_var是一个包含两个字段的结构:name(char *)和value(int)。
这段代码有什么问题?在Valgrind上运行时,它会抱怨realloc和sprintf。
答案 0 :(得分:4)
在不知道具体的valgrind错误的情况下,突出的是:
realloc(data, size);
应为data = realloc(data, size);
答案 1 :(得分:0)
我很抱歉地说,但你的代码几乎一切都有问题。
首先,代码不完整。
您说t_var
类型有两个成员,name
和value
。
但您的代码是指nombre
成员。您是否忘记提及或者在发布代码时忘记重命名?
其次,误用了sizeof
。
您使用sizeof(int)
表达式。你知道你在这里做了什么吗?!
显然,您尝试计算打印的int
值的长度。唉,运算符sizeof
检索有关参数在内存中占用的字节数的信息。因此,例如,对于32位整数,sizeof(int)
的结果是4(32位适合4个字节),但最大有符号32位整数值是幂(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
,因为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;
}
}