Подтвердить что ты не робот

Я пытаюсь понять getchar()!= EOF

Я читаю язык программирования C и все понял до сих пор. Однако, когда я наткнулся на getchar() и putchar(), я не понял, что их использует, и, более конкретно, что делает следующий код.

main()
{
    int c;
    while ((c = getchar()) != EOF)
       putchar(c);
}

Я понимаю функцию main(), объявление целых чисел c и цикла while. Тем не менее я смущен состоянием внутри цикла while. Каков вход в этот код C и какой результат.

Извините, если это основной и глупый вопрос, но я просто ищу простое объяснение, прежде чем двигаться дальше в книге и запутаться.

4b9b3361

Ответ 1

Этот код можно записать более четко:

main()
{
    int c;
    while (1) {
        c = getchar();            // Get one character from the input
        if (c == EOF) { break; }  // Exit the loop if we receive EOF ("end of file")
        putchar(c);               // Put the character to the output
    }
}

Символ EOF принимается, когда больше нет ввода. Имя имеет смысл в том случае, когда ввод считывается из реального файла, а не для ввода пользователем (что является частным случаем файла).


[В стороне, как правило, функция main должна быть записана как int main(void).]

Ответ 2

getchar() - это функция, которая считывает символ из стандартного ввода. EOF - это специальный символ, используемый в C, чтобы указать, что достигнут КОНЕЦ ФАЙЛА.

Обычно вы получите символ EOF, возвращающийся из getchar(), когда ваш стандартный ввод отличается от консоли (т.е. файла).

Если вы запустите свою программу в unix следующим образом:

$ cat somefile | ./your_program

Затем ваш getchar() вернет каждый символ в somefile и EOF, как только закончится somefile.

Если вы запустите свою программу следующим образом:

$ ./your_program

И отправьте EOF через консоль (нажав CTRL+D в Unix или CTRL + Z в Windows), тогда getchar() также вернет EOF, и выполнение закончится.

Ответ 3

Может быть, вы запутались в том, что ввод -1 в командной строке не заканчивается вашей программой? Поскольку getchar() читает это как два символа, - и 1. В присваивании c символ преобразуется в числовое значение ASCII. Это числовое значение сохраняется в некоторой ячейке памяти, доступ к которой осуществляется с помощью c.

Затем putchar(c) извлекает это значение, просматривает таблицу ASCII и преобразует обратно в символ, который печатается.

Я думаю, что найти значение -1 десятичного числа в таблице ASCII невозможно, потому что таблица начинается с 0. Таким образом, getchar() должен учитывать различные решения на разных платформах. может быть, есть версия getchar() для каждой платформы?

Мне просто кажется странным, что этот EOF не находится в обычном ascii. Это мог быть один из первых символов, которые нельзя распечатать. Например, End-of-line находится в ASCII.

Что произойдет, если вы перенесите свой файл из окон в linux? Будет ли автоматически обновляться символ файла EOF?

Ответ 4

Код, написанный с текущими стандартами C, должен быть

#include <stdio.h>

int main(void)
{
    int c;
    while ((c = getchar()) != EOF)
       putchar(c);
}

Цикл можно переписать как

int c;
while (1) {
    c = getchar();
    if (c != EOF)
        putchar(c);
    else
        break;
}

это читается как

  • повторять навсегда
    • введите следующий символ ( "байт" ) ввода из стандартного ввода и сохраните его в c
    • если при чтении указанного символа не произошло исключительного условия
      • затем выведите символ, сохраненный в c, в стандартный вывод
    • еще
      • разрыв цикла

Многие языки программирования обрабатывают исключительные условия путем создания исключений, которые нарушают нормальный поток программы. C не делает этого. Вместо этого функции, которые могут выйти из строя, имеют возвращаемое значение, и любые исключительные условия сигнализируются специальным возвращаемым значением, которое необходимо проверить из документации данной функции. В случае getchar в документации по стандарту C11 говорится (C11 7.21.7.6p3):

  1. Функция getchar возвращает следующий символ из входного потока, на который указывает stdin. Если поток находится в конце файла, индикатор конца файла для потока установлен и getchar возвращает EOF. Если возникает ошибка чтения, отображается индикатор ошибки для потока, а getchar возвращает EOF.

В другом месте указано, что EOF является целочисленной константой, 0, и любое обычное возвращаемое значение >= 0 - unsigned char с нулевым продолжением до int.

