Разница между fflush(stdin) и flushstdin()
В чем разница между использованием fflush(stdin)
а также flushstdin()
? Единственное различие, которое я знаю, это то, что мне нужно написать пустые вещи перед использованием flushstdin()
но я не знаю почему.
void flushstdin()
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
int main () {
float a, b, c;
float s=0, ar1=0, ar2=0;
printf("Inform value of side A");
while(scanf("%f",&a) != 1 || a <= 0){
printf("Invalid value.\n");
flushstdin();
}
}
а также
int main(){
float a,b,c,s=0;
printf("Inform value of side A.");
while(scanf("%f",&a) != 1 || a<=0){
printf("Invalid value.\n");
fflush(stdin);
}
}
Я новичок! Какой код лучший? Или они равны?
3 ответа
Обе версии имеют проблемы.
Как уже было подробно документировано, fflush(stdin)
имеет неопределенное поведение в соответствии со стандартом C. Альтернатива с использованием flushstdin()
Функция не намного лучше. Я предлагаю читать стандартный ввод по одной строке за раз и анализировать это с sscanf()
, все в служебной функции, которую вы можете использовать по мере необходимости:
int readfloat(const char *prompt, float *val) {
char buf[128];
for (;;) {
if (prompt)
fputs(prompt, stdout);
if (!fgets(buf, sizeof(buf), stdin)) {
printf("Premature end of file\n");
return 1;
}
if (sscanf(buf, "%f", val) == 1 && *val > 0)
return 0;
printf("Invalid value.\n");
}
}
int main(void) {
float a, b, c, s = 0;
if (readfloat("Enter value of side A: ", &a))
return 1;
...
}
Разница в том, что flushstdin
определяется пользователем и единственный способ в стандартном C для сброса stdin
, fflush
является стандартной библиотечной функцией fflush(stdin);
вызовет неопределенное поведение.
fflush
определяется только для выходных потоков. Поскольку его определение "flush" состоит в том, чтобы завершить написание буферизованных символов (не отбрасывать их), отбрасывание непрочитанного ввода не будет аналогичным значением дляfflush
на входных потоках.
Не существует стандартного способа отбрасывать непрочитанные символы из входного потока stdio. Некоторые поставщики внедряют
fflush
чтобыfflush(stdin)
отбрасывает непрочитанные символы, хотя переносимые программы не могут зависеть от этого. (Некоторые версииstdio
реализация библиотекиfpurge
или жеfabort
вызовы, которые делают то же самое, но они также не являются стандартными. Обратите внимание, что сбросstdio
входных буферов необязательно достаточно: непрочитанные символы также могут накапливаться в других входных буферах уровня ОС. Если вы пытаетесь активно отбросить ввод (возможно, в ожидании неожиданного приглашения подтвердить деструктивное действие, для которого случайно введенный "у" может иметь катастрофические последствия), вам придется использовать методику, специфичную для системы, чтобы обнаружить наличие опережающего ввода; см. вопросы 19.1 и 19.2. Имейте в виду, что пользователи могут расстроиться, если вы откажетесь от ввода, которое было введено слишком быстро.
Они совсем разные. Они оба могут "сбрасывать" ввод, но в разных смыслах этого слова.
fflush
является стандартной функцией C. Его поведение на входных потоках, таких как stdin
не определено - это означает, что стандарт C не определяет его поведение.
Некоторые системы определяют поведение fflush
на входном потоке. Например, в Linux:
Для входных потоков,
fflush()
отбрасывает любые буферизованные данные, которые были извлечены из базового файла, но не были использованы приложением.
Вы можете положиться на fflush(stdin)
вести себя в соответствии с этим описанием, если ваша программа работает в системе на основе Linux или в другой системе, которая документирует то же поведение. Поведение вашей программы не будет переносимым; в других системах он может вести себя как угодно плохо. (Скорее всего, если fflush(stdin)
не работает, ничего не даст, кроме как вернуть сообщение об ошибке, но это не гарантировано.)
Твой собственный flushstdin
Функция делает что-то отличное от поведения Linux fflush(stdin)
, Он читает и отбрасывает все функции ввода до первой новой строки или до EOF
(который вызывается либо концом файла, либо ошибкой). Это происходит независимо от того, буферизован ли этот вход или нет.
Например, предположим, что вы вводите главы hello
(без новой строки), то ваша программа вызывает fflush(stdin)
, а затем вы вводите новую строку.
fflush(stdin)
, учитывая задокументированное поведение Linux, откажется hello
и немедленно вернитесь, оставив перевод строки для последующего вызова. Это "вспыхивает" stdin
в том смысле, что он отбрасывает все ожидающие данные, независимо от того, что это такое.
Ваш flushstdin()
функция будет читать и отбрасывать hello
и затем подождите, пока вы не введете Enter (или Ctrl-D), а затем прочитаете и откажитесь от этого. Он считывает и отбрасывает весь ввод до новой строки или EOF, независимо от того, ожидал ли он во время вызова.
И снова поведение fflush(stdin)
не определяется стандартом C, поэтому его использование делает вашу программу непереносимой (и ваш компилятор не обязательно предупредит вас об этом).
Между прочим, "пустота" - это определение flushstdin
функция. Это не нужно для fflush
потому что это стандартная функция библиотеки C, которая уже определена для вас.