我已经完成了以下代码,但我找不到什么问题。函数getsxnremem()
使用len
获取最多fgets()
个字符的字符串,用空终止符覆盖换行符(如果有的话),然后重新调整内存大小以适应字符串。无论如何,这是个主意。
以下代码有时会起作用,有时会崩溃。我过去经常发生过这种情况,我经常发现问题,但这次我花了太长时间。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned getsxnremem(char **str, unsigned len){
unsigned l, flag = 1;
free(*str);
char *buff;
if ((*str = malloc(len)) == NULL) return 0;
if(fgets(*str, len, stdin) == NULL) { free(*str); return 0; }
l = strlen(*str);
if (l && ((*str)[l-1] == '\n')) { *(str)[l-1] = '\0'; flag = 0; }
if ((buff = realloc(*str, l + flag)) == NULL){ free(*str); return 0; }
*str = buff;
return (l - 1);
}
int main(void){
char *buff = NULL;
unsigned l = getsxnremem(&buff, 256);
printf("%s\n%u chars long.", buff, l);
}
答案 0 :(得分:10)
问题是,您未能在那里收集realloc()
的返回值。
根据C11
标准,章节§7.22.3.5
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
realloc
函数释放ptr
指向的旧对象并返回一个 指向具有size
指定大小的新对象的指针。 [...]
realloc()
调整内存大小,返回指向新内存的指针。考虑到free()
成功,旧记忆为realloc()
d。
所以,
您需要收集并检查realloc()
的返回值并对其进行测试以确保成功。然后,将其重新分配给*str
。
注意:请不要使用p = realloc(p, newsize);
之类的表单,因为如果realloc()
失败,您最终也会丢失实际指针。
如果realloc()
成功,则您不得free()
旧指针。在free()
- d内存上调用free()
会调用undefined behavior。
之后,正如other answer dbush中正确提到的,用法
{ *(str)[l-1] = '\0'; flag = 0; }
也错了。您所需的字符串由*str
表示,而不是str
。根据{{3}},数组下标运算符([]
)优先于解除引用(*
)运算符,所以基本上你的代码看起来像
{ * ((str)[l-1]) = '\0'; flag = 0; }
这不是你想要的。因此,要尊重operator precedence,您应该像
一样修改它{ (*str)[l-1] = '\0'; flag = 0; }
也就是说,在使用目标缓冲区之前,还应该检查fgets()
的返回值以确保成功。当malloc()
返回单位化内存时,如果fgets()
失败,你最终会从单位化内存中读取,这将再次导致UB。
答案 1 :(得分:1)
对于您最近的更新,您的括号位于错误的位置。
此:
if (l && ((*str)[l-1] == '\n')) { *(str)[l-1] = '\0'; flag = 0; }
应该是:
if (l && ((*str)[l-1] == '\n')) { (*str)[l-1] = '\0'; flag = 0; }
^---- here