Поток, находящийся в конце файла, означает, что весь вход был потреблен. Для стандартного ввода это можно вызвать с клавиатуры, набрав Ctrl + D на терминалах Unix/Linux и Ctrl + Z в окнах консоли Windows. Другая возможность заключалась бы в том, чтобы программа получала входные данные из файла или канала, а не из клавиатуры, - тогда конец файла будет сигнализироваться всякий раз, когда этот вход полностью потребляется, т.е.

cat file | ./myprogram

или

./myprogram < file

Как сказано выше, существуют фактически два разных условия, которые могут привести к возврату getchar EOF: либо был достигнут конец файла, либо произошла фактическая ошибка. Это не может быть выведено только из возвращаемого значения. Вместо этого вы должны использовать функции feof и ferror. feof(stdin) вернет истинное значение, если на стандартном входе достигнут конец файла. ferror(stdin) вернет true, если произошла ошибка.

Если произошла фактическая ошибка, переменная errno, определенная <errno.h>, будет содержать код ошибки; функция perror может использоваться для автоматического отображения сообщения с возможностью чтения человеком с префиксом. Таким образом, мы могли бы расширить пример до

#include <stdio.h>
#include <errno.h> // for the definition of errno
#include <stdlib.h> // for exit()
int main(void)
{
    int c;
    while ((c = getchar()) != EOF)
       putchar(c);

    if (feof(stdin)) {
        printf("end-of-file reached\n");
        exit(0);
    }
    else if (ferror(stdin)) {
        printf("An error occurred. errno set to %d\n", errno);
        perror("Human readable explanation");
        exit(1);
    }
    else {
        printf("This should never happen...\n");
        exit('?');
    }
}

Чтобы запустить конец файла, можно использовать Ctrl + D (здесь отображается как ^D) в новой строке в Linux:

% ./a.out
Hello world
Hello world
^D
end-of-file reached

(обратите внимание, как вход здесь буферизируется по строке, поэтому вход не чередуется в строке с выходом).

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

% echo Hello world | ./a.out
Hello world
end-of-file reached

Чтобы вызвать ошибку, это немного сложнее. В оболочках bash и zsh стандартный ввод может быть закрыт, чтобы он не происходил нигде, добавив <&- в командную строку:

% ./a.out <&-
An error occurred. errno set to 9
Human readable explanation: Bad file descriptor

Дескриптор Bad файла или EBADF означает, что стандартный дескриптор ввода-кода 0 был недопустимым, так как он вообще не был открыт.

Другим интересным способом генерации ошибки будет чтение стандартного ввода из каталога - это приводит к тому, что errno устанавливается на EISDIR в Linux:

% ./a.out < / 
An error occurred. errno set to 21
Human readable explanation: Is a directory

Собственно, нужно также проверить возвращаемое значение putchar - это также возвращает EOF при ошибке или символ, написанный:

while ((c = getchar()) != EOF) {
    if (putchar(c) == EOF) {
        perror("putchar failed");
        exit(1);
    }
}

И теперь мы можем протестировать это, перенаправив стандартный вывод на /dev/full - однако есть gotcha - поскольку стандартный вывод буферизирован, нам нужно написать достаточно, чтобы заставить буфер сбрасываться сразу, а не в конце программа. Мы получаем бесконечные нулевые байты из /dev/zero:

 % ./a.out < /dev/zero > /dev/full
 putchar failed: No space left on device

P.S. очень важно всегда использовать переменную типа int для хранения возвращаемого значения getchar(). Несмотря на то, что он читает символ, с использованием signed/unsigned/plain char всегда ошибочно.

Ответ 5

Функция getchar() считывает символ с клавиатуры (т.е. stdin)

В условии внутри заданного цикла while перед каждой итерацией вызывается getchar(), а принятое значение присваивается целому числу c.

Теперь нужно понимать, что в C стандартный ввод (stdin) является как файл. т.е. вход буферизуется. Вход останется в буфере, пока он фактически не будет потреблен. stdin - фактически стандартный поток ввода.

getchar() возвращает следующее доступное значение во входном буфере.

Программа по существу отображает все, что было прочитано с клавиатуры; включая пробел, например \n (новая строка), пробел и т.д.

т.е. вход - это вход, который пользователь предоставляет с помощью клавиатуры (stdin обычно означает клавиатуру). И вывод - это то, что мы предоставляем в качестве входных данных.

Ввод, который мы предоставляем, считывается символом по символу и обрабатывается как символы, даже если мы даем их как числа.

getchar() вернет EOF только в том случае, если достигнут конец файла. "Файл, который нам касается здесь, это сам stdin (стандартный ввод).

Представьте себе файл, в котором хранится ввод, который мы предоставляем с помощью клавиатуры. Thats stdin. Этот файл похож на бесконечный файл. Поэтому no EOF.

Если мы предоставляем больше входных данных, чем getchar() может обрабатывать одновременно (прежде чем давать его как ввод, нажав клавишу ввода), дополнительные значения будут по-прежнему сохраняться в неиспользуемом входном буфере. getchar() будет читать первый символ из ввода, сохранить его в c and print c with putchar (c) `.

Во время следующей итерации цикла while дополнительные символы, указанные во время предыдущей итерации, которые все еще находятся в stdin, принимаются во время while ((c = getchar()) != EOF) с помощью части c=getchar(). Теперь этот же процесс повторяется до тех пор, пока в входном буфере ничего не останется.

Это заставляет его выглядеть так, как будто putchar() возвращает строку вместо одного символа за раз, если в течение итерации вводится более одного символа.

Например: если вход был abcdefghijkl
выход был бы тем же
abcdefghijkl

Если вы не хотите этого поведения, вы можете добавить fflush (stdin); сразу после putchar(c);. Это заставит цикл печатать только первый символ на входе, предоставляемом во время каждой итерации.

Например: если вход был adgbad
будет напечатан только a.

Вход отправляется на stdin только после нажатия клавиши ввода.

putchar() является противоположностью getchar(). Он записывает вывод в стандартный выходной поток (stdout, обычно монитор).

EOF не является символом, присутствующим в файле. Его что-то возвращает функция как код ошибки.

Вероятно, вы, вероятно, не сможете выйти из цикла give while. Входной буфер будет опустошен (для отображения на выходе), как только что-то попадет в него с клавиатуры, а stdin не даст EOF.

Для ручного выхода из цикла, EOF можно отправить с помощью клавиатуры, нажав ctrl + D в Linux и
ctrl + Z в Windows

например:

while ((c = getchar()) != EOF)
{

   putchar(c);
   fflush(stdin);
}
printf("\nGot past!");

Если вы нажмете комбинацию клавиш, чтобы дать EOF, перед выходом из программы появится сообщение Got past!.

Если stdin уже not уже пуст, вам придется дважды нажать эту комбинацию клавиш. Как только очистите этот буфер, а затем, чтобы имитировать EOF.

EDIT: дополнительная пара скобок вокруг c = getchar() в while ((c = getchar()) != EOF) заключается в том, чтобы удостовериться, что значение, возвращаемое getchar(), сначала присваивается c до , что значение сравнивается с EOF.

Если этой дополнительной круглой скобки не было, выражение могло бы быть while (c = (getchar() != EOF) ), что означало бы, что c может иметь одно из двух значений: 1 (для true) или 0 (для false), который, очевидно, не является тем, что предполагается.

Ответ 6

Аналогично | pipe выше вы можете использовать перенаправление в своей системе, чтобы использовать вышеприведенный код, чтобы отображать все содержимое символа файла, пока он не достигнет конца (EOF), представленного CTRL-Z или CTRL-D обычно.

В консоли: ProgramName < FileName1.txt

И чтобы создать копию того, что читается из FileName1, вы можете: ProgramName < FileName1.txt > CopyOfInput.txt

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

-Удача, которая помогает.

Ответ 7

main(){
int c;
while ((c = getchar()) != EOF)
   putchar(c);
}

На самом деле с = GetChar() предоставляет символ, который пользователь вводит на консоли, и это значение проверяется с EOF, которая представляет конец файла. EOF встречается в конце файла. (С = GetChar())!= EOF эквивалентно с!= EOF. Теперь я думаю, что это намного проще. Если вам нужен дальнейший запрос, дайте мне знать.

Ответ 8

 getchar()

получает символ от ввода.

 c = getchar()

Значение этого присваивания - это значение левой стороны после присвоения или значение прочитанного символа. Значение EOF по умолчанию -1.

 ((c = getchar()) != EOF)

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

Дополнительные скобки вокруг c = getchar() предназначены для компилятора, чтобы подчеркнуть, что мы действительно хотели выполнить назначение внутри условия, потому что обычно предполагается, что вы хотите набрать == и предупредить вас.

 main() {
     int c;
     while ((c = getchar()) != EOF)
         putchar(c);
 }

Таким образом, весь код на самом деле перекликается с тем, что вы вводите. Он присваивает значение символов c внутри условия, а затем выводит его обратно в тело цикла, заканчивая только тогда, когда обнаружен конец файла.