Member 13999874 Ответов: 1

Создать работающий калькулятор на языке Си


У меня есть эта программа, которая должна быть работающим калькулятором. Я не могу заставить свой код работать после первого вычисления. Я не могу понять, что не так С "если". Какой-нибудь вклад?

Что я уже пробовал:

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

int calculate(int num1, char operator, int num2);

int main()
{
    int num1 = 0;
    int num2 = 0;
    int temp = 0;
    char operator;
    
    int count = scanf("%d %c %d", &num1, &operator, &num2);

    void clearBuffer(void)
    {
       while ((getchar()) != '\n')
           ;
    }

    int result = calculate(num1, operator, num2);
    printf("%d", result);
    temp = result;
      
    do
    {
        num1 = temp;
        int answer = 0;
        scanf("%c %d", &operator, &num2);
        void clearBuffer(void)
        {
            while( (getchar()) != '\n' )
                ; 
        }

        switch (operator)
        {
          case '+':
            answer = num1 + num2;
            break;
          case '-':
            answer = num1 - num2;
            break;
          case '*':
            answer = num1 * num2;
            break;
          case '/':
            answer = num1 / num2;
            break;
          case '%':
            answer = num1 % num2;
            break;
          default:
            printf("Thank you for using COP2220 Calculator!");
        }
        printf("%d", answer);
    } while(num1 >= 0);

    return 0;
}

int calculate(int num1, char operator, int num2)
{
    int answer = 0;
    switch (operator)
    {
    case '+':
        answer = num1 + num2;
        break;
    case '-':
        answer = num1 - num2;
        break;
    case '*':
        answer = num1 * num2;
        break;
    case '/':
        answer = num1 / num2;
        break;
    case '%':
        answer = num1 % num2;
        break;
    }

    return answer;
}

Rick York

Я не прошелся по вашему коду мелкозубой расческой, но немного отрегулировал интервал и добавил теги pre к вашему сообщению. Я бы внимательно посмотрел на функцию clearBuffer. Я удивлен, что даже компилируется на Си на самом деле. Я бы переместил эту основную функцию и сделал ее отдельной функцией, вне каких-либо других. Я бы также пересмотрел ваш код, чтобы он всегда вызывал calculate для выполнения своих вычислений. У вас есть код, чтобы сделать это в двух местах, и это то, чего следует избегать.

Richard MacCutchan

Почему вы делаете расчеты в двух местах? Я показал вам, что делать вчера в вашем вопросе на https://www.codeproject.com/Questions/1261653/Run-a-switch-for-characters-equals-in-a-while-loop[^].

Member 13999874

Это всего лишь одна из моих многочисленных попыток заставить его компилироваться и запускаться. Он делает то же самое, что и тогда, когда я только что вызвал функцию снова, но я еще не переключил ее обратно. Я просто не могу понять, где все идет не так. Я пытался связаться с моим профессором, но не получил никакого ответа.

Richard MacCutchan

Вчера я предложил вам рабочее решение, так почему же вы им не воспользовались?

Member 13999874

Я не мог заставить его работать правильно.

Richard MacCutchan

Тогда вы должны были ответить на мое сообщение в этом вопросе с полной информацией о том, что вы пробовали, вместо того, чтобы открывать новый вопрос с другим кодом.

Member 13999874

Извините, если я не следовал типичному процессу. Я новичок на этом сайте. Я попытался ответить, но он не позволил мне, так как я принял решение. Теперь у меня есть код, который компилируется и запускается благодаря всей той помощи, которую я получил здесь. Единственная проблема, с которой я сталкиваюсь, - это когда недопустимый оператор, код завершается с моим значением по умолчанию, за которым следует 0. Я знаю, что это происходит потому, что у меня есть возвращаемое значение 0, но когда я вынимаю его, возникает ошибка. Вы не знаете, как я могу это исправить?

Richard MacCutchan

Добавить а default: дело в вашем заявлении о переключении. И если вы хотите помочь с ошибкой, вам нужно объяснить, что это за ошибка на самом деле.

Кроме того, всегда полезно прочитать документацию, если вы в чем-то не уверены.

Rick York

Одна из очень веских причин иметь код расчета только в одном месте-это то, что он позволяет вам легче видеть поток кода, когда он не так загроможден. Кроме того, сделайте clearBuffer функцией, реализованной один раз. Затем вы можете легко прокомментировать его и посмотреть, какой эффект это имеет. Вот ваш код с функциями, как я уже упоминал :

