Язык программирования K&R C 1.5.1 (копирование файлов)

Что ж, несколько месяцев назад я прочитал еще одну «хорошо известную» книгу C (на моем языке), и я так ничего и не узнал об этом. То, как K&R пишет 3 главы на 20 страницах, просто потрясающе, и, конечно, я не могу ожидать огромных объяснений, но это также вызывает вопросы.

У меня есть вопрос по этому пункту 1.5.1 В книге говорится (стр. 16):

main(){
  int c;// <-- Here is the question
  c=getchar();
  while (c != EOF){
    putchar(c);
    c = getchar();
  }
}

[...] Тип char специально предназначен для хранения таких символьных данных, но можно использовать любой целочисленный тип. Мы использовали int по тонкой, но важной причине. Проблема заключается в том, чтобы отличить конец ввода от действительных данных. Решение состоит в том, что getchar возвращает отличительное значение, когда больше нет ввода, значение, которое нельзя связать с каким-либо реальным символом. Это значение называется EOF, что означает «конец файла». Мы должны объявить c достаточно большим типом, чтобы хранить любое значение, которое возвращает getchar. Мы не можем использовать char, так как c должен быть достаточно большим, чтобы содержать EOF в дополнение к любому возможному char. Поэтому мы используем int.[...]

После поиска в Google другого объяснения:

EOF — это специальный макрос, представляющий конец файла (Linux: используйте CTRL+d на клавиатуре, чтобы создать его, команда Windows: используйте CTRL+z (может быть, в начале новой строки с последующим RETURN)): часто EOF = -1, но зависит от реализации. Должно быть значение, которое не является допустимым значением для любого возможного символа. По этой причине c имеет тип int (а не char, как можно было бы ожидать).

Итак, я изменил исходный код с int на char, чтобы увидеть, в чем проблема, с получением значений EOF... но проблем нет. Работает так же.

Я также не понял, как getchar берет каждый символ, который я пишу, и печатает все. Тип Int имеет длину 4 байта, поэтому он может содержать 4 символа внутри переменной. Но я могу поставить любое количество символов, он будет читать и писать все одинаково. И с char происходит то же самое... Что происходит на самом деле? Где хранятся значения, когда символов больше 1-4?


person SOMN    schedule 24.08.2012    source источник


Ответы (3)


Итак, я изменил исходный код с int на char, чтобы увидеть, в чем проблема, с получением значений EOF... но проблем нет. Работает так же

Я случайно работаю так же. Все зависит от реального типа char, т. е. знакового или беззнакового. На эту тему также есть часто задаваемые вопросы по C. У вас больше шансов увидеть ошибку, если ваши char не подписаны.

Однако ошибка может оставаться незамеченной в течение длительного времени, если символы подписаны и если ввод состоит только из 7-битных символов.

РЕДАКТИРОВАТЬ

Последний вопрос: тип char имеет длину один байт, а длина int — 4 байта. Итак, char будет принимать только один символ ascii. Но если я наберу «переполнение стека превышает 1 байт», вывод будет «переполнение стека превышает 1 байт». Где хранится «переполнение tack длиной более 1 байта» и как putchar помещает всю строку

Каждый символ будет сохранен c по очереди. Итак, в первый раз getchar() вернет s, а putchar отправит его в путь. Затем придет t и так далее. Ни в коем случае c не будет хранить более одного символа. Таким образом, хотя вы передаете ему большую строку, он справляется с ней, поедая по одному символу за раз.

person cnicutar    schedule 24.08.2012
comment
Последний вопрос: тип char имеет длину один байт, а длина int — 4 байта. Итак, char будет принимать только один символ ascii. Но если я наберу переполнение стека длиной более 1 байта, на выходе будет переполнение стека длиной более 1 байта. Где хранится переполнение tack длиной более 1 байта, и как работает putchar, помещает целую строку. Извините, если это нубский вопрос. - person SOMN; 24.08.2012
comment
О, это был немного глупый вопрос. Я почти забыл, как работают циклы. :Р Спасибо. - person SOMN; 24.08.2012
comment
Если char без знака, ошибка редко пропускается, это приводит к бесконечному циклу. Когда char подписан, его можно долго не замечать; если программа используется только в локали, где -1 не назначено (говорит UTF-8), это может быть так навсегда. - person AProgrammer; 24.08.2012

Разделение на два ответа:

Почему int, а не char

Короткий и формальный ответ: если вы хотите иметь возможность представлять все реальные символы и еще один ненастоящий символ (EOF), вы не можете использовать тип данных, предназначенный для хранения только реальных символов.

Ответ понятен, но не совсем точен: функция getchar() возвращает код ASCII прочитанного символа, или EOF.

Поскольку -1, преобразованное в char, равно 255, мы не можем отличить 255-символьный символ от EOF. То есть,

char a = 255;
char b = EOF;
a == b // Evaluates to TRUE

но,

int a = 255;
int b = EOF;
a == b // Evaluates to FALSE

Таким образом, использование char не позволит вам различить символ, чей код ASCII равен 255 (что может произойти при чтении из файла), и EOF.

Почему вы можете использовать putchar() с целым числом?

Функция putchar() просматривает свой параметр, видит число, обращается к таблице ASCII и рисует глиф, который видит. Когда вы передаете ему int, оно неявно приводится к char. Если число в int подходит к char, все в порядке, и никто ничего не замечает.

person user1071136    schedule 24.08.2012

Если вы используете char для хранения результата getchar(), есть две потенциальные проблемы, с которыми вы столкнетесь, зависит от подписи char.

  • если char не имеет знака, c == EOF никогда не будет истинным, и вы получите бесконечный цикл.

  • если char подписано, c == EOF будет истинным при вводе некоторого символа. Что будет зависеть от используемой кодировки; в локали с использованием ISO8859-1 или CP852 это «ÿ», если EOF равен -1 (наиболее распространенное значение). Некоторые кодировки, например UTF-8, не используют значение (char)EOF в допустимых кодах, но вы редко можете гарантировать, что ваша проблема останется при реализации подписанного символа и будет использоваться только в непроблемных локалях.

person AProgrammer    schedule 24.08.2012