#include #include #include #include #include #define EPSILON 0.001 // Tolerancia pre porovnanie reálnych čísel: ak je rozdiel menší alebo rovný EPSILON, považujeme čísla za rovnaké. /* * Funkcia trim_newline * -------------------- * Odstraňuje znak nového riadku ('\n') zo zadaného reťazca, ak je prítomný. * Pri načítavaní riadkov pomocou fgets sa totiž často na konci reťazca nachádza '\n', * ktorý by mohol ovplyvniť ďalšie spracovanie. * * Parametre: * - line: Reťazec, z ktorého sa má odstrániť koncový znak nového riadku. */ 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 whitespace. */ 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 (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 ('+', '-', '*' alebo '/'). * - num2: Druhé číslo. * - error: Ukazovateľ, do ktorého sa uloží 1, ak nastane chyba (napr. delenie nulou). * * Návratová hodnota: * - Výsledok operácie, ak prebehne úspešne. * - Ak nastane chyba, error je nastavený na 1 a funkcia vráti 0. * * Príklad: * calculate(10.0, '/', 2.0, &error) vráti 5.0, 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 '/': // Kontrola delenia nulou; ak num2 je takmer 0, signalizujeme chybu if (fabs(num2) < EPSILON) { *error = 1; // Chyba: delenie nulou 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 zápis * správny a či je výsledok správny. * * Postup: * 1. Skopíruje vstupný riadok do lokálneho bufferu a odstráni prípadný koncový znak nového riadku. * 2. Rozparsuje riadok na časti: prvé číslo, operátor, druhé číslo a očakávaný výsledok. * 3. Ak parsovanie zlyhá, nastaví output na "CHYBA". * 4. Vykoná operáciu a ak nastane chyba (napr. delenie nulou), nastaví output na "ZLE". * 5. Zaokrúhli výsledok operácie na 2 desatinné miesta, pretože čísla sú zadané na max. 2 desatinné miesta. * 6. Porovná zaokrúhlený výsledok s očakávaným výsledkom. Ak sa líšia o viac ako EPSILON, * nastaví output na "ZLE", inak na "OK". * * Parametre: * - line: Vstupný riadok (napr. "10.0 / 2.0 = 5.0"). * - output: Buffer, do ktorého sa uloží výsledný reťazec ("OK", "ZLE" alebo "CHYBA"). * - output_size: Veľkosť bufferu output. * * Príklad vstupu a výstupu: * Vstup: "1 + 1 = 2" * Výstup: "OK" */ void process_line(const char *line, char *output, size_t output_size) { char buffer[256]; // Skopírujeme vstupný riadok do lokálneho bufferu strncpy(buffer, line, 255); buffer[255] = '\0'; // Zabezpečíme, že buffer je správne zakončený '\0' trim_newline(buffer); 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; } int calcError = 0; float calculatedResult = calculate(num1, op, num2, &calcError); if (calcError) { // V prípade chyby (napr. delenie nulou) vypíšeme "ZLE" snprintf(output, output_size, "ZLE"); return; } // Zaokrúhľujeme výsledok operácie na 2 desatinné miesta, pretože vstupné čísla majú max. 2 desatinné miesta. float roundedResult = round(calculatedResult * 100) / 100; // Porovnáme zaokrúhlený výsledok so zadaným výsledkom. if (fabs(roundedResult - givenResult) <= EPSILON) { snprintf(output, output_size, "OK"); } else { snprintf(output, output_size, "ZLE"); } } /* * Hlavná funkcia programu. * ------------------------- * 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 * * Pre každý neprázdny riadok program overí správnosť zápisu a výsledku a na štandardný výstup * vypíše "OK", "ZLE" alebo "CHYBA". * * Ak sa načíta prázdny riadok (iba medzery), program sa ukončí. * * Ako skompilovať: * gcc program.c -o program -lm * * Ako spustiť: * ./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); // Ak je riadok prázdny (iba medzery), ukončíme cyklus a program if (*skip_spaces(buffer) == '\0') { break; } process_line(buffer, output, sizeof(output)); printf("%s\n", output); } return 0; }