Проверить корректность арифметического выражения, заданного строкой - C (СИ)

Узнай цену своей работы

Формулировка задачи:

Задано строку, которая представляет арифметическое выражение. Проверить корректность заданного выражения. Вычислить его.

Решение задачи: «Проверить корректность арифметического выражения, заданного строкой»

textual
Листинг программы
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <ctype.h>
  4. #include <string.h>
  5.  
  6. //коды ошибок
  7. enum err_expr {
  8.     ERR_SUCCESS,      //нет ошибки
  9.     ERR_NONE_STR,     //строка пуста
  10.     ERR_DIV_BYZERO,   //деление на нуль!
  11.     ERR_PARSE_NUMBER, //ошибка при парсирование числа
  12.     ERR_EXPR          //другие ошибки: скобки, иные символы...
  13.     //...
  14. };
  15. int    is_expr(const char* s);
  16. double _calc(const char* s, const char** p, enum err_expr* e);
  17.  
  18.  
  19. //вычисление мат-выражений из строки
  20. double calculate(char* s, enum err_expr* err){
  21.     char* a, *b;
  22.     enum  err_expr e = ERR_SUCCESS;
  23.     const char*    p = NULL;
  24.     double         n = 0.0;
  25.  
  26.     if(*s && is_expr(s)){
  27.         a = s;
  28.         while(*a && !isspace(*a))
  29.             ++a;
  30.         for(b = a; *a; *a = *(++b)){
  31.             if(! isspace(*b))
  32.                 ++a;
  33.         }
  34.  
  35.         if(*s)
  36.             n = _calc(s, &p, &e);
  37.         else
  38.             e = ERR_NONE_STR;
  39.     } else
  40.         e = (*s) ? ERR_EXPR : ERR_NONE_STR;
  41.  
  42.     if(err != NULL)
  43.         *err = e;
  44.     return n;
  45. }
  46.  
  47.  
  48. int main(void){
  49.     enum err_expr e;
  50.     char          s[256];
  51.     double        t, res;
  52.  
  53.     //1-ый пример
  54.     strcpy(s, "-(-(-(-(-(-(-(-(-(-0.5))))))) + 0.7))*5.123-(-(0.4*3.3/0.0001))/2.5");
  55.     t   =      -(-(-(-(-(-(-(-(-(-0.5))))))) + 0.7))*5.123-(-(0.4*3.3/0.0001))/2.5;
  56.     res = calculate(s, NULL);
  57.     printf("result: %lg\n",   res);
  58.     printf("test  : %lg\n\n", t);
  59.  
  60.     //2-ой пример
  61.     strcpy(s, "-1.4e+5 + (-2) * (-(-5.5 + 0.1234)*(-5.2 / 0.1234 + 9.9) + 0.333) / 0.5");
  62.     t   =      -1.4e+5 + (-2) * (-(-5.5 + 0.1234)*(-5.2 / 0.1234 + 9.9) + 0.333) / 0.5;
  63.     res = calculate(s, NULL);
  64.     printf("result: %lg\n",   res);
  65.     printf("test  : %lg\n\n", t);
  66.  
  67.     //3-ий пример
  68.     strcpy(s, "1. / 1000.0 * (-(-999.2-(-9.0e+3))+(-(0.5 + 5.5*200)/(-3.3) + 0.7) * 2.8)");
  69.     t    =     1. / 1000.0 * (-(-999.2-(-9.0e+3))+(-(0.5 + 5.5*200)/(-3.3) + 0.7) * 2.8);
  70.     res  = calculate(s, NULL);
  71.     printf("result: %lg\n",   res);
  72.     printf("test  : %lg\n\n", t);
  73.  
  74.     //4-ый пример с обработкой ошибок
  75.     strcpy(s, "10 * 2 / 0");
  76.     res = calculate(s, &e);
  77.     switch(e){
  78.     case ERR_SUCCESS:
  79.         printf("%lg\n\n", res);
  80.         break;
  81.     case ERR_NONE_STR:
  82.         puts("строка пуста");
  83.         break;
  84.     case ERR_DIV_BYZERO:
  85.         puts("деление на нуль!");
  86.         break;
  87.     case ERR_PARSE_NUMBER:
  88.         puts("ошибка при парсирование числа.");
  89.         break;
  90.     case ERR_EXPR:
  91.         puts("другая ошибка.");
  92.         break;
  93.     }
  94.     getchar();
  95.     return 0;
  96. }
  97.  
  98. //проверка скобок на правильность расстоновки
  99. int is_expr(const char* s){
  100.     int n = 0;
  101.     for(; *s; ++s){
  102.         if(*s == '(')
  103.             ++n;
  104.         else if(*s == ')'){
  105.             if(--n < 0)
  106.                 break;
  107.         }
  108.     }
  109.     return (n == 0);
  110. }
  111.  
  112. // рекурсивное вычисление мат-выражений из строки
  113. double  _calc(const char* s, const char** p, enum err_expr* e){
  114.     int    neg;
  115.     char   c, c1;
  116.     char*  i;
  117.     const char* o;
  118.     double k, v, n = 0.0;
  119.  
  120.     if((*s == '(') || (*s == '-' && *(s + 1) == '(')){
  121.         neg = (*s == '-');
  122.         n   = _calc(s + (1 + neg), &o, e);
  123.         if(*e != ERR_SUCCESS)
  124.             return 0.0;
  125.         s = o;
  126.         if(neg)
  127.             n = 0.0 - n;
  128.     } else {
  129.         n = strtod(s, &i);
  130.         if(s == i){
  131.             *e = ERR_PARSE_NUMBER;
  132.             return 0.0;
  133.         }
  134.         s = i;
  135.     }
  136.  
  137.     while(*s && (*s != ')')){
  138.         c = *s++;
  139.         if(! *s){
  140.             *e = ERR_EXPR;
  141.             return 0.0;
  142.         }
  143.  
  144.         if(*s == '('){
  145.             k = _calc(s + 1, &o, e);
  146.             if(*e != ERR_SUCCESS)
  147.                 return 0.0;
  148.             s = o;
  149.         } else {
  150.             k = strtod(s, &i);
  151.             if(s == i){
  152.                 *e = ERR_PARSE_NUMBER;
  153.                 return 0.0;
  154.             }
  155.             s = i;
  156.         }
  157.  
  158.         switch(c){
  159.         case '*':
  160.             n *= k;
  161.             break;
  162.         case '/':
  163.             if(k == 0.0){
  164.                 *e = ERR_DIV_BYZERO;
  165.                 return 0.0;
  166.             }
  167.             n /= k;
  168.             break;
  169.         case '+':
  170.         case '-':
  171.  
  172.             if((*s == '*') || (*s == '/')) {
  173.                 v = k;
  174.                 while(*s && (*s != ')')) {
  175.  
  176.                     c1 = *s;
  177.                     if((c1 == '+') || (c1 == '-'))
  178.                         break;
  179.                    
  180.                     ++s;
  181.                     if(*s == '('){
  182.                         k = _calc(s + 1, &o, e);
  183.                         if(*e != ERR_SUCCESS)
  184.                             return 0.0;
  185.                         s = o;
  186.                     } else {
  187.                         k = strtod(s, &i);
  188.                         if(s == i){
  189.                             *e = ERR_PARSE_NUMBER;
  190.                             return 0.0;
  191.                         }
  192.                         s = i;
  193.                     }
  194.  
  195.                     if(c1 == '/') {
  196.                         if(k == 0.0){
  197.                             *e = ERR_DIV_BYZERO;
  198.                             return 0.0;
  199.                         }
  200.                         v /= k;
  201.                     } else if(c1 == '*')
  202.                         v *= k;
  203.                 }
  204.                 k = v;
  205.             }
  206.  
  207.             if(c == '+')
  208.                 n += k;
  209.             else if(c == '-')
  210.                 n -= k;
  211.  
  212.             if(*s == ')'){
  213.                 *p = s + 1;
  214.                 return n;
  215.             }
  216.             break;
  217.         }
  218.     }
  219.  
  220.     if(*s == ')')
  221.         *p = s + 1;
  222.     return n;
  223. }

