Когда я запускаю свой код дважды (после while / DoWhile), scanf работает не так, как задумано.(Я использую консольное приложение Visual C ++ для Windows) - PullRequest
0 голосов
/ 19 мая 2019

Я новичок в программировании, и я пытался сделать калькулятор, и я добавляю цикл while, так что если вы хотите повторить, просто наберите "1", и программа повторится.Проблема в том, что, если я повторяю это, разрывы scanf() не позволяют мне вводить что-либо в командную строку.(Я использую консольное приложение Visual C ++ для Windows)

Я пытался использовать fflush(stdin) для очистки буфера клавиатуры, это тоже не сработало.

#include "pch.h"
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>


void main() {
    char v;
    int exit=1;
    while (exit == 1) {
        v = 0;
        //Read what type of calcualtion the user wants to do.
        printf("Type (+,-,*,/): ");
        fflush(stdin); 
        scanf("%c", &v);
        //system("cls");
        //show the user for 2 sec what he chose
        printf("Type you chose: %c", v);
        Sleep(2000);
        //system("cls");
        //here the calcualtion will take place. 
        switch (v) {
        case '+':
            printf("\nTBD +");
            break;
        //Here are some more cases that i have excluded.
        default:
            printf("Please only use '+,-,*,/' above\n");
            exit = 1;
            break;
        }
        printf("\n do you want to repeat (1==yes|0==no): ");
        scanf_s("%d", &v);
    }
}

Результат при запуске этой программы выглядит следующим образом:

Type (+,-,*,/): +
Type you chose: +
TBD +
 do you want to repeat (1==yes|0==no): 1
Type (+,-,*,/): Type you chose:
Please only use '+,-,*,/' above

do you want to repeat (1==yes|0==no):

Результат должен выглядеть примерно так:

Type (+,-,*,/): +
Type you chose: +
TBD +
 do you want to repeat (1==yes|0==no): 1
Type (+,-,*,/): +
Type you chose: +
TBD +
 do you want to repeat (1==yes|0==no): 1

Ответы [ 2 ]

1 голос
/ 19 мая 2019

Есть много проблем с вашим кодом. Во-первых, вам не нужен заголовок Windows или вам нужно было использовать scanf_s. Также fflush(stdin) приводит к неопределенному поведению. Вы должны очистить поток ввода самостоятельно. В качестве альтернативы scanf используйте fgets или fgetc и выполните преобразование самостоятельно. Другая проблема в вашем коде заключается в том, что вы сбрасываете значение v в начале цикла. Затем вы задаете значение по умолчанию от 1 до x, но отмечаете while(x==1) Вы также пытаетесь выполнить код хотя бы один раз, независимо от начального условия, и циклы do while являются лучшей альтернативой while в этом случае. , Также только для соглашения об именах, если вы продолжаете цикл на exit == 1, это вводит в заблуждение. Если exit == 1, то вы должны завершить цикл. это очень запутанный и запутанный код. Позвольте мне попытаться очистить это для вас.

int main()  {
    //We only need a size of 3 , 1 for character, 1 for null terminator,1 for carriage return
    char v[32] = {0};
    int exit = 0;
    do{
        //Read what type of calcualtion the user wants to do.
        printf("Type (+,-,*,/): ");
        fgets(v, sizeof(v), stdin);
        //system("cls");
        //show the user for 2 sec what he chose
        printf("Type you chose: %c", *v);//dereference the pointer to the first character
        //system("cls");
        //here the calcualtion will take place.
        switch (*v) {//dereference the pointer to the first character
            case '+':
                printf("\nTBD +");
                break;
                //Here are some more cases that i have excluded.
            default:
                printf("Please only use '+,-,*,/' above\n");
        }
        printf("\n do you want to exit (1==yes|0==no): ");
        fgets(v, sizeof(v),stdin);
        exit = atoi(v);
    }while(exit != 1);
}

Мы даем v размером 32, хотя если мы вводим только 1 символ, то достаточно размера 3. Главным образом потому, что ввод одного символа с помощью fgets будет занимать три байта. Но так как мы принимаем целочисленное значение в конце цикла, мы хотим убедиться, что в буфере достаточно места. В случае, если пользователь вводит 123, например, буфер все еще будет в порядке, и дополнительные байты не останутся в потоке.

0 голосов
/ 19 мая 2019

Чтобы ваш оригинальный код работал

  • удалить вызов на fflush(stdin), поскольку fflush() не определено для входных потоков.
  • изменить scanf("%c", &v); на scanf(" %c", &v); (обратите внимание на пробел перед спецификатором преобразования %c), чтобы scanf() пропустить начальные пробелы.
  • изменить scanf_s("%d", &v); на scanf_s("%d", &exit);. Компилятор должен был предупредить вас о несоответствии типов между спецификатором преобразования %d и аргументом &v (int* против char*). Если этого не произошло, вы должны повысить уровень предупреждения вашего компилятора.

Возможная реализация с проверкой ошибок при вводе с использованием scanf():

#include <stdio.h>

int main(void)
{
    char keep_running;
    do {
        double first_operand;
        while (printf("First operand: "), scanf("%lf%*[^\n]", &first_operand) != 1)
               fputs("Input error. :(\n\n", stderr);

        char op;  // operator  (not named "operator" in case a C++-compiler ever sees this file)
        while (printf("Operation: "),
               scanf(" %c%*[^\n]", &op) != 1 || (op != '+' && op != '-' && op != '*' && op != '/'))
        {
            fputs("Input error. :(\n\n", stderr);
        }

        double second_operand;
        while (printf("Second operand: "), scanf("%lf%*[^\n]", &second_operand) != 1)
               fputs("Input error. :(\n\n", stderr);

        switch (op) {
        case '+':
            printf("\n%f %c %f = %f\n\n", first_operand, op, second_operand, first_operand + second_operand);
            break;

        case '-':
            printf("\n%f %c %f = %f\n\n", first_operand, op, second_operand, first_operand - second_operand);
            break;

        case '*':
            printf("\n%f %c %f = %f\n\n", first_operand, op, second_operand, first_operand * second_operand);
            break;

        case '/':
            if(second_operand)
                printf("\n%f %c %f = %f\n\n", first_operand, op, second_operand, first_operand / second_operand);
            else fputs("\nDivision by zero is undefined. :(\n\n", stderr);
            break;
        }

        while (printf("Do you want to repeat (y/n)? "),
               scanf(" %c%*[^\n]", &keep_running) != 1 || (keep_running != 'n' && keep_running != 'y'))
        {
            fputs("Input error. :(\n\n", stderr);
        }

        puts("\n");

    } while (keep_running == 'y');
}
  • Обратите внимание, что список параметров функций, которые не принимают аргументов, должен быть void в C, следовательно, int main(void).
  • scanf() возвращает количество успешных назначений. Проверьте это возвращаемое значение и обработайте ошибки ввода. Никогда не доверяйте пользователю.
  • Спецификатор преобразования %*[^\n] потребляет все символы, пока не будет найден символ новой строки, и не отбрасывает их. Таким образом, после scanf() во входном буфере не останется мусора. Обратите внимание, что при этом будут учитываться успешные преобразования, за которыми следует ввод правильного мусора. Если вы хотите рассматривать это как ошибку ввода, вам придется использовать более сложные методы.
...