Из stdin. Он там остался после того, как были считаны два int. То, что программа что-то вывела в stdout, никоим образом на это не влияет. Это только Вы видите всё перемешанным в терминале.QWERTYASDF писала: ↑30.08.2018 15:42Однако не понятно, откуда (в моем примере) берется символ перевода строки в переменной s. Если, например, верхнюю строчку с printf убрать, то результат такой-же - что-то выбрать не предлагается. Т.е. каким-то образом, насколько понимаю, в процессе запроса значения для s, вводится перевод строки? Но откуда и как?...
Начинаю осваивать C, появляются вопросы...
Модератор: Модераторы разделов
- Bizdelnick
- Модератор
- Сообщения: 20793
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
Спасибо сказали:
Re: Начинаю осваивать C, появляются вопросы...
Там пробел.
Пусть входная строка такова: 1 2 +[Enter] -- в потоке ввода это "1 2 +\n", -- где \n -- это один символ с кодом 10.
2 примера.
Пример неправильный:
Пример правильный:
Пусть входная строка такова: 1 2 +[Enter] -- в потоке ввода это "1 2 +\n", -- где \n -- это один символ с кодом 10.
2 примера.
Пример неправильный:
Код: Выделить всё
#include <stdio.h>
int main(void)
{
int a, b;
scanf("%d %d", &a, &b); // прочитано 1, пропущен(ы) пробел(ы), прочитано 2
scanf("%c", &op); // прочитан пробел после 2
printf("%d\n", op); // 32 -- код пробела
return 0;
}
Код: Выделить всё
#include <stdio.h>
int main(void)
{
int a, b;
scanf("%d %d", &a, &b); // прочитано 1, пропущен(ы) пробел(ы), прочитано 2
scanf(" %c", &op); // пропушен(ы) пробел(ы), прочитан '+'
printf("%d\n", op); // 43 -- код '+'
return 0;
}
Спасибо сказали:
Re: Начинаю осваивать C, появляются вопросы...
Вот такое:Bizdelnick писал: ↑30.08.2018 15:50Вы взорвали мой мозг. Какое преобразование массива в указатель, если «массив» в C и есть указатель?
Код: Выделить всё
int *a, b[10];
printf("%ld is not equal %ld: so b is NOT pointer", sizeof a, sizeof b);
Код: Выделить всё
8 is not equal 40: so b is NOT pointer
Re: Начинаю осваивать C, появляются вопросы...
Это говорит стандарт в пункте 6.3 Conversions. Это если мы про Си говорим.Bizdelnick писал: ↑30.08.2018 15:50И Вы что, хотите сказать, что char преобразуется в int всегда и везде, даже на 8-битной архитектуре с 16-битным int?
If an int can represent all values of the original type (as restricted by the width, for a bit-field), the
value is converted to an int; otherwise, it is converted to an unsigned int. These are called the
integer promotions.58) All other types are unchanged by the integer promotions.
--------
58)The integer promotions are applied only: as part of the usual arithmetic conversions, to certain argument expressions, to
the operands of the unary+,- , and ~ operators, and to both operands of the shift operators, as specified by their respective
subclauses.
Последний раз редактировалось bormant 30.08.2018 16:17, всего редактировалось 1 раз.
- Bizdelnick
- Модератор
- Сообщения: 20793
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
bormant, sizeof array — это костыль, работающий только для статических массивов. Его существование не означает, что выполняется какое-то преобразование типов, оно означает только то, что размер статического массива известен компилятору, и он предоставляет возможность получить его (причём во время компиляции, а не во время выполнения).
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
Re: Начинаю осваивать C, появляются вопросы...
Стандарт несколько иного мнения на этот счет, 6.3.2.1:
Видите, "...выражение, имеющее тип "массив объектов типа", преобразуется в выражение, имеющее тип "указатель на тип", указывающее на первый объект массива и не являющееся lvalue."Except when it is the operand of the sizeof operator, or the unary & operator, or is a string literal
used to initialize an array, an expression that has type “array of type” is converted to an expression
with type “pointer to type” that points to the initial element of the array object and is not an lvalue.
If the array object has register storage class, the behavior is undefined.
- Bizdelnick
- Модератор
- Сообщения: 20793
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
Не тот кусок цитируете. Надо 6.5.2.2 Function calls:
If the function is defined with a type that includes a prototype, and either the prototype ends with an ellipsis ( , ... ) or the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
Re: Начинаю осваивать C, появляются вопросы...
давайте посмотрим на нестатический массив, вот VLA:
Код: Выделить всё
#include <stdio.h>
int main(void)
{
int n;
scanf(" %d", &n);
int a[n];
printf("n = %d; size of a is %ld\n", n, sizeof a);
return 0;
}
Код: Выделить всё
n = 10; size of a is 40
- Bizdelnick
- Модератор
- Сообщения: 20793
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
Ну ок, вопрос терминологии. Важнее то, что в рантайме никаких отличий между массивом и указателем нет (а между char и int — есть). Приравнивать «преобразование», выполняемое компилятором, к преобразованию, выполняемому в рантайме, как минимум странно.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
Re: Начинаю осваивать C, появляются вопросы...
Тут играем, тут не играем, тут рыбу заворачивали... (q)Bizdelnick писал: ↑30.08.2018 16:30Не тот кусок цитируете. Надо 6.5.2.2 Function calls:If the function is defined with a type that includes a prototype, and either the prototype ends with an ellipsis ( , ... ) or the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined.
Внимательнее, the types of the arguments after promotion are not compatible with the types of the parameters. То есть, сперва сработает integer promotion для argument (char в int), только потом будет проверка, совместимы ли с типом параметров, а если не совместимы, то поведение не определено.
Я правильно прочитал?
Re: Начинаю осваивать C, появляются вопросы...
Между char и int есть, но при передаче на месте ... в списке параметров функции выполняется default argument promotion, про который вы почему-то не стали цитировать, хотя про него в том же самом абзаце предложением раньше (там где про без прототипа), то есть выполняются promotion в integer и promotion из float в double.Bizdelnick писал: ↑30.08.2018 16:34в рантайме никаких отличий между массивом и указателем нет (а между char и int — есть)
Поскольку прототип у printf() примерно такой:
int printf( const char *format, ... );
то передать этой функции во втором и далее параметре что-либо короче int и double язык Си не умеет.
Даже в худшем случае (-O0 -- без оптимизаций) https://godbolt.org/z/cQZEgp будет
movzx ax,byte ptr [переменная_unsigned_char] ; вот оно, преобразование unsigned char -> unsigned int
или
movx ax,byte ptr [переменная_signed_char] ; вот оно, преобразование signed char -> signed int
тот самый default argument promotion, а именно здесь -- integer argument promotion -- перед передачей параметров в printf(fmt, ...).
Вот именно поэтому для следующего стандарту языка компилятора совершенно правильно:
char ch; /* ... */ printf("%d\n", ch);
и абсолютно не нужно явное преобразование переменной типа char к int или unsigned int:
char ch; /* ... */ printf("%d\n", (int)ch);
;-)
- Bizdelnick
- Модератор
- Сообщения: 20793
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
bormant
Так и быть, сдаюсь, убедили. ☺
Так и быть, сдаюсь, убедили. ☺
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
-
- Сообщения: 989
- Статус: Чайник со свистком
- ОС: GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
Что-то я все-таки не понимаю механику происходящего. Был один ввод, потом другой. Почему из предыдущего ввода в следующий пробивается пробел или перевод строки?,..
Я сейчас представляю поток ввода, как некую виртуальную трубу, которая может накапливать вводимые символы. Насколько понимаю, пробел и перевод строки - это часть, так скажать, одной итерации ввода в какой-нибудь процесс. Почему перевод строки переносится на другую - мне не понятно...
Я сейчас представляю поток ввода, как некую виртуальную трубу, которая может накапливать вводимые символы. Насколько понимаю, пробел и перевод строки - это часть, так скажать, одной итерации ввода в какой-нибудь процесс. Почему перевод строки переносится на другую - мне не понятно...
-
- Сообщения: 989
- Статус: Чайник со свистком
- ОС: GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
Где пробел? В моем примере, если использовать Ваш совет определения значения переменной, то мне printf кажет "10" т.е. перевод строки.bormant писал(а): ↑30.08.2018 15:56Там пробел.
Пусть входная строка такова: 1 2 +[Enter] -- в потоке ввода это "1 2 +\n", -- где \n -- это один символ с кодом 10.
2 примера.
Пример неправильный:Пример правильный:Код: Выделить всё
#include <stdio.h> int main(void) { int a, b; scanf("%d %d", &a, &b); // прочитано 1, пропущен(ы) пробел(ы), прочитано 2 scanf("%c", &op); // прочитан пробел после 2 printf("%d\n", op); // 32 -- код пробела return 0; }
Код: Выделить всё
#include <stdio.h> int main(void) { int a, b; scanf("%d %d", &a, &b); // прочитано 1, пропущен(ы) пробел(ы), прочитано 2 scanf(" %c", &op); // пропушен(ы) пробел(ы), прочитан '+' printf("%d\n", op); // 43 -- код '+' return 0; }
А почему не перевод строки, он же последним стоит?прочитан пробел после 2
Чет ничего не понимаю...
Спасибо, теперь кажись понимаю : )
Последний раз редактировалось QWERTYASDF 30.08.2018 20:09, всего редактировалось 2 раза.
- Bizdelnick
- Модератор
- Сообщения: 20793
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
Всё правильно, это труба. Вы слили из неё нечто, соответствующее формату, а потом закрыли кран. Кусок, не соответствующий формату, остался в трубе. Открыли кран снова — и получили этот кусок.QWERTYASDF писала: ↑30.08.2018 19:02Я сейчас представляю поток ввода, как некую виртуальную трубу, которая может накапливать вводимые символы. Насколько понимаю, пробел и перевод строки - это часть, так скажать, одной итерации ввода в какой-нибудь процесс. Почему перевод строки переносится на другую - мне не понятно...
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
Спасибо сказали:
-
- Сообщения: 989
- Статус: Чайник со свистком
- ОС: GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
Хмм...Нуу...Это неожиданно, но вроде бы вопрос решен, мне более или менее ясно.
А что вместо "крамольной" scanf народ использует? Странно, почему в столь многих учебниках именно эту функцию приводят в роли ввода, и ничего не говорят об ее крамольности...
А что вместо "крамольной" scanf народ использует? Странно, почему в столь многих учебниках именно эту функцию приводят в роли ввода, и ничего не говорят об ее крамольности...
Спасибо сказали:
Re: Начинаю осваивать C, появляются вопросы...
Ну, опять? Массив в C не то же самое, что и указатель. Да, они прозрачно (пока) друг в друга преобразуются. Но это все-таки разное.
Re: Начинаю осваивать C, появляются вопросы...
Крамольного там реакция на некорректные данные. Там же некорректный символ возвращается обратно и следующий scanf и вообще любое чтение с stdio его опять прочтет. Ну да, можно проанализировать возвращаемое значение, только если оно не соответствует ожидаемому, то что делать дальше совсем нкпонятно.QWERTYASDF писала: ↑30.08.2018 19:37Хмм...Нуу...Это неожиданно, но вроде бы вопрос решен, мне более или менее ясно.
А что вместо "крамольной" scanf народ использует? Странно, почему в столь многих учебниках именно эту функцию приводят в роли ввода, и ничего не говорят об ее крамольности...
А еще если не предпринять особых действий весь ввод прилетит только после нажатия enter.
Так что самое простое —сначала fgets а потом sscanf
Спасибо сказали:
-
- Сообщения: 989
- Статус: Чайник со свистком
- ОС: GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
Да, только вот есть ли по ним адекватные учебные статьи для новичков? Я конечно пока не берусь ничего утверждать, сильно гуглить сейчас лень, но навскидку выдаются только статьи с весьма замороченными (для новичка) примерами. Не получится ли так, что мне сейчас легче разобраться с некоторыми косяками scanf, чем вникать в весьма сложные для меня примеры с fgets и sscanf?...
Re: Начинаю осваивать C, появляются вопросы...
Если у вас ввод был такой:QWERTYASDF писала: ↑30.08.2018 19:15Где пробел? В моем примере, если использовать Ваш совет определения значения переменной, то мне printf кажет "10" т.е. перевод строки.А почему не перевод строки, он же последним стоит?прочитан пробел после 2
Чет ничего не понимаю...
Спасибо, теперь кажись понимаю : )
1 2
+
то есть 1 2[Enter]+[Enter],
соответственно: "1 2\n+\n",
то после 2 будет прочитан сивол '\n'. Если по шаблону scanf ожидает символ без указания пропускать пробельные (в шаблоне перед %c нет пробела), он его и вернет. Иначе будет продолжать читать поток ввода, пока не встретит непробельный символ, его и вернет.
Про особенности scanf: предупрежден, значит вооружен. Прежде всего стоит проверять возвращаемый функцией результат — количество прочитанных переменных — и предусматривать логику на случай, если что-то пошло не так, для учебных задачек пока вполне достаточно
Иначе можно за деревьями и леса не заметить...
Ну а если стало скучно и разобрались и с этим, то как с Казанью, не обратно же ее отдавать
Спасибо сказали:
Re: Начинаю осваивать C, появляются вопросы...
Ага, особенно они замороченные для fgets(), которая проста как огурец Просто считывает одну строчку в символьный массив. У sscanf логика точно такая же, как и у scanf, только данные он использует не из файла, а из символьной строки. Тут просто понятно что делать, если что-то пошло не так: вернуться обратно к fgetsQWERTYASDF писала: ↑31.08.2018 00:38Да, только вот есть ли по ним адекватные учебные статьи для новичков? Я конечно пока не берусь ничего утверждать, сильно гуглить сейчас лень, но навскидку выдаются только статьи с весьма замороченными (для новичка) примерами. Не получится ли так, что мне сейчас легче разобраться с некоторыми косяками scanf, чем вникать в весьма сложные для меня примеры с fgets и sscanf?...
Но вообще аккуратный разбор вводимых данных -- задача не такая простая, как хотелось бы.
-
- Сообщения: 989
- Статус: Чайник со свистком
- ОС: GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
А не могли бы Вы немножко прокомментировать строчки:bormant писал(а): ↑30.08.2018 14:43Код: Выделить всё
#include <stdio.h> int main(void) { int a, b; char op, *fmt = "%d %c %d = %d\n"; do { printf("number operator number: "); scanf(" %d %c %d", &a, &op, &b); switch (op) { case '+': printf(fmt, a, op, b, a+b); break; case '-': printf(fmt, a, op, b, a-b); break; case '*': printf(fmt, a, op, b, a*b); break; case '/': printf(fmt, a, op, b, a/b); break; default: printf("*** wrong! ***"); } printf("0 to stop, other to continue: "); scanf(" %c", &op); } while ('0' != op); return 0; }
Код: Выделить всё
int main(void)
Код: Выделить всё
return 0;
Я сейчас еще подробно не осваиваю по своим учебникам моменты, связанные с ними, но может быть какую-то пользу смогу сейчас извлечь из этого вопроса. Собственно, мне понятно все кроме void в скобочках после объявления главной функции. Второстепенно - зачем вообще все это в таких, достаточно простых, программах нужно, если не учитывать "правила хорошего тона, к которому надо сразу привыкать"? Беглое гугление выдало противоречивый результат - кто-то говорит, что писать return в таких случаях - может быть практически полезно ; другие утверждают, что это совершенно бесполезная вещь, только усложняющая код. Примерно такое же впечатление и по поводу формата объявления main. Говорят, что она по умолчанию возвращает целочисленное значение - зачем тогда это отдельно указывать? Ну и что значит и int и void одновременно, причем второе в скобках (впрочем, это был первый вопрос)?...
- Hephaestus
- Сообщения: 3729
- Статус: Многоуважаемый джинн...
- ОС: Slackware64-14.1/14.2
- Контактная информация:
Re: Начинаю осваивать C, появляются вопросы...
Пожалуйста:QWERTYASDF писала: ↑03.09.2018 22:24А не могли бы Вы немножко прокомментировать строчки:
Код: Выделить всё
int main(void) { ... ... return 0; }
int - функция возвращает целое значение.
void - значение отсутствует (в данном случае отсутствуют входные параметры).
return 0 - возврат целого значения (того самого, которое int).
Другие варианты записи функции main:
Код: Выделить всё
void main(void)
{
...
...
}
Код: Выделить всё
void main()
{
...
...
}
Код: Выделить всё
main()
{
...
...
}
В разное время разные версии компиляторов выдавали предупреждения для разных вариантов.
Последний раз редактировалось Hephaestus 04.09.2018 10:03, всего редактировалось 1 раз.
Спасибо сказали:
-
- Сообщения: 989
- Статус: Чайник со свистком
- ОС: GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
Ну так получается, что можно просто:
?
Return тоже, насколько понимаю, необязателен. Так, для "привычки к хорошему тону". Ладно, не буду себе этим сейчас голову забивать, надо хотя бы до этого по учебнику дойти.
Код: Выделить всё
main()
{
...
...
}
Return тоже, насколько понимаю, необязателен. Так, для "привычки к хорошему тону". Ладно, не буду себе этим сейчас голову забивать, надо хотя бы до этого по учебнику дойти.
Re: Начинаю осваивать C, появляются вопросы...
Код возврата функции main - это атавизм, оставшийся с древних времён. Когда программы были маленькими, а компьютеры - большими.
Вообще, если что-то идёт не так в функции main - можно вернуть ненулевое значение. Допустим, если хотели открыть файл, а его не оказалось.
И, затем, проанализировать. В скрипте, к примеру.
Вообще, если что-то идёт не так в функции main - можно вернуть ненулевое значение. Допустим, если хотели открыть файл, а его не оказалось.
И, затем, проанализировать. В скрипте, к примеру.
- Bizdelnick
- Модератор
- Сообщения: 20793
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
Фигасе атавизм. Как без него жить-то?
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
Re: Начинаю осваивать C, появляются вопросы...
Вполне нормально. В GUI-программах. Всё равно ведь, если что пойдёт не так, будете смотреть stack вызовов, анализировать какие-нибудь файлы программы и т.д. Толку то вам от единственного кода ошибки...
Он нужен разве что в консольных программах.
P.S. К тому же, я не говорил, что код возврата совсем не нужен.
-
- Сообщения: 989
- Статус: Чайник со свистком
- ОС: GNU/Linux
- Bizdelnick
- Модератор
- Сообщения: 20793
- Статус: nulla salus bello
- ОС: Debian GNU/Linux
Re: Начинаю осваивать C, появляются вопросы...
По коду ошибки, как минимум, можно понять, успешно завершилась программа или нет. И это очень часто бывает нужно обработать, в том числе в GUI-приложениях.
Посмотрите в словаре значение слова «атавизм» в таком случае.
Пишите правильно:
в консоли вку́пе (с чем-либо) в общем вообще | в течение (часа) новичок нюанс по умолчанию | приемлемо проблема пробовать трафик |
Спасибо сказали: