Какую альтернативу я могу использовать вместо gets() и puts()?

Фрагмент кода для 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(). Как мне это исправить?


person Blythe S.    schedule 31.01.2019    source источник
comment
Нет ничего плохого в использовании puts()   -  person user3629249    schedule 31.01.2019


Ответы (4)


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

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

char buffer[MAX_SIZE] = "";
if (fgets(buffer, MAX_SIZE ,stdin)) {
  buffer[strcspn(buffer,"\n")] = '\0';
}
person Stephan Lechner    schedule 31.01.2019
comment
Извините, почему вы выбрали fputs(), а не puts()? - person Sourav Ghosh; 31.01.2019
comment
Между gets() и fgets() есть несколько других различий, в том числе самое важное, что общее количество входных байтов ограничено. Единственная большая разница между puts() и fputs() заключается в том, что fputs() может записывать практически любой файл, а puts() может записывать только stdout. - person user3629249; 31.01.2019
comment
@Sourav Ghosh: просто для симметрии, поскольку fgets принимает поток FILE в качестве явного параметра, то же самое можно использовать и для выходной стороны. - person Stephan Lechner; 31.01.2019
comment
@ user3629249: ясно, есть много различий, которые привели к удалению gets из стандарта. Я имел в виду разницу в использовании... - person Stephan Lechner; 31.01.2019

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

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

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

[....]

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

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


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

person Sourav Ghosh    schedule 31.01.2019
comment
ошибка: слишком мало аргументов для функции fgets, она выдает мне это сообщение об ошибке, когда я использую fgets() - person Blythe S.; 31.01.2019
comment
@БлайтС. хоть мануал читай. Никто не говорил, что это замена. - person Federico klez Culloca; 31.01.2019
comment
@БлайтС. Пожалуйста, прочитайте соответствующую справочную страницу, как указано в ответе. - person Sourav Ghosh; 31.01.2019
comment
в любом случае я могу использовать getchar() вместо этого? - person Blythe S.; 31.01.2019
comment
@БлайтС. Да, конечно, можете, но если вашей целью является чтение строк, fgets() является предпочтительным способом. - person Sourav Ghosh; 31.01.2019
comment
@БлайтС. Задав новый вопрос или выполнив поиск на этом сайте, как использовать getchar() - person nos; 31.01.2019
comment
@БлайтС. Я настоятельно рекомендую вам сначала прочитать руководство. Базовая схема будет заключаться в том, чтобы использовать цикл, читать из ввода один за другим, пока не останется элемент буфера или вы не введете завершающий нуль, а затем. закончить петлю. - person Sourav Ghosh; 31.01.2019
comment
@nos При всем уважении, сэр, использование getchar() не подходит для SO. В случае возникновения проблем во время использования, мы будем рады услышать об этом. - person Sourav Ghosh; 31.01.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);
}
person Mayur    schedule 31.01.2019

альтернативу я могу использовать вместо gets()

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);
}
person chux - Reinstate Monica    schedule 31.01.2019
comment
Возможно, вам нужен один ungetc(), когда буфер слишком короткий, чтобы не потерять 1 символ. - person pmg; 31.01.2019
comment
@pmg Для mygets() идея состоит в том, чтобы всегда потреблять всю строку и не оставлять лишнюю часть длинной строки в stdin - возвращая условие ошибки. - person chux - Reinstate Monica; 31.01.2019
comment
Плохо... я s = NULL; /*imagined*/break; читал, а ты продолжаешь читать - person pmg; 31.01.2019