Несколько нубских вопросов по Си ("The C programming Language" SE Brian W.Kernighan, Dennis M.Ri)

Модератор: Модераторы разделов

FlySnake
Сообщения: 992
ОС: openSUSE

Несколько нубских вопросов по Си

Сообщение FlySnake »

Всем привет.
Начинаю изучать Си по вышеупомянутой книге и возникают вопросы, на которые затрудняюсь найти ответы. Это моя первая книга вообще высокоуровневым языкам так что просьба сильно не бить :) Заранее спасибо
По 1-й главе пункт "1.5 Character Input and Output" описано как взять символ с клавиатуры, записать его в переменную типа интеджер и циклом проверять пока это не EOF - печатать его. И 2 примера кода. Вот второй более гуманоидный:

Код: Выделить всё

#include <stdio.h>
/* copy input to output; 2nd version */
main()
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
Вроде всё понятно. Но после компиляции получается что оно печатает всё что я набиваю на клаве, потом нажимаю Ctrl+D но оно не тут же прибивается, а сначала ещё раз скопирует всю сторку что было напечатано перед этим, а уже после второго раза прибьётся. Почему так происходит?
И ещё в этом же пункте 2 задания. С ними тоже есть непонятки:
QUOTE писал(а):Exercsise 1-6. Verify that the expression getchar() != EOF is 0 or 1.
Т.е. требуется проверить результат сравнения и вывести 0 либо 1 в зависимости от него? Т.е. требуется что-то вроде:

Код: Выделить всё

if getchar() != EOF
printf("1");
else
printf("0");
? Или как-то ещё вывести результат сравнения?
И наконец крайний вопрос
QUOTE писал(а):Exercise 1-7. Write a program to print the value of EOF.
Это действительно всего лишь putchar(EOF) ?
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Несколько нубских вопросов по Си

Сообщение eddy »

А зачем вы используете getchar? Это же буферизованный ввод-вывод.
Попробуйте в самом начале написать

Код: Выделить всё

setbuf(stdin, NULL);
setbuf(stdout, NULL);

или заменить функции буферизованного I/O на небуферизованные (read/write).

FlySnake писал(а):
13.07.2010 20:59
Это действительно всего лишь putchar(EOF) ?

EOF == -1, так что этим вы ничего не добьетесь, правильнее уж:

Код: Выделить всё

printf("EOF == %d\n", EOF);
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: Несколько нубских вопросов по Си

Сообщение watashiwa_daredeska »

eddy, не забивайте новичку голову всякой мутью раньше времени :)

FlySnake писал(а):
13.07.2010 20:59
а сначала ещё раз скопирует всю сторку что было напечатано перед этим, а уже после второго раза прибьётся. Почему так происходит?
Почему после второго раза? Или почему печатает строку еще раз?
Строку печатает потому, что первый раз печатает не Ваша программа, а сам терминал. Ибо по умолчанию включено «эхо» и построчный ввод. Т.е. терминал на самом деле отсылает программе не отдельные символы, а всю строку целиком, после того, как пользователь ее введет и нажмет <Enter> или Ctrl-D. Вот только после этого начинает работать Ваша программа и выводит строку второй раз. Почему программа выходит только после второго Ctrl-D, это надо подумать, так сразу не скажу.

FlySnake писал(а):
13.07.2010 20:59
Т.е. требуется проверить результат сравнения и вывести 0 либо 1 в зависимости от него?
Нет. Дело в том, что в C нет типа bool, в отличие от C++, и результат сравнения имеет тип int. 0=false, 1=true. На самом деле, true — это любое число, отличное от 0, но результат операции сравнения всегда 0 или 1. Вот это и надо проверить. Желательно при этом следить, что программа собирается именно компилятором C, а не C++.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Несколько нубских вопросов по Си

Сообщение eddy »

watashiwa_darede... писал(а):
13.07.2010 21:49
Дело в том, что в C нет типа bool

Я тоже так думал, пока меня не переубедили! Описывается этот тип в stdbool.h, является, по-видимому, unsigned char'ом с маленькой особенностью: bool принимает только два значения: 0 или 1 (что очень удобно, на мой взгляд).
А насчет "не забивать голову": разве в первой главе K&R было уже про буферизованный ввод/вывод?
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
IMB
Сообщения: 2567
ОС: Debian

Re: Несколько нубских вопросов по Си

