Какую альтернативу я могу использовать вместо gets () и put ()? - PullRequest
0 голосов
/ 31 января 2019

Фрагмент кода для 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 голосов
/ 31 января 2019

альтернативу можно использовать вместо get ()

char str[MAX_SIZE]; gets() возникают проблемы при чтении строки из N символов.(N также учитывает '\n').

  • Когда N > MAX_SIZE, результатом будет неопределенное поведение (UB).Слишком много информации и некуда идти.Часто этот UB записывает в места, используемые другими объектами.Плохо - очень плохо.

  • C11 исключено gets() и с тех пор не является стандартной функцией.

Обычное решение fgets()хорошо предложено @ Stephan Lechner .fgets() имеет некоторые недостатки, перечисленные ниже.

  1. str[MAX_SIZE] теперь должно быть str[MAX_SIZE + 1], поскольку fgets() также сохраняет '\n', в отличие от gets().Иногда добавление + 1 нецелесообразно.

  2. fgets() сохраняет потенциал '\n'.См. Удаление завершающего символа новой строки из fgets ()

  3. Если ввод слишком большой, fgets() просто не читает его, в отличие от gets().Это хорошо ведет себя (не UB), но мы все еще сталкиваемся с этой проблемой: как обнаружить чрезмерный ввод и что с этим делать?

Если код может с этим справиться, используйте fgets().В противном случае читайте дальше.


mygets() альтернатива

Эта функция не нуждается в +1 к размеру буфера s.

Чрезмерно длинный ввод возвращает 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() немного сомнительно на этом.

  • Размер буфера - идиоматический 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);
}
0 голосов
/ 31 января 2019

Никогда не используйте gets().Поскольку невозможно заранее не знать, сколько символов будет прочитано gets(), а из-за того, что gets() будет продолжать хранить символы после конца буфера, использовать его крайне опасно.Он был использован для взлома компьютерной безопасности.Используйте fgets() вместоchar * fgets ( char * str, int num, FILE * stream );

В следующем примере показано использование функции 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);
}
0 голосов
/ 31 января 2019

Используйте fgets и fputs вместо.Помимо устранения всех недостатков gets, есть и основное отличие в использовании между gets и fgets: fgets сохраняет символ новой строки в буфере (а gets - нет).

Таким образом, эквивалент - то есть исключение любой новой строки, если не желательно - может выглядеть следующим образом.Вызов функции strcspn(buffer,"\n") дает самую длинную последовательность символов, пока не встретится новая строка (или strlen (буфер), если строка не содержит новой строки).Путем записи 0 в индекс в этой позиции новая строка - если таковая имеется - исключается.

char buffer[MAX_SIZE] = "";
if (fgets(buffer, MAX_SIZE ,stdin)) {
  buffer[strcspn(buffer,"\n")] = '\0';
}
0 голосов
/ 31 января 2019

Вы должны абсолютно, безусловно, избегать использования gets(), , это опасно и удалено из недавнего стандарта C. Вот почему вы видите предупреждение

C11, Предисловие, пункт 6 упоминает

Основные изменения по сравнению с предыдущим изданием:

[....]

  • удалена функция gets (<stdio.h>)

Вместо этого используйте fgets().


Чтобы добавить, puts() просто отлично, я не вижу причин для замены этого.

...