除了gets()和puts()之外,我还能使用什么替代方法?

时间:2019-01-31 08:06:28

标签: c gcc gcc-warning gets

gets()的代码段

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

puts()的代码段

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

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

4 个答案:

答案 0 :(得分:4)

请改用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';
}

答案 1 :(得分:3)

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

C11,前言中提到了第6段

  

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

     

[....]

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

相反,请使用fgets().


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

答案 2 :(得分:1)

请勿使用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);
}

答案 3 :(得分:0)

  

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

读取char str[MAX_SIZE]; gets()个字符的时,

N有问题。 (N也算为'\n')。

  • N > 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);
}