用fgets()替换gets()

7

我一直在测试这个结构,并且收到了使用gets的警告。有人建议使用fgets代替,并将结尾替换为'\0'。您有什么建议可以帮助我修改代码吗?

void regCars(Car reg[], int *pNrOfCars) {
    char again[WORDLENGTH] = "yes", model[WORDLENGTH], tmp[WORDLENGTH];
    int year, milage;

    while (strcmp(again, "yes") == 0) {
        printf("Enter model:");
        gets(model);
        printf("Enter Year:");
        gets(tmp);
        year = atoi(tmp);
        printf("Enter milage:");
        gets(tmp);
        milage = atoi(tmp);
        reg[*pNrOfCars] = createCar(model, year, milage); 
        (*pNrOfCars)++;
        printf("Continue? (yes/no)");
        gets(again);
    }
}
3个回答

1

这比看起来要棘手一些。如果您仅仅将gets替换为fgets(),然后在输入过长的情况下处理截断行并将其作为有效行处理,那么这样做没有太多意义。您只是将未定义的行为替换为错误的行为。

if( fgets(line, sizeof(line), fp) )
{
   if(!strchr(line, '\n'))
   {
      /* line is too long, what you do is up to you, but normally
         we will discard it */
      int ch;

      while( (ch = fgetc(fp)) != EOF)
        if(ch == '\n')
          break;

   }
   else
   {
       /* line is a normal line with a trailing '\n' (gets trims the '\n')           */
   }
}

不必仅仅舍弃长行……在计算机程序编写的文本文件中,长行非常频繁。fgets()可以读取它们……只需要更多的调用和逻辑来处理它们。 - Peter
如果有效行是无界的,fgets() 不是您的输入函数选择。但当然,过长的行意味着什么取决于情况,有时丢弃它是错误的。默默地截断并将其余部分与完整行无法区分几乎从来不是正确的行为。 - Malcolm McLean

0

只需举个例子

if (NULL != fgets(model, WORDLENGTH, stdin)) /* Read the string. */
{
  model[strcspn(model, "\r\n")] = '\0'; /* Cut off \n and/or \r, if any. */
}

我认为这只是针对模型的,如果我有多个整数和字符,是否有一个函数可以查看所有这些并替换 \n? - xxFlashxx
@Alex:fgets()(以及get())只能读取“字符串”。如果要读取“年份”,可以使用gets(tmp),并按照所示进行替换。 - alk
我应该在fgets(model)之后立即插入if语句吗? - xxFlashxx
是的。而且你想为else情况添加一些错误处理。 - alk
同时阅读使用的函数文档也是我推荐的。 - alk

0
你可以编写一个实用函数mygets(),它需要2个参数:指向目标数组的指针和目标数组的大小:
char *mygets(char *dest, size_t size) {
    /* read a line from standard input and strip the linefeed if any */
    if (fgets(dest, size, stdin)) {
        dest[strcspn(dest, "\n")] = '\0');
        return dest;
    }
    return NULL;
}

void regCars(Car reg[], int *pNrOfCars) {
    char model[WORDLENGTH], tmp[WORDLENGTH];
    int year, milage;

    for (;;) {
        printf("Enter model:");
        if (!mygets(model, sizeof mode))
            break;
        printf("Enter year:");
        if (!mygets(tmp, sizeof tmp))
            break;
        year = atoi(tmp);
        printf("Enter milage:");
        if (!mygets(tmp, sizeof tmp))
            break;
        milage = atoi(tmp);
        reg[*pNrOfCars] = createCar(model, year, milage); 
        (*pNrOfCars)++;
        printf("Continue? (yes/no)");
        if (!mygets(tmp, sizeof(tmp))
            break;
        if (strcmp(again, "yes") != 0)
            break;
    }
}

请注意,您可以使用prompt()函数来因式分解更多的代码,该函数输出问题并读取响应:
char *prompt(const char *message, char *dest, size_t size) {
    printf("%s ", message);
    fflush(stdout);
    /* read a line from standard input and strip the linefeed if any */
    if (fgets(dest, size, stdin)) {
        dest[strcspn(dest, "\n")] = '\0');
        return dest;
    }
    return NULL;
}

void regCars(Car reg[], int *pNrOfCars) {
    char model[WORDLENGTH], tmp[WORDLENGTH];
    int year, milage;

    for (;;) {
        if (!prompt("Enter model:", model, sizeof mode))
            break;
        if (!prompt("Enter year:", tmp, sizeof tmp))
            break;
        year = atoi(tmp);
        if (!prompt("Enter milage:", tmp, sizeof tmp))
            break;
        milage = atoi(tmp);
        reg[*pNrOfCars] = createCar(model, year, milage); 
        (*pNrOfCars)++;
        if (!prompt("Continue? (yes/no)", tmp, sizeof(tmp))
            break;
        if (strcmp(again, "yes") != 0)
            break;
    }
}

同时请注意,此函数应该接受reg数组的大小,以便在其已满时停止提示更多的输入。如当前规定的,它与gets()具有相同的缺点,意外的输入将导致未定义的行为。


@Alex:你介意给你认可的答案点个赞吗? - chqrlie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接