#include #include #include #include #include #define EPSILON 0.001 // Tolerancia pre porovnanie reálnych čísel: ak rozdiel dvoch čísel je menší alebo rovný EPSILON, považujeme ich za rovnaké. /* * Funkcia trim_newline * -------------------- * Odstraňuje znak nového riadku ('\n') zo zadaného reťazca, ak je prítomný. * Táto funkcia je užitočná, keď načítavame riadky pomocou fgets, * pretože fgets zachytáva aj znak nového riadku, ktorý by mohol narušiť parsovanie. * * Parametre: * - line: reťazec, z ktorého chceme odstrániť koncový znak nového riadku. * * Príklad použitia: * char buffer[256]; * fgets(buffer, sizeof(buffer), stdin); * trim_newline(buffer); // Odstráni '\n' na konci, ak existuje. */ void trim_newline(char *line) { size_t len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\0'; } } /* * Funkcia skip_spaces * -------------------- * Preskakuje všetky whitespace znaky (medzery, tabulátory, nové riadky) v zadanom reťazci * a vráti ukazovateľ na prvý znak, ktorý nie je whitespace. * * Parametre: * - str: reťazec, v ktorom chceme preskočiť medzery. * * Návratová hodnota: * - Ukazovateľ na prvý znak, ktorý nie je medzera. */ char* skip_spaces(char *str) { while(*str && isspace((unsigned char)*str)) { str++; } return str; } /* * Funkcia parse_expression * ------------------------- * Rozparsuje riadok obsahujúci matematický príklad vo formáte: * * ČÍSLO OPERÁCIA ČÍSLO = VÝSLEDOK * * Medzi jednotlivými časťami môže byť ľubovoľný počet medzier. * * Parametre: * - line: Reťazec obsahujúci matematický príklad, napr. "1.1 + 2.2 = 3.3" * - num1: Ukazovateľ, do ktorého sa uloží prvé číslo. * - op: Ukazovateľ, do ktorého sa uloží operátor ('+', '-', '*' alebo '/'). * - num2: Ukazovateľ, do ktorého sa uloží druhé číslo. * - result: Ukazovateľ, do ktorého sa uloží očakávaný výsledok. * * Návratová hodnota: * - 0, ak sa parsovanie podarilo úspešne. * - 1, ak nastala chyba (napr. nesprávny formát, chýbajúce číslo, operátor alebo '=') * * Príklad vstupu: * " 10.0 / 2.0 = 5.0" */ int parse_expression(char *line, float *num1, char *op, float *num2, float *result) { char *ptr = line; // Preskočíme úvodné medzery a načítame prvé číslo ptr = skip_spaces(ptr); char *endPtr; *num1 = strtof(ptr, &endPtr); if (ptr == endPtr) { return 1; // Chyba: nepodarilo sa načítať číslo } ptr = endPtr; // Preskočíme medzery a načítame operátor ptr = skip_spaces(ptr); if (*ptr == '\0') return 1; *op = *ptr; if (*op != '+' && *op != '-' && *op != '*' && *op != '/') { return 1; // Chyba: operátor nie je platný } ptr++; // Preskočíme medzery a načítame druhé číslo ptr = skip_spaces(ptr); *num2 = strtof(ptr, &endPtr); if (ptr == endPtr) { return 1; // Chyba: nepodarilo sa načítať druhé číslo } ptr = endPtr; // Preskočíme medzery a očakávame znak '=' ptr = skip_spaces(ptr); if (*ptr != '=') { return 1; // Chyba: chýba znak '=' } ptr++; // Preskočíme '=' // Preskočíme medzery a načítame výsledok ptr = skip_spaces(ptr); *result = strtof(ptr, &endPtr); if (ptr == endPtr) { return 1; // Chyba: nepodarilo sa načítať výsledok } ptr = endPtr; // Overíme, že za výsledkom nie sú žiadne neočakávané znaky (okrem medzier) ptr = skip_spaces(ptr); if (*ptr != '\0') { return 1; // Chyba: neočakávané znaky za výsledkom } return 0; // Úspešné parsovanie } /* * Funkcia calculate * ----------------- * Vykoná aritmetickú operáciu medzi dvoma číslami podľa zadaného operátora. * * Parametre: * - num1: Prvé číslo. * - op: Operátor, ktorý môže byť '+', '-', '*' alebo '/'. * - num2: Druhé číslo. * - error: Ukazovateľ na premennú, do ktorej sa uloží 1, ak nastane chyba (napr. delenie nulou). * * Návratová hodnota: * - Výsledok operácie, ak prebehne úspešne. * - V prípade chyby (napr. delenie nulou) sa error nastaví na 1 a funkcia vráti 0. * * Príklad: * calculate(10.0, '/', 2.0, &error) vráti 5.0, pričom error zostáva 0. */ float calculate(float num1, char op, float num2, int *error) { *error = 0; // Inicializácia chyby na 0 (žiadna chyba) float res; switch(op) { case '+': res = num1 + num2; break; case '-': res = num1 - num2; break; case '*': res = num1 * num2; break; case '/': // Pred delením overíme, či nedochádza k deleniu nulou if (fabs(num2) < EPSILON) { *error = 1; return 0; } res = num1 / num2; break; default: *error = 1; return 0; } return res; } /* * Funkcia process_line * --------------------- * Spracuje jeden riadok vstupu obsahujúci matematický príklad a určí, či je príklad * zapísaný správne a či je výsledok správny. Výsledok sa uloží do parametra output. * * Postup: * 1. Skopíruje vstupný riadok do lokálneho bufferu a odstráni prípadný koncový znak nového riadku. * 2. Ak riadok obsahuje iba medzery, nastaví output na "KONIEC". * 3. Pokúsi sa rozparsovať riadok na jednotlivé časti: prvé číslo, operátor, druhé číslo a výsledok. * 4. Ak parsovanie zlyhá, nastaví output na "CHYBA". * 5. Ak ide o delenie nulou, tiež nastaví output na "CHYBA". * 6. Vykoná operáciu a porovná vypočítaný výsledok so zadaným výsledkom s toleranciou EPSILON. * - Ak sa výsledok zhoduje, nastaví output na "OK". * - Ak sa výsledok nezhoduje, nastaví output na "ZLE". * * Parametre: * - line: Vstupný riadok (napr. "10.0 / 2.0 = 5.0"). * - output: Buffer, do ktorého sa uloží výsledný reťazec ("OK", "ZLE", "CHYBA" alebo "KONIEC"). * - output_size: Veľkosť bufferu output. * * Príklad vstupu a výstupu: * Vstup: "1+2=3" * Výstup: "OK" */ void process_line(const char *line, char *output, size_t output_size) { char buffer[256]; strncpy(buffer, line, 255); buffer[255] = '\0'; // Zabezpečíme, že buffer je správne zakončený '\0' trim_newline(buffer); // Ak riadok obsahuje iba medzery, nastavíme výstup na "KONIEC" char *tmp = skip_spaces(buffer); if (*tmp == '\0') { snprintf(output, output_size, "KONIEC"); return; } float num1, num2, givenResult; char op; // Pokúsime sa rozparsovať matematický príklad if (parse_expression(buffer, &num1, &op, &num2, &givenResult) != 0) { snprintf(output, output_size, "CHYBA"); return; } // Overenie delenia nulou: ak ide o delenie a menovateľ je nulový, nastane chyba if (op == '/' && fabs(num2) < EPSILON) { snprintf(output, output_size, "CHYBA"); return; } int calcError = 0; float calculatedResult = calculate(num1, op, num2, &calcError); if (calcError) { snprintf(output, output_size, "CHYBA"); return; } // Porovnáme vypočítaný výsledok so zadaným výsledkom // Ak je absolútny rozdiel menší alebo rovný EPSILON, výsledok považujeme za správny if (fabs(calculatedResult - givenResult) <= EPSILON) { snprintf(output, output_size, "OK"); } else { snprintf(output, output_size, "ZLE"); } } /* * Hlavná funkcia programu. * ------------------------- * Tento program načíta riadky zo štandardného vstupu. Každý riadok obsahuje matematický príklad vo formáte: * * ČÍSLO OPERÁCIA ČÍSLO = VÝSLEDOK * * Príklad vstupu: * 10.0 / 2.0 = 5.0 * 1+2=3 * 3.333+4.667=8.0 * [prázdny riadok] // Po načítaní prázdneho riadku program vypíše "KONIEC" a ukončí sa. * * Pre každý riadok program vypíše na štandardný výstup: * OK - ak je výsledok správny * ZLE - ak je výsledok nesprávny * CHYBA - ak je riadok zle zapísaný alebo nastala chyba (napr. delenie nulou) * KONIEC - ak je riadok prázdny * * Ako spustiť program: * - Kompilujte: gcc program.c -o program -lm * - Spustite: ./program */ int main(int argc, char *argv[]) { char buffer[256]; char output[32]; // Načítavame riadky zo štandardného vstupu (napr. z konzoly alebo súboru) while (fgets(buffer, sizeof(buffer), stdin) != NULL) { trim_newline(buffer); process_line(buffer, output, sizeof(output)); printf("%s\n", output); // Ak je vstup prázdny (obsahuje iba medzery), ukončíme program char *tmp = skip_spaces(buffer); if (*tmp == '\0') { break; } } return 0; }