int calculate(int num1, char operator, int num2)
{
    int answer = 0;
    switch (operator)
    {
    case '+':
        answer = num1 + num2;
        break;
    case '-':
        answer = num1 - num2;
        break;
    case '*':
        answer = num1 * num2;
        break;
    case '/':
        answer = num1 / num2;
        break;
    case '%':
        answer = num1 % num2;
        break;
    }

    return answer;
}


void clearBuffer(void)
{
     while( getchar() != '\n' )
         ; 
}


int main()
{
    int num1 = 0;
    int num2 = 0;
    int temp = 0;
    char operator;
    
    int count = scanf("%d %c %d", &num1, &operator, &num2);

    clearBuffer();

    int result = calculate( num1, operator, num2 );
    printf( "result is %d\n", result );
    temp = result;
      
    do
    {
        num1 = temp;
        int answer = 0;
        scanf("%c %d", &operator, &num2);
        
        clearBuffer();
        
        answer = calculate( num1, operator, num2 );

        printf("answer is %d\n", answer);

    } while(num1 >= 0);

    return 0;
}

Разве теперь это не легче увидеть? Кстати, я пишу код вверх ногами с очень небольшим количеством прототипов. Это всего лишь я.

Richard MacCutchan

Почти то же самое, что я дал ему вчера, так что понятия не имею, почему он ушел и сделал что-то другое. Кстати, я согласен с вами в том, что вы не используете прототипы; это одна из худших идей на свете.

Rick York

Я думаю, что они имеют смысл, когда код находится в разных модулях, но не для кода в одном и том же.

Richard MacCutchan

Верно, но только потому, что вы должны определить любые внешние функции. Проблема в том, что они должны быть созданы в двух местах: заголовок и файл реализации. Поэтому гораздо проще сделать простую ошибку, если один из них изменится.

Rick York

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

KarstenK

Используйте отладчик с установкой точки останова и выясните это.

1 Ответов

Рейтинг:
8

OriginalGriff

Компиляция не означает, что ваш код верен! :смеяться:
Подумайте о процессе разработки как о написании электронного письма: успешная компиляция означает, что вы написали письмо на правильном языке - например, на английском, а не на немецком, - а не то, что письмо содержало сообщение, которое вы хотели отправить.

Итак, теперь вы входите во вторую стадию разработки (на самом деле это четвертая или пятая, но вы перейдете к более ранним стадиям позже): тестирование и отладка.

Начните с рассмотрения того, что он делает, и как это отличается от того, что вы хотели. Это важно, потому что это дает вам информацию о том, почему он это делает. Например, если программа предназначена для того, чтобы позволить пользователю ввести число, а затем удвоить его и напечатать ответ, то если бы ввод / вывод был таким:

Input   Expected output    Actual output
  1            2                 1
  2            4                 4
  3            6                 9
  4            8                16
Тогда совершенно очевидно, что проблема заключается в бите, который удваивает его - он не прибавляет себя к себе или умножает его на 2, он умножает его на себя и возвращает квадрат входного сигнала.
Таким образом, вы можете посмотреть на код, и очевидно, что он находится где-то здесь:
int Double(int value)
   {
   return value * value;
   }

Как только у вас появится идея, что может пойти не так, начните использовать отладчик, чтобы выяснить, почему. Поместите точку останова в первую строку метода и запустите приложение. Когда он достигнет точки останова, отладчик остановится и передаст управление вам. Теперь вы можете запускать свой код построчно (так называемый "одноступенчатый") и просматривать (или даже изменять) содержимое переменных по мере необходимости (черт возьми, вы даже можете изменить код и повторить попытку, если вам это нужно).
Подумайте о том, что должна делать каждая строка кода перед ее выполнением, и сравните это с тем, что она действительно делала, когда вы использовали кнопку "Step over" для выполнения каждой строки по очереди. Он сделал то, что вы ожидали? Если да, то переходите к следующей строке.
Если нет, то почему? Чем это отличается?
Надеюсь, это поможет вам определить, в какой части этого кода есть проблема и в чем она заключается.
Это навык, и его стоит развивать, поскольку он помогает вам как в реальном мире, так и в развитии. И, как и все навыки, он только улучшается при использовании!