为什么fgets会覆盖看似无关的变量?

时间:2017-11-28 19:36:52

标签: c

我在学习C的同时从事一个小项目,偶然发现了一个让我疯狂的问题。 我有一个结构,其中包含指向同一类型的其他结构的指针,以及一个从stdin获取字符串的输入数组

typedef struct Node
{
  char *objectName;
  char *question;
  struct Node *yesPtr;
  struct Node *noPtr;
}Node;

int main(int argc, char **argv)
{
  Node *rootNode = initialise(LAUNCH_TYPE);
  Node *currentNode = rootNode;
  int quit = 0;
  char input[INPUT_SIZE];
  while (quit == 0)
  {
   ...

但是,在尝试使用fgets接受输入时,它将覆盖看似无关的变量。

fgets(input,INPUT_SIZE,stdin);
input[strcspn(input, "\n")] = '\0';
pNew->objectName = input;              //Code works here, input behaves as expected..
printf(pNew->objectName); //..and this is correct
printf("Please type a question!\n");

fgets(input,INPUT_SIZE,stdin);         //However, this line overwrites pNew->objectName to its input
input[strcspn(input, "\n")] = '\0';
currentNode->question = input;         //While this line still functions as expected
printf(pNew->objectName);              //This will now (incorrectly) print out the string that had just been entered

即使使用完全独立于结构的变量,也会出现完全相同的问题。

fgets(input,INPUT_SIZE,stdin);
input[strcspn(input, "\n")] = '\0';
char *newObject = input;              //Even when replacing the pointer with another variable
printf(newObject);
printf("Please type a question!\n");

fgets(input,INPUT_SIZE,stdin);       //This line will overwrite the new variable too
input[strcspn(input, "\n")] = '\0';
currentNode->question = input;
pNew->objectName = newObject;
printf(pNew->objectName);            //And results in the same problem

我已经解决了这个问题多年,并且无法在线找到任何解决方案,虽然它可能只是一些奇怪的malloc错误,有谁知道为什么会发生这种情况?

2 个答案:

答案 0 :(得分:1)

执行此操作时:

pNew->objectName = input;

您已将input数组的地址指定给objectName。您制作副本。

然后当你这样做时:

currentNode->question = input;

您再次将input的地址分配给此字段。所以现在pNew->objectNamecurrentNode->question都指向同一个地方,即input。因此,当您使用上述任一变量时,任何时候input更改都会反映出来。

要制作字符串的副本,请使用strdup

pNew->objectName = strdup(input);

这为字符串的副本动态分配内存,将字符串复制到新分配的内存,并返回该内存的地址。

在清理包含的结构时,请确保在每个对象上调用free

答案 1 :(得分:1)

您一直在扫描同一个变量,即进入input

您需要为每个变量分配新内存。像:

fgets(input,INPUT_SIZE,stdin);
input[strcspn(input, "\n")] = '\0';
char* tmp = malloc(strlen(input) + 1);  // Allocate memory - Plus 1 for the string termination
if (tmp == NULL)
{
    // ups... out of mem
    exit(1);
}
strcpy(tmp, input);
pNew->objectName = tmp;

另一种方法是使用strdup,但这不是标准的一部分,因此并非所有系统都支持它。