Объяснение кода листинга программы

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

  1. include - подключает стандартную библиотеку для ввода и вывода данных.

  2. include - подключает стандартную библиотеку для работы с числами.

  3. include - подключает стандартную библиотеку для работы со строками и символами.

  4. include - подключает стандартную библиотеку для работы со строками.

    Основная функция - это функция calculate, которая принимает строку с математическим выражением, указатель на переменную, в которую будет сохранено результат, и указатель на ошибку. Функция parse_number - это функция, которая преобразует строку в число. Код использует стек для обработки выражений. Когда функция is_expr проверяет, что выражение корректно, она создает стек для хранения операндов и операций. Когда она встречает операцию, она помещает ее на вершину стека, а затем продолжает работу с предыдущими операндами. Когда функция _calc встречает число, она вызывает функцию parse_number для преобразования строки в число, а затем добавляет это число в стек. Когда функция _calc встречает операцию, она проверяет, что стек не пуст, и затем выполняет операцию. Если происходит ошибка, она возвращает значение ошибки. Функция main - это точка входа в программу. Она демонстрирует использование калькулятора, вызывая функцию calculate для трех примеров. В первом примере она вычисляет выражение -(-(-5.5 + 0.1234)*(-5.2 / 0.1234 + 9.9) + 0.333) / 0.5. Во втором примере она вычисляет выражение -1.4e+5 + (-2) * (-(-5.5 + 0.1234)*(-5.2 / 0.1234 + 9.9) + 0.333) / 0.5. В третьем примере она вычисляет выражение 1. / 1000.0 * (-(-999.2-(-9.0e+3))+(-(0.5 + 5.5*200)/(-3.3) + 0.7) * 2.8). В третьем примере программа выдает ошибку, потому что деление на ноль невозможно. В четвертом примере программа выдает ошибку, потому что выражение 10 * 2 / 0 некорректно синтаксически.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

10   голосов , оценка 4 из 5

Нужна аналогичная работа?

Оформи быстрый заказ и узнай стоимость

Бесплатно
Оформите заказ и авторы начнут откликаться уже через 10 минут
Похожие ответы