Проверить корректность арифметического выражения, заданного строкой - C (СИ)
Формулировка задачи:
Решение задачи: «Проверить корректность арифметического выражения, заданного строкой»
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> //коды ошибок enum err_expr { ERR_SUCCESS, //нет ошибки ERR_NONE_STR, //строка пуста ERR_DIV_BYZERO, //деление на нуль! ERR_PARSE_NUMBER, //ошибка при парсирование числа ERR_EXPR //другие ошибки: скобки, иные символы... //... }; int is_expr(const char* s); double _calc(const char* s, const char** p, enum err_expr* e); //вычисление мат-выражений из строки double calculate(char* s, enum err_expr* err){ char* a, *b; enum err_expr e = ERR_SUCCESS; const char* p = NULL; double n = 0.0; if(*s && is_expr(s)){ a = s; while(*a && !isspace(*a)) ++a; for(b = a; *a; *a = *(++b)){ if(! isspace(*b)) ++a; } if(*s) n = _calc(s, &p, &e); else e = ERR_NONE_STR; } else e = (*s) ? ERR_EXPR : ERR_NONE_STR; if(err != NULL) *err = e; return n; } int main(void){ enum err_expr e; char s[256]; double t, res; //1-ый пример strcpy(s, "-(-(-(-(-(-(-(-(-(-0.5))))))) + 0.7))*5.123-(-(0.4*3.3/0.0001))/2.5"); t = -(-(-(-(-(-(-(-(-(-0.5))))))) + 0.7))*5.123-(-(0.4*3.3/0.0001))/2.5; res = calculate(s, NULL); printf("result: %lg\n", res); printf("test : %lg\n\n", t); //2-ой пример strcpy(s, "-1.4e+5 + (-2) * (-(-5.5 + 0.1234)*(-5.2 / 0.1234 + 9.9) + 0.333) / 0.5"); t = -1.4e+5 + (-2) * (-(-5.5 + 0.1234)*(-5.2 / 0.1234 + 9.9) + 0.333) / 0.5; res = calculate(s, NULL); printf("result: %lg\n", res); printf("test : %lg\n\n", t); //3-ий пример strcpy(s, "1. / 1000.0 * (-(-999.2-(-9.0e+3))+(-(0.5 + 5.5*200)/(-3.3) + 0.7) * 2.8)"); t = 1. / 1000.0 * (-(-999.2-(-9.0e+3))+(-(0.5 + 5.5*200)/(-3.3) + 0.7) * 2.8); res = calculate(s, NULL); printf("result: %lg\n", res); printf("test : %lg\n\n", t); //4-ый пример с обработкой ошибок strcpy(s, "10 * 2 / 0"); res = calculate(s, &e); switch(e){ case ERR_SUCCESS: printf("%lg\n\n", res); break; case ERR_NONE_STR: puts("строка пуста"); break; case ERR_DIV_BYZERO: puts("деление на нуль!"); break; case ERR_PARSE_NUMBER: puts("ошибка при парсирование числа."); break; case ERR_EXPR: puts("другая ошибка."); break; } getchar(); return 0; } //проверка скобок на правильность расстоновки int is_expr(const char* s){ int n = 0; for(; *s; ++s){ if(*s == '(') ++n; else if(*s == ')'){ if(--n < 0) break; } } return (n == 0); } // рекурсивное вычисление мат-выражений из строки double _calc(const char* s, const char** p, enum err_expr* e){ int neg; char c, c1; char* i; const char* o; double k, v, n = 0.0; if((*s == '(') || (*s == '-' && *(s + 1) == '(')){ neg = (*s == '-'); n = _calc(s + (1 + neg), &o, e); if(*e != ERR_SUCCESS) return 0.0; s = o; if(neg) n = 0.0 - n; } else { n = strtod(s, &i); if(s == i){ *e = ERR_PARSE_NUMBER; return 0.0; } s = i; } while(*s && (*s != ')')){ c = *s++; if(! *s){ *e = ERR_EXPR; return 0.0; } if(*s == '('){ k = _calc(s + 1, &o, e); if(*e != ERR_SUCCESS) return 0.0; s = o; } else { k = strtod(s, &i); if(s == i){ *e = ERR_PARSE_NUMBER; return 0.0; } s = i; } switch(c){ case '*': n *= k; break; case '/': if(k == 0.0){ *e = ERR_DIV_BYZERO; return 0.0; } n /= k; break; case '+': case '-': if((*s == '*') || (*s == '/')) { v = k; while(*s && (*s != ')')) { c1 = *s; if((c1 == '+') || (c1 == '-')) break; ++s; if(*s == '('){ k = _calc(s + 1, &o, e); if(*e != ERR_SUCCESS) return 0.0; s = o; } else { k = strtod(s, &i); if(s == i){ *e = ERR_PARSE_NUMBER; return 0.0; } s = i; } if(c1 == '/') { if(k == 0.0){ *e = ERR_DIV_BYZERO; return 0.0; } v /= k; } else if(c1 == '*') v *= k; } k = v; } if(c == '+') n += k; else if(c == '-') n -= k; if(*s == ')'){ *p = s + 1; return n; } break; } } if(*s == ')') *p = s + 1; return n; }
Объяснение кода листинга программы
Этот код - это математический калькулятор, который проверяет и вычисляет выражения, заданные в виде строк. Он поддерживает основные арифметические операции, а также скобки для группировки выражений. Код также проверяет ошибки, такие как деление на ноль и неправильное использование скобок. Синтаксис кода:
-
include
- подключает стандартную библиотеку для ввода и вывода данных. -
include
- подключает стандартную библиотеку для работы с числами. -
include
- подключает стандартную библиотеку для работы со строками и символами. -
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
некорректно синтаксически.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д