diff --git a/du3/program.c b/du3/program.c new file mode 100644 index 0000000..e84d197 --- /dev/null +++ b/du3/program.c @@ -0,0 +1,280 @@ +#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; +}