影响FGET的Realloc
我正在尝试为用户输入重新创建一个简单的字符串解析器。我可以毫无疑问地获取输入字符串,并确定其中有多少个单独的字符串,以便为malloc提供正确的大小。起初,我在stdin中找不到字符串的数量,只需重新定位我的字符串数组,为多个字符串留出空间,然后malloc新字符串。既然我已经有了尺寸,我相信这是没有必要的,因为我可以为malloc提供合适的尺寸 尝试使用calloc,但在同一位置出现故障 我感到困惑的是,当我在代码中离开realloc时,除了知道它可能会以不希望的方式调整我的数组之外,没有任何问题。但是,如果我删除realloc,我的代码会在fgets尝试执行时出错 这正是我调用解析器和include的地方。h保存所有原型和stdlib/bool/io、string/unistd/limits.h影响FGET的Realloc,c,malloc,user-input,C,Malloc,User Input,我正在尝试为用户输入重新创建一个简单的字符串解析器。我可以毫无疑问地获取输入字符串,并确定其中有多少个单独的字符串,以便为malloc提供正确的大小。起初,我在stdin中找不到字符串的数量,只需重新定位我的字符串数组,为多个字符串留出空间,然后malloc新字符串。既然我已经有了尺寸,我相信这是没有必要的,因为我可以为malloc提供合适的尺寸 尝试使用calloc,但在同一位置出现故障 我感到困惑的是,当我在代码中离开realloc时,除了知道它可能会以不希望的方式调整我的数组之外,没有任何
#include "appserver.h"
int main(int argc, char *argv[])
{
if(argc != 4)
{
exit(0);
}
struct userInput user = { parseInt(*argv[1]), parseInt(*argv[2]), argv[3] };
printf("> ");
char **newArgs = stringParser();
for (int i = 0; newArgs[i] != NULL; i++)
{
free(newArgs[i]);
}
free(newArgs);
}
下面是我的解析器代码。如果我不注释realloc,我可以在gdb中单步执行代码,而不会出现问题。使用stdin中的整个字符串显示输入,但是,如果我将其注释掉,我会在尝试在fgets中检索用户输入时正确地选择segfult。为什么评论realloc甚至会对fgets产生影响
char **stringParser()
{
char *input;
fgets(input, INT_MAX, stdin);
int size = numberOfStrings(input);
char **inputArray = malloc((size)*(sizeof(char*)));
inputArray[0] = malloc(sizeof(char*));
strcpy(inputArray[0], strtok(input, " "));
for(int i = 1; i < size /*inputArray[i-1] != NULL*/; i++)
{
// inputArray = realloc(inputArray, (i+1)*sizeof(char*));
inputArray[i] = malloc(sizeof(char*));
strcpy(inputArray[i], strtok(NULL, " "));
printf("Inside inputArray[%d]: %s\n", i-1, inputArray[i-1]);
}
return inputArray;
}
编辑:
我想跟进以确保我已经避免了大多数潜在的未定义行为。
我没有在main中更改任何内容,所以这里是我在**stringParser中的更改
主要的变化领域包括:
我使用calloc而不是malloc,尽管如果我的理解正确,那么callocsize、sizeof*inputArray的行为与忽略“0”或垃圾值初始化时mallocsize*sizeof*inputArray的行为相同
我的一个朋友写了一个*nextLineFILE*输入,允许我通过标准输入法逐个字符地扫描,直到到达EOF或'\n'。这样做的好处是可以精确地分配用户输入所需的内存量。
我确保数组中的每个字符串只分配了必要的内存量。与我以前做的sizeofchar*相反
我已经确保在字符串数组的末尾包含一个null终止值。我在NumberOfString中做了一个更改,我只是在return语句之前添加了count++。
这些改变使我达到了不再有任何内存泄漏的地步。我不敢假设我已经避免了所有未定义的行为,但是,我想我在这一点上做得更好一些。我肯定不会因为一大堆其他问题而阻塞这篇文章,但我想把这个更新留在这里,以防有人发现它有用或相关 realloc的调用不会影响fgets——至少不会直接、可预测或可靠地影响fgets
stringParser中fgetsinput、INT_MAX、stdin的第一个调用具有未定义的行为,因为指针输入未初始化
实际上,fgets的调用可能会覆盖一些不应该覆盖的内存区域
通过添加或注释realloc调用,结果将对程序使用的内存布局进行一些调整,例如更改代码或数据是否位于被FGET覆盖的内存位置
但这并不是因为realloc直接影响FGET。这只是调用realloc会改变程序中某些内容这一事实的副作用
注释掉realloc调用或重新插入它可能会产生任何影响。例如,如果您的代码是使用不同的编译器设置(如优化标志,甚至是不同的编译器)构建的,则可能会得到不同的效果
要消除FGET的问题,请向其传递一个数组
char input[some_positive_value];
fgets(input, sizeof(input), stdin);
或者初始化指针以指向合适的缓冲区
char *input = malloc(some_positive_value); /* remember to `free()` when done */
fgets(input, some_positive_value, stdin);
注意,如上所述,循环确实需要realloc调用
如果没有realloc调用,对inputArray[i]的赋值也将具有未定义的行为。如果你没有看到这种症状,那你就幸运了——再说一次,这是一种你无法依赖的影响
检查各种功能fgets、realloc等是否实际成功也是一个好主意。您的代码是基于这样的假设进行的,即所有函数都按预期工作,但如果它们失败,行为将是未定义的,例如,如果realloc的内存重新分配失败。请解释char*tempCopy=mallocsizeofchar*行;fgetsinput,INT_MAX,stdin;:输入未初始化。@M.M我只是不喜欢输入原始整数值,还没有实现分配字符串确切长度的方法。或者,如果有任何简单的内置方式来做它,我还没有发现它。出于无知,我刚刚使用了sizeofchar*,因为它还没有给我带来任何麻烦。分配不足的空间,然后在该空间的结尾处写入内容会导致您的问题。正如这个问题所表明的那样,它现在给你带来了麻烦。我想我的困惑是因为如果我只留下realloc,为什么这个问题不会发生?因为FGET发生在realloc甚至m之前 alloc发生了。
char input[some_positive_value];
fgets(input, sizeof(input), stdin);
char *input = malloc(some_positive_value); /* remember to `free()` when done */
fgets(input, some_positive_value, stdin);
// inputArray = realloc(inputArray, (i+1)*sizeof(char*));
inputArray[i] = malloc(sizeof(char*));