Сообщение IMB »

eddy писал(а):
13.07.2010 21:55
Описывается этот тип в stdbool.h, является, по-видимому, unsigned char'ом с маленькой особенностью: bool принимает только два значения: 0 или 1

Насколько я помню, появляется только с C99. Так что не гаранитируется наличие.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Несколько нубских вопросов по Си

Сообщение eddy »

IMB писал(а):
13.07.2010 22:07
Насколько я помню, появляется только с C99.

Много чего только с С99 появляется, я уже на несколько функций напарывался: долго бился, пока не прочитал подробно ман.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Несколько нубских вопросов по Си

Сообщение NickLion »

eddy писал(а):
13.07.2010 21:55
watashiwa_darede... писал(а):
13.07.2010 21:49
Дело в том, что в C нет типа bool

Я тоже так думал, пока меня не переубедили! Описывается этот тип в stdbool.h, является, по-видимому, unsigned char'ом с маленькой особенностью: bool принимает только два значения: 0 или 1 (что очень удобно, на мой взгляд).
А насчет "не забивать голову": разве в первой главе K&R было уже про буферизованный ввод/вывод?

Тип зовётся _Bool и подключать ничего не надо. stdbool.h это только для макросов bool false true, вроде. А значения принимает тип, действительно только 0 и 1. Как это сказывается на производительности - сказать трудно.
Спасибо сказали:
FlySnake
Сообщения: 992
ОС: openSUSE

Re: Несколько нубских вопросов по Си

Сообщение FlySnake »

eddy писал(а):
13.07.2010 21:37
А зачем вы используете getchar? Это же буферизованный ввод-вывод.
Ну этим ещё голова засортся потом, а пока в книге так и написано: можете ничего не знать от вводе/выводе, но уже быдлокодить простейшие програмки используя getchar/putchar :)
eddy писал(а):
13.07.2010 21:37
EOF == -1, так что этим вы ничего не добьетесь, правильнее уж:
Спасибо, вроде понятно. %d говорит чтобы printf вывел целое число в десятичной системе. А putchar(EOF) получается выводит не -1, а пытается найти символ, соответствующий коду -1 (0xFF как я понимаю) поэтому и получается кракозябрина. Верно?
watashiwa_darede... писал(а):
13.07.2010 21:49
Нет. Дело в том, что в C нет типа bool, в отличие от C++, и результат сравнения имеет тип int. 0=false, 1=true. На самом деле, true — это любое число, отличное от 0, но результат операции сравнения всегда 0 или 1. Вот это и надо проверить. Желательно при этом следить, что программа собирается именно компилятором C, а не C++.
Т.е. ввести символ, сравнить с EOF, записать результат. Потом ввести EOF и так же записать результат сравнения. Так несколько раз. А в конечном счете проверить что все ранее записаные результаты были 0 или 1. Так получается?
А насчет компилятора я пишу gcc hello_world.c в книжке так и написано. Для C++ вроде g++
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: Несколько нубских вопросов по Си

Сообщение watashiwa_daredeska »

FlySnake писал(а):
13.07.2010 23:02
Т.е. ввести символ, сравнить с EOF, записать результат. Потом ввести EOF и так же записать результат сравнения. Так несколько раз. А в конечном счете проверить что все ранее записаные результаты были 0 или 1. Так получается?
Можно и не записывать ничего, а проверять сразу. Что-то вроде:

Код: Выделить всё

int result;
do {
  result = (getchar() != EOF);
  if (result == 0 || result == 1) {
    puts("Ok\n");
  } else {
    puts("Not 0 and not 1. Not what is expected!\n");
  }
} while(result);
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Несколько нубских вопросов по Си

Сообщение eddy »

watashiwa_darede... писал(а):
13.07.2010 23:24
} else {
puts("Not 0 and not 1. Not what is expected!\n");
}

И как вы думаете, какова вероятность, что выведется эта надпись? ;)
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Несколько нубских вопросов по Си

Сообщение NickLion »

eddy писал(а):
13.07.2010 23:30
watashiwa_darede... писал(а):
13.07.2010 23:24
} else {
puts("Not 0 and not 1. Not what is expected!\n");
}

И как вы думаете, какова вероятность, что выведется эта надпись? ;)

