c - 重新分配影响 fgets

标签 c malloc user-input

我正在尝试为用户输入重新创建一个简单的字符串解析器。我可以毫无问题地获取输入字符串,并确定其中有多少个单独的字符串,以便正确地为 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/

相关文章:

c - 以下是二维数组吗?

c - C 标准 malloc'ing 字符的潜在问题

javascript - Canvas 点对点用户线

c - 为什么SW4STM32 subdir.mk会生成错误?

c - 读取大数据时有没有比 fscanf 更快的方法

linux - 关于glibc中malloc实现的问题

java - 如何让高分榜与用户保持联系?

c - 如何正确释放结构体? ANSI C

c - 用户在逐个字符扫描的字符串中无限输入

c - 将用户输入写入文件,然后读取它