Вопрос

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

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

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

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

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

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

[править 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 может быть здесь не той функцией, или я пытаюсь ее неправильно.Предположим, что это вообще возможно.

Это было полезно?

Решение

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

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

Другие советы

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

Путаница возникает потому, что:

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

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

Я запускаю код на своем компьютере с 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'), чтобы разделить переменные.Различные инструменты UNIX (например. find) способны разделять элементы вывода таким образом, что позволяет предположить, что это довольно стандартный метод.

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

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

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

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

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

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

Вместо того, чтобы прекращать чтение ввода в EOF - это не персонаж -- остановитесь на ENTER.

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

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


Редактировать:вы все еще можете использовать 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)
]
$

Как ввести null в программу?

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

putchar(0);

Это приведет к печати нулевого символа ASCII '\0' в sdtout.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top