И тем не менее она отлична от 0! Битую память, подгоревшие процессоры, неправильный вольтаж ещё пока не отменили. Если, конечно, компилятор не уберёт ветку из кода, а это он может сделать - зависит от флагов оптимизаций.
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: Несколько нубских вопросов по Си

Сообщение watashiwa_daredeska »

eddy писал(а):
13.07.2010 23:30
И как вы думаете, какова вероятность, что выведется эта надпись?
Меня не интересует вероятность, меня интересует сформулированное задание. Задание: проверить, я и проверяю. Не выведется — и хорошо.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Несколько нубских вопросов по Си

Сообщение eddy »

watashiwa_darede... писал(а):
14.07.2010 00:58
Задание: проверить, я и проверяю. Не выведется — и хорошо.

Ну, по-моему, проще всего это задание решить было бы так:

Код: Выделить всё

int ch;
do
printf("(getchar != EOF) == %d\n", ch = (getchar() != EOF));
while(ch);
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: Несколько нубских вопросов по Си

Сообщение watashiwa_daredeska »

eddy писал(а):
14.07.2010 01:08
while(ch != EOF);
Можно и так, но:
1. Фигурные скобочки. Это не Python :)
2. Если всё работает, как надо, то в ch никогда не будет EOF ;)
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Несколько нубских вопросов по Си

Сообщение eddy »

watashiwa_daredeska писал(а):
14.07.2010 01:10
eddy писал(а):
14.07.2010 01:08
while(ch != EOF);
Можно и так, но:
1. Фигурные скобочки. Это не Python :)
2. Если всё работает, как надо, то в ch никогда не будет EOF ;)

1. При чем тут питон? Фигурные скобки нужны лишь если операторов больше одного или для группирования при создании временной переменной.
2. доказательство:

Код: Выделить всё

01:13 /dev/shm
cat 1.c
#include <stdio.h>
int ch;
int main(){
do
printf("(getchar != EOF) == %d\n", ch = (getchar() != EOF));
while(ch);
}
01:13 /dev/shm
gcc 1.c && ./a.out
a
(getchar != EOF) == 1
(getchar != EOF) == 1
s
(getchar != EOF) == 1
(getchar != EOF) == 1

(getchar != EOF) == 1
(getchar != EOF) == 1
(getchar != EOF) == 0

Как видите, после ctrl+D все сработало, как надо.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
ieleja
Сообщения: 307
ОС: Debian 9, macOS, Windows

Re: Несколько нубских вопросов по Си

Сообщение ieleja »

Ctrl-Z

?
ad infinitum
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Несколько нубских вопросов по Си

Сообщение NickLion »

ieleja писал(а):
14.07.2010 01:21
Ctrl-Z

?

Не путать с продуктами Microsoft. Ctrl-Z - это отправить задачу в фон. Если меня память не подводит.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: Несколько нубских вопросов по Си

Сообщение eddy »

NickLion писал(а):
14.07.2010 05:37
Ctrl-Z - это отправить задачу в фон. Если меня память не подводит.

Да, Ctrl+Z генерирует сигнал SIGTSTP.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
BratSinot
Сообщения: 812
ОС: Slackware64

Re: Несколько нубских вопросов по Си

Сообщение BratSinot »

eddy писал(а):
13.07.2010 21:55
watashiwa_darede... писал(а):
13.07.2010 21:49
Дело в том, что в C нет типа bool

Я тоже так думал, пока меня не переубедили! Описывается этот тип в stdbool.h, является, по-видимому, unsigned char'ом с маленькой особенностью: bool принимает только два значения: 0 или 1 (что очень удобно, на мой взгляд).
А насчет "не забивать голову": разве в первой главе K&R было уже про буферизованный ввод/вывод?

Там тупо 3 defin'а.

Код: Выделить всё

#define bool _Bool
#define true 1
#define false 0


В C99 появился булевый тип _Bool.

Код: Выделить всё

Как это сказывается на производительности - сказать трудно.

Во первых, занимает меньше памяти. Всего байт. Может когда-нибудь можно будет и по битам занимать =) Ну плюс в битовом поле можно пачку _Bool использовать по битам.
Во вторых, теоретически с ним работать быстрее, но опять-же зависит от ОСи и компилятора. Но все равно, не нужно гвоздями молоток забивать, есть булевый тип? Так его и нужно использовать для булевых значений.
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Несколько нубских вопросов по Си

Сообщение NickLion »

