Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.56/75: Рейтинг темы: голосов - 75, средняя оценка - 4.56
0 / 0 / 0
Регистрация: 14.04.2013
Сообщений: 5
1

Написать строковый калькулятор

14.04.2013, 00:51. Показов 14856. Ответов 6
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
здравствуйте. просьба, хотя бы идейно, а лучше с примером подсказать, как научить программу решать пример.
суть: 5 + 5 - 28 * 3. нажимаю enter, выдаёт ответ. запускаю заново, пишу: 89 - 64 + 3, нажимаю enter, выдаётся ответ. а в идеале и такое: 2^3 - 5^(2/3).
подскажите, пожалуйста.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
14.04.2013, 00:51
Ответы с готовыми решениями:

Строковый калькулятор
Помогите пожалуйста написать строковый калькулятор . вход пример 56,8 +89,0-8,7 выход результат

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

Калькулятор строковый с защитой от дурака
Делаю курсовую - нужно сделать строковый калькулятор с защитой от дурака. Код не мой, я добавил...

Строковый калькулятор, добавление скобок
Здравствуйте! У меня есть готовый строковый калькулятор, который совершает операции +-/* с...

6
16 / 16 / 3
Регистрация: 06.02.2013
Сообщений: 57
14.04.2013, 01:11 2
Через стек.
Записать исходный пример в массив. Перевести в постфиксную форму, и оценить постфиксное фыражение.

Вот пример но он только для целых чисел и без проверки на корректность ввода.


C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
//РАБОТАЕТ ТОЛЬКО С ЦЕЛЫМИ ЧИСЛАМИ
 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
 
struct stackNode                                //для перевода в постфиксную форму
   {
    char data;
    struct stackNode* nextPtr;
   };
 
struct numberStackNode                          //стэк для калькулятора
   {
    int data;
    struct numberStackNode* nextPtr;
   };
 
typedef struct stackNode StackNode;                //для перевода в постфиксную форму
typedef StackNode* StackNodePtr;
 
typedef struct numberStackNode NumberStackNode;    //для калькулятора
typedef NumberStackNode* NumberStackNodePtr;
 
 
void convertToPostfix(char*, char*);          //переводит выражение и инфиксной в постфиксную запись
int isOperator(char);                         //определяет, является ли символ оператором
int precedence(char, char);                   //сравнивает по приоритету
 
void push(StackNodePtr*, char);
void pushInt(NumberStackNodePtr*, int);              //добавляет в стэк
 
char pop(StackNodePtr*);
int popInt(NumberStackNodePtr*);                      //выбирает из стэка
 
char stackTop(StackNodePtr);                  //смотрит верхнее значение стэка
int isEmpty(StackNodePtr);                    //проверяет пуст ли стэк
void printStack(NumberStackNodePtr);                //вывоит стэк(не используется)
int evaluatePostfixExpression(char*);             //создаёт элементарные выражения для calculate()
int calculate(int, int, char);                    //считает элементарные выражения
 
int main(void)
{
   char string[100];
   char postString[100];
   int i;
 
   printf("Enter infix string: ");
   gets(string);
   convertToPostfix(string, postString);
   printf("Postfix string: ");
   puts(postString);
   printf("Rezult: %d\n", evaluatePostfixExpression(postString));
 
   system("pause");
   return 0;
}
 
void push(StackNodePtr* topPtr, char value)
{
   StackNodePtr newPtr;
 
   newPtr=malloc(sizeof(StackNode));
 
   if(newPtr!=NULL)
     {
      newPtr->data=value;
      newPtr->nextPtr=*topPtr;
      *topPtr=newPtr;
     }
   else
      printf("%c not inserted. No memory available.\n", value);
}
 
void pushInt(NumberStackNodePtr* topPtr, int value)
{
   NumberStackNodePtr newPtr;
 
   newPtr=malloc(sizeof(NumberStackNode));
 
   if(newPtr!=NULL)
     {
      newPtr->data=value;
      newPtr->nextPtr=*topPtr;
      *topPtr=newPtr;
     }
   else
      printf("%d not inserted. No memory available.\n", value);
}
 
char pop(StackNodePtr* topPtr)
{
   StackNodePtr tempPtr;
   char popValue;
 
   tempPtr=*topPtr;
   popValue=(*topPtr)->data;
   *topPtr=(*topPtr)->nextPtr;
  // printf("%c", tempPtr->data);
   free(tempPtr);
 //  printf("\n");
   return popValue;
}
 
 
int popInt(NumberStackNodePtr* topPtr)
{
   NumberStackNodePtr tempPtr;
   int popValue;                                  
 
   tempPtr=*topPtr;
   popValue=(*topPtr)->data;
   *topPtr=(*topPtr)->nextPtr;
  // printf("%c", tempPtr->data);
   free(tempPtr);
 //  printf("\n");
   return popValue;
}
 
void printStack(NumberStackNodePtr currentPtr)
{
   if(currentPtr==NULL)
      printf("The stack is empty.\n\n");
   else
     {
     printf("The stack is:\n");
 
      while(currentPtr!=NULL)
         {
          printf("%d --> ", currentPtr->data);
          currentPtr=currentPtr->nextPtr;
         }
 
      printf("NULL\n\n");
     }
}
 
int isEmpty(StackNodePtr topPtr)
{
   return topPtr==NULL;
}
 
char stackTop(StackNodePtr topPtr)
{
  return topPtr->data;
}
 
int precedence(char operator1, char operator2)                //ничё другого не пришло в голову...
{
   char oper[]={'+', '-', '*', '/', '^', '%'};
   int prior[]={0, 0, 1, 1, 2, 2};
   int counter=-1, op1, op2;
 
   while(++counter<6)
      {
       if(oper[counter]==operator1)
          op1=prior[counter];
 
       if(oper[counter]==operator2)
          op2=prior[counter];
      }
 
   if(op2==op1)
      return 0;
   else if(op1<op2)
      return -1;
   else if(op1>op2)
      return 1;
 
}
 
int isOperator(char c)
{
   if(c=='+' || c=='-' || c=='*' || c=='/' || c=='^' || c=='%')
      return 1;
 
   return 0;
}
 
void convertToPostfix(char* infix, char* postfix)
{
   StackNodePtr stackPtr=NULL;
   int len, i=0, j=0;
   char temp;
 
   push(&stackPtr, '(');
   len=strlen(infix);
   *(infix+len)=')';
   *(infix+len+1)='\0';
 
   while(stackPtr!=NULL)
      {
       if(isdigit(*(infix+i)))
         {
          *(postfix+j++)=*(infix+i++);
 
          while(isdigit(*(infix+i)))
             *(postfix+j++)=*(infix+i++);
 
          *(postfix+j++)=' ';
         }                                     
       else if(*(infix+i)=='(')
         {
          push(&stackPtr, '(');
          i++;
         }
       else if(isOperator(*(infix+i)))
         {
          while(isOperator(stackPtr->data) && precedence(stackPtr->data, *(infix+i))!=-1)
             {
              *(postfix+j++)=pop(&stackPtr);
              *(postfix+j++)=' ';
             }
 
          push(&stackPtr, *(infix+i++));
         }
       else if(*(infix+i)==')')
         {
          while(stackPtr->data!='(')
             {
              *(postfix+j++)=pop(&stackPtr);
              *(postfix+j++)=' ';
             }
 
          temp=pop(&stackPtr);
          i++;
         }
      }
 
   *(postfix+j)='\0';
}
 
int evaluatePostfixExpression(char *postfixString)
{
   NumberStackNodePtr stackPtr=NULL;
   int x=0, y=0;
   int i=0;
   char *resPtr;
 
   while(*(postfixString+i)!='\0')
      {
       if(*(postfixString+i)==' ')
         {
          i++;
          continue;
         }
 
       if(isdigit(*(postfixString+i)))
         {
          pushInt(&stackPtr, strtol(postfixString, &resPtr, 0));
 
          if(resPtr[0]==' ')
             postfixString=&resPtr[1];
         else
             postfixString=resPtr;
         }
       else
         {
          y=popInt(&stackPtr);
          x=popInt(&stackPtr);
          printf("x=%d %c y=%d =%d\n", x, *(postfixString+i),y, calculate(x, y, *(postfixString+i)));
          pushInt(&stackPtr, calculate(x, y, *(postfixString+i)));
          postfixString+=2;
         }
      }
 
   return popInt(&stackPtr);
}
 
int calculate(int x, int y, char opr)
{
   int rez=0;
 
   switch(opr)
      {
       case '+':
          rez=x+y;
          break;
       case '-':
          rez=x-y;
          break;
       case '*':
          rez=x*y;
          break;
       case '/':
          if(y==0)
          rez=0;
          else
          rez=x/y;
          break;
       case '^':
          rez=pow(y, x);
          break;
       case '%':
          rez=x%y;
       default:
          break;
      }
 
   return rez;
}
2
29 / 29 / 13
Регистрация: 15.11.2012
Сообщений: 93
14.04.2013, 01:26 3
Лучший ответ Сообщение было отмечено Памирыч как решение

Решение

Вот готовый пример калькулятора, не используя стек, а просто обрабатывая строку.
Сложение, вычитание, умножение, деление, возведение в степень, скобочки, тригонометрические функции (sin, cos, tang). При желании можно добавить еще что-нибудь.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#include <iostream>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cmath>
using std::cin;
using std::cout;
using std::endl;
#include "Windows.h"
 
void eatspaces(char* str); //функция для удаления пробелов
double expr(char* str); //функция, вычисляющая выражение
double term(char* str, int& index); //функция для анализа элемента
double trigon(char* str, int& index); //функция для вычисления тригонометрических значений
double power(char* str, int& index); //функция для извлечения степени
double number(char* str, int& index); //функция, распознающая число
char* extract(char* str, int& index); //функция для извлечения подстроки
 
const int MAX = 80; //максимальный размер буфера
 
int main()
    {
    setlocale(0, "Russian");
    char buffer[MAX] = {0}; //область хранения вычисляемого входного выражения
    cout << endl << "Добро пожаловать в дружественный колькулятор!" << endl
         << "Введите выражение или пустую строку для завершения." << endl;
    for ( ; ; )
        {
        cin.getline(buffer, sizeof buffer); //читаем входную строку
        eatspaces(buffer); //удаляем все пробелы из строки
        if (!buffer[0]) //если пустая строка
            return 0;
        cout << "= " << expr(buffer)
             << endl << endl;
        }
    }
        
void eatspaces(char* str)
    {
    int i = 0;                          //индекс места в строке "куда копировать"
    int j = 0;                          //индекс места в строке "откуда копировать"
    while ((*(str+i) = *(str + j++)) != '\0') //цикл, пока очередной символ не '\0'
        if (*(str+i) != ' ')  //увеличиваем i, если символ не пробел
            i++;
    return;
    }
    
double expr(char* str)
    {
    double value = 0.0;         //здесь сохраняем результат
    int index = 0;              //текущая позиция символа
    value = term(str, index);   //получить первый элемент
    for ( ; ; )                 //бесконечный цикл, выход внутри
        {
        switch (*(str+index++)) //выбрать действие на основе текущего символа
            {
            case '\0':          //конец строки, возвращаем значение
                return value;
            case '+':           //знак плюс, прибавляем элемент к value
                value += term(str, index);
                break;
            case '-':           //знак минус, вычитаем элемент из value
                value -= term(str, index);
                break;
            default:            //все остальное не котируется
                int i = index;
                while (--i > 0)
                    cout << " ";
                cout << "^" << endl;
                cout << "Эй, повнимательней можно?! Здесь обнаружена ошибка. " << endl;
                exit(1);
            }
        }
    }
    
double term(char* str, int& index)
    {
    double value = 0.0;             //здесь накапливается значение результата
    value = power(str, index);      //получить первое число элемента
    //выполняем цикл до тех пор, пока имеем допустимую операцию
    while ((*(str + index) == '*') || (*(str + index) == '/')) 
        {
        if (*(str+index) == '*')
            value *= power(str, ++index);
        if (*(str+index) == '/')
            value /= power(str, ++index);
        }
    return value;
    }
    
    
double power(char* str, int& index)
    {
    double value = 0.0;
    value = trigon(str, index);
    while (*(str + index) == '^')
        {
        value = pow(value, trigon(str, ++index)); //возводим в степень
        }
    return value;
    }   
 
double trigon(char* str, int& index)
    {
    int buf_index = 0;
    int temp_index = index; //переменная для хранения индекса (чтобы если что вернуть индекс без изменений)
    char* p_str = 0;    //временный указатель для сравнения символов
    double value = 0;
    while (isalpha(*(str + temp_index)))
        {
        buf_index++;    //сколько букв
        temp_index++;   //текущий индекс
        }
    if (!buf_index)     //если нет ни одной буквы, то возвращаем число
        {
        value = number(str, index);
        return value;
        }
    else                //иначе смотрим, являются ли буквы чем-нибудь этим
        {
        p_str = new char[buf_index+1];  //а для этого создаем временную строку, чтобы сравнить
        p_str[buf_index] = '\0';
        strncpy(p_str, str+index, buf_index);
        }
    if (strcmp(p_str, "sin") == 0)      //синус в градусах
        {
        value = sin(3.141592/180*number(str, temp_index));
        index = temp_index;
        delete[] p_str;     //не забываем удалить временную строку
        return value;
        }
    else if (strcmp(p_str, "cos") == 0) //косинус в градусах
        {
        value = cos(3.141592/180*number(str, temp_index));
        index = temp_index;
        delete[] p_str;     //не забываем удалить временную строку
        return value;
        }
    else if (strcmp(p_str, "tan") == 0) //тангенс в градусах
        {
        value = tan(3.141592/180*number(str, temp_index));
        index = temp_index;
        delete[] p_str;     //не забываем удалить временную строку
        return value;
        }
    else
        {
        return value;
        }
    }
    
double number(char* str, int& index)
    {
    double value = 0.0;                 //хранит результирующее значение
    if (*(str + index) == '(')
        {
        char* p_substr = 0;
        p_substr = extract(str, ++index);
        value = expr(p_substr);
        delete[] p_substr;
        return value;
        }
    //продуманский цикл, превращает символы в число
    while (isdigit(*(str+index)))       //цикл накапливает ведущие цифры 
        value = 10*value + (*(str + index++) - '0');
    if (*(str + index) != '.')          //если не цифра, проверяем на десятичную точку
        return value;
    double factor = 1.0;                //множитель для десятичных разрядов
    //еще один продуманский цикл, возвращает десятичную часть
    while (isdigit(*(str + (++index)))) //выполнять цикл, пока идут цифры 
        {
        factor *= 0.1;
        value = value + (*(str + index) - '0')* factor;
        }
    return value;
    }
    
char* extract(char* str, int& index)
    {
    char buffer[MAX];       //временное пространство для подстроки
    char* p_str = 0;        //указатель на новую строку для возврата
    int numL = 0;           //счетчик найденных левых скобок
    int buf_index = index;  //сохранить начальное значение index
    do
        {
        buffer[index - buf_index] = *(str+index); //копируем символ текущей строки в подстроку
        switch(buffer[index - buf_index]) //смотрим, чо это за символ
            {
            case ')':
                if (numL == 0)
                    {
                    buffer[index - buf_index] = '\0'; //если счетчик скобочек верный, ставим символ конца строки
                    ++index;    //устанавливаем индекс на следующий за скобочкой элемент
                    p_str = new char[index-buf_index];
                    if (!p_str)
                        {
                        cout << "Выделение памяти не удалось, программа прервана.";
                        exit(1);
                        }
                    strcpy_s(p_str, index - buf_index, buffer); //и копируем подстроку в новую память
                    return p_str;
                    }
                else
                    numL--;     //уменьшаем счетчик скобок
                break;
            case '(':
                numL++;         //соответственно увеличиваем
                break;
            }
        } while (*(str + index++) != '\0');     //устанавливаем индекс в следующий элемент
    cout << "Вывод за пределы выражения, возможно, плохой ввод." << endl;
    exit(1);
    return p_str;
    }
3
1 / 1 / 0
Регистрация: 10.04.2013
Сообщений: 17
14.04.2013, 02:33 4
Вместо тысячи слов...
http://ru.wikipedia.org/wiki/%... 1%81%D1%8C
0
134 / 106 / 10
Регистрация: 22.05.2010
Сообщений: 533
14.04.2013, 03:11 5
Rifle и _Simpson правильно говорят.
Разве только я бы делал через дерево или очередь.
Почему? Потому что так удобнее держать единственное результирующее значение, а юзая рекурсию вообще получаем едва ли не бесплатный калькулятор. Правда стек и реализует рекурсию более эффектино, придётся немного подумать. Да и очередь почти одно и тоже даст. А так, я вижу примерно такое:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include ...
 
using ...
 
enum Operator ( sum, substract, mult, div );
 
int count ( string expression, Operator op = sum ) { // op is 'operator'
    stringList splits = expression.split ( op )
    if ( stringList.count == 1 ) {
        return parseInt ( stringList[ 0 ] );
    }
    int res = ( op == sum || op == substract ? 0 : 1 );
    foreach ( string &s in splits ) {
        if ( op == sum || op == substract ) {
            res += ( op == substract ? -1 : 1 ) * count ( s );
        } else if ( op == mult ) {
            res *= count ( s );
        } else if ( op == div ) {
            res /= count ( s );
        }
    }
    
    return res;
}
 
int main ( int argc, char **argv ) {
    println ( "%d\n", count ( argv[ 1 ] ) );
    
    return 0;
}
Внимание! Компилировать никак не получиться, да и вообще стиль написания кода соответствует стилю написания кода в 2 часа ночи в перерывах между ходами в HoMM4 и почитывания хабры, так что "казнить нельзя, помиловать".
Алсо, здесь потребуется много чего реализовать. То как доделать класс std::string, сделать класс StringList и так далее. Да и использовались плюшки из C++11.

Добавлено через 37 минут
Update:
Это рекурсия, но по сути она соответствует дереву. Работает через стек, конечно. Производительность пониже, но писать намного проще.

Добавлено через 1 минуту
Цитата Сообщение от cygwin Посмотреть сообщение
Вместо тысячи слов...
http://ru.wikipedia.org/wiki/%... 1%81%D1%8C
Не, это не зергут. На wolframalpha.com так не издеваются, например.
0
0 / 0 / 0
Регистрация: 28.10.2014
Сообщений: 15
14.04.2013, 07:55 6
спасиб как раз то что на прогу надо ьыло
0
0 / 0 / 0
Регистрация: 14.04.2013
Сообщений: 5
14.04.2013, 12:17  [ТС] 7
всем спасибо, сижу разбираюсь)
0
14.04.2013, 12:17
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
14.04.2013, 12:17
Помогаю со студенческими работами здесь

Строковый калькулятор в два стека
У кого есть какие примеры реализации на плюсах, желательно с комментариями. Ибо перечитав море...

Калькулятор выражений(строковый) через бинарное дерево
Создал калькулятор выражений, но он считает только целые числа. Не могу доработать чтобы работал на...

Написать функцию (строковый парсер), воспроизводящую работу простейшего калькулятора
В качестве параметра задается строка где a - целое число от 1 до 9, Z - знак * или / Функция...

Тема: Циклы, строковый тип. Написать программу по данной задаче
:help: В строке записан текст, в котором слова разделены знаками препинания (пробел : , - ; ), в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru