gpt4 book ai didi

c - 重新分配影响 fgets

转载 作者:行者123 更新时间:2023-11-30 14:54:22 24 4
gpt4 key购买 nike

我正在尝试为用户输入重新创建一个简单的字符串解析器。我可以毫无问题地获取输入字符串,并确定其中有多少个单独的字符串,以便正确地为 malloc 提供正确的大小。最初,我没有在标准输入中找到字符串的数量,只是重新分配我的字符串数组,为另一个字符串留出空间,然后 malloc 新的字符串。现在我已经有了大小,我相信这是没有必要的,因为我只需为 malloc 提供适当的大小即可。

(尝试使用 calloc(),在同一位置出现段错误)

令我困惑的是,当我在代码中保留 realloc 时,没有任何问题(除了知道它可能会以不期望的方式调整我的数组之外)。但是,如果我删除 realloc,我的代码会在 fgets() 尝试执行时出现段错误。

这就是我调用解析器和我的#includes 的地方。 “appserver.h”保存所有原型(prototype)和 std(lib/bool/io),string/unistd/limits.h

#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( 中检索用户输入时,我会出现段错误) )。为什么注释掉 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;
}

这是我的 numberOfStrings() 方法的代码,如果这可能值得研究,但是我也使用 gdb 逐步完成了它,它看起来非常具体。

int numberOfStrings(char *input)
{
int count = 0;
char *tempCopy = malloc(sizeof(char*));
strcpy(tempCopy, input);
char* token = strtok(tempCopy, " ");
while(token != NULL)
{
token = strtok(NULL, " ");
count++;
}
free(tempCopy);
return count;
}

<小时/>编辑:我想跟进以确保我已经避免了大多数潜在的未定义行为。我没有更改 main 中的任何内容,因此这是我对 **stringParser()

的更改
char **stringParser()
{
char *input = nextLine(stdin);
int size = numberOfStrings(input, strlen(input));
char **inputArray = calloc(size, sizeof(*inputArray));
char *token = strtok(input, " ");
inputArray[0] = malloc(strlen(token));
strcpy(inputArray[0], token);
for(int i = 1; i < size - 1; i++)
{
token = strtok(NULL, " ");
inputArray[i] = malloc(strlen(token));
strcpy(inputArray[i], token);
}
free(input);
inputArray[size-1] = (char*)NULL;
return inputArray;
}

主要变化领域是:

  • 我使用 calloc() 而不是 malloc(),但如果我的理解正确的话 calloc(size, sizeof(*inputArray)) code> 的行为与 malloc((size)*sizeof(*inputArray)) 相同(忽略“0”或垃圾值初始化)
  • 我的一个 friend 写了一个 *nextLine(FILE *input) ,它允许我通过 stdin 逐个字符地扫描,直到到达 EOF'\n'。这样做的好处是可以准确分配用户输入所需的内存量。
  • 我确保数组中的每个字符串仅分配必要的内存量。 (与我之前所做的 sizeof(char*) 相反)
  • 我已确保在字符串数组的末尾包含一个空终止值。 (我对 numberOfStrings() 进行了一项更改,只是在 return 语句之前添加了 count++

这些变化让我不再有任何内存泄漏。我不敢假设我已经避免了所有未定义行为的行为,但我想我在这一点上做得更好一点。我确保不会用一堆其他问题来堵塞这篇文章,但我想把这个更新留在这里,以防有人发现它有用或相关。

最佳答案

realloc() 的调用不会影响 fgets() - 至少不会直接、可预测或可靠地影响。

stringParser() 中第一次调用 fgets(input, INT_MAX, stdin) 具有未定义的行为,因为指针 input 未初始化。

实际上,fgets() 的调用可能会覆盖一些不应该覆盖的内存区域。

通过添加(或注释掉)realloc() 的调用,结果将是对程序使用的内存布局进行一些调整(例如,更改代码或数据是否位于内存位置被 fgets() 覆盖。

但这并不是因为realloc()直接影响fgets()。这只是调用 realloc() 改变程序中某些内容这一事实的副作用。

注释掉 realloc() 调用或重新插入它的效果可以是任何东西。例如,如果您的代码是使用不同的编译器设置(例如优化标志)甚至不同的编译器构建的,则可能会得到不同的效果。

要消除 fgets() 的问题,请向其传递一个数组

  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() 调用

 // inputArray = realloc(inputArray, (i+1)*sizeof(char*));
inputArray[i] = malloc(sizeof(char*));

如果没有 realloc() 调用,对 inputArray[i] 的赋值也将具有未定义的行为。如果您还没有看到这种症状,那么您只是很幸运 - 再说一次,这是一种您不能依赖的影响。

检查各种函数(fgets()realloc() 等)是否实际成功也是一个好主意。您的代码基于以下假设继续进行:所有函数均按预期工作,但如果它们失败,则行为将是未定义的(例如,如果 realloc() 的内存重新分配失败)。

关于c - 重新分配影响 fgets,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46822799/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com