影响fgets的Realloc

时间:2017-10-19 04:21:03

标签: c malloc user-input

我试图为用户输入重新创建一个简单的String解析器。我可以毫无问题地获取输入字符串,并确定其中有多少单独的字符串,以正确地为malloc提供正确的大小。最初我没有在stdin中找到Strings的数量,只是重新分配我的String数组以允许多一个String的空间,然后malloc新的String。既然我有这个尺寸,我相信这不是必要的,因为我可以提供具有适当尺寸的malloc。

(尝试使用calloc(),在同一地点进行segfaulted)

我感到困惑的是,当我在我的代码中留下realloc时没有问题(除了知道它可能会以不合需要的方式调整我的数组)。但是,如果我删除realloc,我的代码段错误即时fgets()尝试执行。

这就是我调用解析器的地方,以及我的#includes。 " appserver.h"保存所有原型和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))的行为相同(忽略&#39; 0&#39;或垃圾值初始化) malloc((size)*sizeof(*inputArray))
  • 我的一位朋友写了一个*nextLine(FILE *input),允许我逐个字符地扫描stdin,直到我到达EOF'\n'。这样做的好处是可以准确分配用户输入所需的内存量。
  • 我确保我的数组中的每个String只分配了必要的内存量。 (与之前的sizeof(char*)相反)
  • 我确保在String数组的末尾包含一个空终止值。 (我在numberOfStrings()中做了一处更改,我在return语句之前添加了count++

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

1 个答案:

答案 0 :(得分:1)

realloc()的来电不会影响fgets() - 至少,不是直接,可预测或可靠。

fgets(input, INT_MAX, stdin)stringParser()的第一次调用具有未定义的行为,因为指针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()的内存重新分配失败),则行为将是未定义的。