Проблема с EOF в C - PullRequest
       50

Проблема с EOF в C

2 голосов
/ 26 октября 2009

Я пишу программу, которая должна читать две строки, которые могут содержать разрывы строк и различные другие символы. Поэтому я использую EOF (Ctrl-Z или Ctrl-D) для завершения строки.

Это прекрасно работает с первой переменной, но со второй переменной, однако, это кажется проблематичным, поскольку очевидно, что что-то застряло во входном буфере, и пользователь ничего не набирает.

Я попытался очистить буфер с помощью while (getchar() != '\n'); и нескольких похожих вариантов, но, похоже, ничего не помогло. Все попытки очистки привели к бесконечному циклу, и без очистки добавление второй переменной невозможно.

Символы для обеих переменных читаются в цикле следующим образом: while((c = getchar()) != EOF), что предполагает, что это EOF, что я застрял в моем буфере. Или это как-то влияет на поведение программы? Что-то не так с используемой логикой?

Я начинаю чувствовать себя немного отчаянным после нескольких часов борьбы с этим.

[править: код добавлен ниже]

[edit 2: clearerr (), похоже, в конце концов заставляет работать это решение EOF.

Кажется, он работает в своем первоначальном виде, как я и предполагал в Linux, я вчера пробовал это с Windows.]

код:

#include <stdio.h>
#include <string.h>

int main(void)
{
    int x = 0;
    int c;
    char a[100];
    char b[100];

    printf("Enter a: ");
    while((c = getchar()) != EOF)
    {
        a[x] = c;
        x++;
    }
    a[x] = '\0';
    x = 0;

    /*while (getchar() != '\n'); - the non-working loop*/

    printf("\nEnter b: ");
    while((c = getchar()) != EOF)
    {
        b[x] = c;
        x++;
    }
    b[x] = '\0';

    printf("\n\nResults:\na: %s\n", a);
    printf("b: %s\n", b);

    return(0);
}

[править 3:]

Динамическая проблема с памятью:

Моя программа также должна обрабатывать строки длиной более 100 символов. Первоначально я намеревался решить эту проблему путем динамического выделения памяти, но когда у меня возникли проблемы с бесконечным циклом, описанным выше, и сбоями, связанными с памятью, я оставил его и переключился на char [100].

Я думаю, что я пытался, как правило, что-то вроде этого:

while((c = getchar()) != EOF)
{
  a = malloc(sizeof(char));
  a[x] = c;
  x++;
}

Это возможный (или разумный) способ сделать это? Я пытаюсь выделить больше памяти для каждого персонажа, который там обрабатывается. Индивидуально. С таким кодом (этот пример содержит, вероятно, синтаксические ошибки) у меня возникли сбои, поэтому мне кажется, что malloc может быть неправильной функцией, или я пытаюсь ошибиться. Предположим, что это даже возможно.

Ответы [ 7 ]

9 голосов
/ 26 октября 2009

После того как вы получили EOF от терминала, вы не получите никаких дополнительных данных . Невозможно отключить ввод - конец файла, ну, в конце концов.

Таким образом, вы должны определить, что каждая переменная вводится в отдельной строке, и чтобы пользователи нажимали ввод вместо EOF. Вам все еще нужно проверить, получили ли вы eof, потому что это означает, что пользователь действительно набрал EOF, и вы больше ничего не увидите - в этом случае вам нужно выйти из цикла и напечатать сообщение об ошибке.

2 голосов
/ 26 октября 2009

EOF не является символом - это специальное значение, которое возвращают входные функции, чтобы указать условие , что "конец файла" в этом входном потоке имеет были достигнуты Как говорит Мартин против Лёвиса, когда возникает условие «конец файла», это означает, что в этом потоке больше не будет входных данных.

Путаница возникает из-за:

  • Многие типы терминалов распознают специальное нажатие клавиши, чтобы сигнализировать «конец файла», когда «файл» является интерактивным терминалом (например, Ctrl-Z или Ctrl-D); и
  • Значение EOF является одним из значений, которые могут быть возвращены семейством функций getchar().

Вам потребуется использовать фактическое значение символа для разделения входных данных - нулевой символ ASCII '\0' может быть хорошим выбором, если он не может отображаться в качестве допустимого значения в самих входах.

1 голос
/ 26 октября 2009

Я запускаю код на моей Linux-коробке, вот результат:

Enter a: qwer
asdf<Ctrl-D><Ctrl-D>
Enter b: 123
456<Ctrl-D><Ctrl-D>

Results:
a: qwer
asdf
b: 123
456

Требовалось два нажатия Ctrl-D, поскольку входной буфер терминала не был пустым.

0 голосов
/ 26 октября 2009

Как вы вводите ноль в программе?

Вы можете реализовать функцию -print0, используя:

putchar(0);

Это выведет ноль символа ASCII '\ 0' в sdtout.

0 голосов
/ 26 октября 2009

Вместо остановки ввода чтения в EOF - , который не является символом - остановка в ENTER.

while((c = getchar()) != '\n')
{
    if (c == EOF) /* oops, something wrong, input terminated too soon! */;
    a[x] = c;
    x++;
}

EOF - это сигнал о прекращении входа. Вы почти гарантированы, что все вводимые пользователем данные заканчиваются на '\ n': это последний ключ, который пользователь вводит !!!


Редактировать: вы все еще можете использовать Ctrl-D и clearerr() для сброса входного потока.

#include <stdio.h>

int main(void) {
  char a[100], b[100];
  int c, k;

  printf("Enter a: "); fflush(stdout);
  k = 0;
  while ((k < 100) && ((c = getchar()) != EOF)) {
    a[k++] = c;
  }
  a[k] = 0;

  clearerr(stdin);

  printf("Enter b: "); fflush(stdout);
  k = 0;
  while ((k < 100) && ((c = getchar()) != EOF)) {
    b[k++] = c;
  }
  b[k] = 0;

  printf("a is [%s]; b is [%s]\n", a, b);
  return 0;
}
$ ./a.out
Enter a: two
lines (Ctrl+D right after the next ENTER)
Enter b: three
lines
now (ENTER + Ctrl+D)
a is [two
lines (Ctrl+D right after the next ENTER)
]; b is [three
lines
now (ENTER + Ctrl+D)
]
$
0 голосов
/ 26 октября 2009

Вы можете использовать нулевой символ ('\0') для разделения переменных. Различные инструменты UNIX (например, find) способны таким образом разделять свои выходные элементы, что предполагает, что это довольно стандартный метод.

Еще одним преимуществом этого является то, что вы можете прочитать поток в один буфер, а затем создать массив char* s для указания на отдельные строки, и каждая строка будет правильно '\0' -определена без необходимости изменить что-либо в буфере вручную. Это означает меньшие накладные расходы на выделение памяти, что может значительно ускорить выполнение вашей программы в зависимости от того, сколько переменных вы читаете. Конечно, это необходимо, только если вам нужно хранить все переменные в памяти одновременно & mdash; если вы имеете дело с ними по одному, вы не получите этого особого преимущества.

0 голосов
/ 26 октября 2009

То, что вы пытаетесь, принципиально невозможно с EOF.

Хотя в некоторых отношениях он ведет себя как единое целое, EOF - это не символ в потоке, а определенный макросом среды, представляющий end потока. Я не видел ваш код, но я понимаю, что вы делаете что-то вроде этого:

while ((c=getchar()) != EOF) {
    // do something
}
while ((c=getchar()) != EOF) {
    // do something else
}

Когда вы вводите символ EOF в первый раз, чтобы завершить первую строку, поток безвозвратно закрывается. То есть статус потока таков, что он закрыт.

Таким образом, содержимое второго цикла while никогда не запускается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...