【问题标题】:What alternative can I use instead of gets() and puts()?我可以使用什么替代方法来代替gets() 和puts()?
【发布时间】:2019-01-31 08:06:28
【问题描述】:

gets() 的代码 sn-p

int main(int argc, char *argv[])
{
    char str[MAX_SIZE]
    gets(str);
    printf("\n");

puts() 的代码 sn-p

  printf("The most probable key is: %d\n", max2);
  puts(output);
  return 0;

我没有粘贴我的整个代码,因为它似乎与我的问题无关。我只是想知道一种可以解决此问题的方法,因为当我通过 GCC 运行代码时,它会给我带来错误并且不允许我使用 gets()。我该如何解决这个问题?

【问题讨论】:

  • 使用puts()没有错

标签: c gcc gcc-warning gets


【解决方案1】:

请改用fgetsfputs。除了删除gets 的所有缺陷之外,还有getsfgets 之间用法的主要区别:fgets 在缓冲区中存储一个换行符(而gets 没有)。

因此,等效项(即,如果不需要,则删除任何新行)可能如下所示。函数调用strcspn(buffer,"\n") 给出最长的字符序列,直到遇到新行(或 strlen(buffer),如果字符串不包含新行)。通过将0 写入该位置的索引,新行(如果有)将被删除。

char buffer[MAX_SIZE] = "";
if (fgets(buffer, MAX_SIZE ,stdin)) {
  buffer[strcspn(buffer,"\n")] = '\0';
}

【讨论】:

  • 抱歉,为什么选择fputs() 而不是puts()
  • gets()fgets() 之间还有其他一些区别,其中最重要的一点是输入字节的总数是有限的。 puts()fputs() 之间唯一的大区别是 fputs() 可以写入大多数文件,而 puts() 只能写入 stdout
  • @Sourav Ghosh:只是为了对称,因为fgets 将 FILE 流作为显式参数,所以同样可以用于输出端。
  • @user3629249:很清楚,有许多差异导致将gets 从标准中删除。我的意思是用法上的不同......
【解决方案2】:

您绝对应该避免使用gets()its dangerous 并从最近的C 标准中删除。 That's why you see the warning

C11,前言,第 6 段提及

与上一版相比的主要变化包括:

[....]

  • 删除了 gets 函数 (<stdio.h>)

改为使用fgets().


补充一点,puts() 很好,我认为没有理由更换那个。

【讨论】:

  • 错误:函数“fgets”的参数太少,当我使用 fgets() 时它给了我这个错误消息
  • @BlytheS。至少阅读手册。没有人说这是一个替代品。
  • @BlytheS。请阅读答案中链接的相关手册页。
  • @BlytheS。通过提出新问题或搜索本网站了解如何使用 getchar()
  • @nos 恕我直言,先生,如何使用 getchar() 不适合 SO。如果在使用过程中出现问题,我们很乐意听到。
【解决方案3】:

永远不要使用gets()。因为事先不知道数据是不可能知道gets() 将读取多少个字符,并且因为gets() 将继续存储超过缓冲区末尾的字符,所以使用起来非常危险。它已被用来破坏计算机安全。
请改用fgets()
char * fgets ( char * str, int num, FILE * stream );

下面的example展示了fgets()函数的用法。

#include <stdio.h>

int main () {
   FILE *fp;
   char str[60];

   /* opening file for reading */
   fp = fopen("file.txt" , "r");
   if(fp == NULL) {
      perror("Error opening file");
      return(-1);
   }
   if( fgets (str, 60, fp)!=NULL ) {
      /* writing content to stdout */
      puts(str);
   }
   fclose(fp);

   return(0);
}

【讨论】:

    【解决方案4】:

    我可以使用替代方法来代替gets()

    char str[MAX_SIZE]; gets() 在读取N 字符的 时出现问题。 (N 也算'\n')。

    • N &gt; MAX_SIZE 时,结果是未定义的行为 (UB)。输入太多,无处可去。通常,此 UB 会写入其他对象使用的位置。糟糕 - 非常糟糕。

    • C11 淘汰了gets(),从此不再是标准功能。

    @Stephan Lechner 很好地建议了通常的fgets() 解决方案。 fgets() 有一些不足之处。

    1. str[MAX_SIZE] 现在需要为str[MAX_SIZE + 1],因为fgets() 还保存了'\n',这与gets() 不同。有时加 + 1 是不切实际的。

    2. fgets() 保留了潜力 '\n'。见Removing trailing newline character from fgets()

    3. 当输入过多时,fgets() 根本不会读取它,这与gets() 不同。这表现良好(不是 UB),但我们仍然遇到这个问题:如何检测过度输入以及如何处理?

    如果代码可以接受这些,请使用fgets()。否则,请继续阅读。


    mygets()替代

    此函数不需要对s 缓冲区的大小+1。

    过长的输入返回NULL。读取所有行。 s 缓冲区被初始字符填充。

    char *mygets(char *s, size_t n) {
      char *dest = s;
    
      // Pathological case of n==0
      char dummy[1];
      if (n == 0) {
        n = sizeof dummy;
        dest = dummy;
      }
    
      size_t i = 0;
      int ch;
      n--;
      while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
        if (i < n) {
          dest[i++] = (char) ch;
        } else {
          s = NULL; // Not enough room
        }
      }
    
      if (ch == EOF) {
        if (feof(stdin)) {  // end-of-file
          if (i == 0) {
            s = NULL;
          }
        } else { // input error
          i = 0;
          s = NULL;
        }
      }
    
      dest[i] = '\0';
      return s;
    }
    

    微妙的奖励:

    • s 缓冲区在罕见的输入错误上定义良好。使用gets/fgets 时,缓冲区内容未定义。

    • 0 的病理大小已明确定义。 fgets() 有点像iffy

    • 缓冲区大小是惯用的size_t,而不是int,就像fgets()


    用法

    str[MAX_SIZE];
    
    if (mygets(str, sizeof str)) {
      printf("Success <%s>\n", str);
    } else {
      if (feof(str)) printf("End of file detected. <%s>\n", str);
      else if (ferror(str)) printf("End of file detected.  <%s>\n", str);
      else printf("Input too long <%s>.", str);
    }
    

    【讨论】:

    • 当缓冲区太短而无法避免丢失 1 个字符时,您可能需要一个 ungetc()
    • @pmg 对于mygets(),我们的想法是始终使用整行,而不是在stdin 中留下长行的多余部分——返回错误条件。
    • 我的错……我读了s = NULL; /*imagined*/break;,但你继续读
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多