Почему это запускает бесконечный цикл?

Я пишу на C, и кажется, что программа игнорирует команду scanf и начинает выполнять бесконечный цикл, если я вставляю что-нибудь, кроме числа. Кто-нибудь знает, как это исправить или даже что происходит?

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

#define NBITS 8

void inserimento() {
    int N, ret;

    do {
        printf("Immetti un numero maggiore di 1\n");
        ret = scanf("%d", &N);
    } while (ret == 0 || N <= 1);
}

int main() {
    int N;
    inserimento();
}

Я пробовал изменить порядок оператора or и использовать решение из кода, который дал нам мой профессор, но я довольно новичок в этом, поэтому не знаю, не ошибся ли я при его копировании.

Это связано с тем, что символы остаются в буфере клавиатуры. Поэтому вам необходимо очистить буфер клавиатуры.

CGi03 07.08.2024 10:56

@ CGi03 Не «буфер клавиатуры». Это опасное заблуждение. Символы остаются в потоке и должны быть удалены из потока путем их чтения.

n. m. could be an AI 07.08.2024 11:03

Никогда не используйте scanf для взаимодействия с пользователем. Прочитайте весь интерактивный ввод с помощью fgets, затем проанализируйте полученную строку. Смотрите здесь.

n. m. could be an AI 07.08.2024 11:05

Повторите 1000 раз: Никогда не используйте scanf.

Support Ukraine 07.08.2024 12:07
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
68
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Это происходит потому, что символы остаются в потоке. Поэтому вы должны опорожнить поток.

#include <stdio.h>

void fflush_stdin(void)
{
    int c;
    while ((c = getchar()) != EOF && c != '\n');
}

void inserimento()
{
    int N, ret;
    do
    {
        printf("Immetti un numero maggiore di 1\n");
        ret = scanf("%d", &N);
        fflush_stdin();
    }
    while(ret==0 || N <= 1);
}

int main()
{
    inserimento();
}

Когда первый вызов scanf("%d", &N) возвращает EOF, ret==0 || N <= 1 пытается оценить неинициализированный N. Бесконечный цикл все еще может существовать. Используйте ret==0 || (ret > 0 && N <= 1)

chux - Reinstate Monica 07.08.2024 11:38

Есть несколько проблем:

  • если scanf() не удается преобразовать входные данные в десятичное целое число, он вернет либо 0, и ошибочный ввод должен быть удален вручную, либо EOF, если обнаружен конец файла или ошибка чтения. Рекомендуется тщательно проверять эти условия, чтобы гарантировать правильную работу во всех случаях.
  • вы не передаете адрес N в функцию main, поэтому значение, прочитанное inserimento(), будет потеряно.
  • Циклы do/while сбивают с толку и подвержены ошибкам, я рекомендую использовать циклы forever for (;;) и явные тесты.

Вот модифицированная версия:

#include <stdbool.h>
#include <stdio.h>

int flush_stream(FILE *fp) {
    int c;
    while ((c = fgetc(fp)) != EOF && c != '\n')
        continue;
    return c;
}

bool inserimento(int *dest) {
    for (;;) {
        printf("Enter a number greater than 1:\n");
        switch (scanf("%d", dest)) {
          case EOF:
            printf("invalid or missing input\n");
            return false;
          case 0:
            flush_stream(stdin);
            printf("invalid input\n");
            break;
          case 1:
            if (*dest > 1)
                return true;
            printf("invalid entry: %d\n", *dest);
            break;
        }
    }
}

int main(void) {
    int N;
    if (inserimento(&N)) {
        /* do something with N */
        return 0;
    } else {
        return 1;
    }
}

Другие вопросы по теме