BratSinot писал(а):
15.07.2010 15:18
Во вторых, теоретически с ним работать быстрее, но опять-же зависит от ОСи и компилятора. Но все равно, не нужно гвоздями молоток забивать, есть булевый тип? Так его и нужно использовать для булевых значений.

Я о том, что операции над этим типом должны контролировать выход за пределы типа. А значит потенциально - медленнее.
Спасибо сказали:
FlySnake
Сообщения: 992
ОС: openSUSE

Re: Несколько нубских вопросов по Си

Сообщение FlySnake »

Если не возражаете ещё один вопрос, даже 2
QUOTE писал(а):Exercise 1-10. Write a program to copy its input to its output, replacing each tab by \t, each
backspace by \b, and each backslash by \\. This makes tabs and backspaces visible in an
unambiguous way.
Просят поменять табуляцию, бэкслеш и бэкспейс на соответствующие символы. Но как можно отобразить бэкспейс? 0_о
Я сделал так:

Код: Выделить всё

#include <stdio.h>
main()
{
  int c;
  while ((c = getchar()) != EOF) {
    if (c == '\t')
      printf("\\t");
    if (c == '\b')
      printf("\\b");
    if (c == '\\')
      printf("\\\\");
  putchar(c);
  }
}
Вроде работает, но как оно с точки зрения быдлокода?
Нашел сайт с решениями к заданиям из этой книги http://www.trunix.org/programlama/c/kandr2/krx110.html см. первый вариант.
Суть вроде та же, но зачем там для хранения всего лишь 2-х состояний (аки флаг наличия символа) используется целый интеджер? Хотя short использовать в отсутствии булева типа. Или в подобном расточительстве памяти есть смысл?
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5405
ОС: Gentoo

Re: Несколько нубских вопросов по Си

Сообщение /dev/random »

FlySnake писал(а):
24.07.2010 16:14
Или в подобном расточительстве памяти есть смысл?

Вы считаете одиночную переменную в нерекурсивной функции расточительством? Да будь она хоть 10kB размером, стеку пофиг.
Спасибо сказали:
Аватара пользователя
deadhead
Сообщения: 1913
Статус: zzz..z

Re: Несколько нубских вопросов по Си

Сообщение deadhead »

/dev/random писал(а):
24.07.2010 20:13
Да будь она хоть 10kB размером, стеку пофиг.
если он (стек) не урезан до меньшего размера :-)
[x] close
Спасибо сказали:
FlySnake
Сообщения: 992
ОС: openSUSE

Re: Несколько нубских вопросов по Си

Сообщение FlySnake »

/dev/random писал(а):
24.07.2010 20:13
FlySnake писал(а):
24.07.2010 16:14
Или в подобном расточительстве памяти есть смысл?

Вы считаете одиночную переменную в нерекурсивной функции расточительством? Да будь она хоть 10kB размером, стеку пофиг.
Ну так одна тут, другая там, третью по привычке в рекурсивной функции сделал и тд как снежный ком лишние байты потекли. Реально тут пофиг? Я просто немного микроконтроллеры програмирую на ассеблере, а там каждый байт посчитан
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5405
ОС: Gentoo

Re: Несколько нубских вопросов по Си

Сообщение /dev/random »

FlySnake писал(а):
24.07.2010 22:59
Реально тут пофиг?

Если вы не собираетесь запускать эту программу в системе с микроскопическим стеком, то абсолютно пофиг. Главное - не делать такого в крупных массивах и в динамической памяти.
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: Несколько нубских вопросов по Си

Сообщение watashiwa_daredeska »

FlySnake писал(а):
24.07.2010 16:14
Вроде работает, но как оно с точки зрения быдлокода?
s/printf/puts/g
Спасибо сказали:
FlySnake
Сообщения: 992
ОС: openSUSE

Re: Несколько нубских вопросов по Си

Сообщение FlySnake »

Вы об этом? Про эту функцию будет в главе посвещённой I/O, а пока предлагается только printf, getchar и putchar
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: Несколько нубских вопросов по Си

Сообщение watashiwa_daredeska »

FlySnake писал(а):
26.07.2010 20:10
Вы об этом?
Да.

FlySnake писал(а):
26.07.2010 20:10
Про эту функцию будет в главе посвещённой I/O, а пока предлагается только printf, getchar и putchar
А, ну тогда ладно :)
Спасибо сказали: