2025-03-12 17:32:46 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
2025-03-12 17:38:46 +00:00
|
|
|
#define EPSILON 0.001 // Tolerancia pre porovnanie reálnych čísel: ak je rozdiel dvoch čísel menší alebo rovný EPSILON, považujeme ich za rovnaké.
|
2025-03-12 17:32:46 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Funkcia trim_newline
|
|
|
|
* --------------------
|
|
|
|
* Odstraňuje znak nového riadku ('\n') zo zadaného reťazca, ak je prítomný.
|
2025-03-12 17:38:46 +00:00
|
|
|
* Pri načítavaní riadkov pomocou fgets sa totiž často na konci reťazca nachádza '\n',
|
|
|
|
* ktorý by mohol ovplyvniť ďalšie spracovanie.
|
2025-03-12 17:32:46 +00:00
|
|
|
*
|
|
|
|
* Parametre:
|
2025-03-12 17:38:46 +00:00
|
|
|
* - line: Reťazec, z ktorého sa má odstrániť koncový znak nového riadku.
|
2025-03-12 17:32:46 +00:00
|
|
|
*/
|
|
|
|
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:
|
2025-03-12 17:38:46 +00:00
|
|
|
* - str: Reťazec, v ktorom chceme preskočiť medzery.
|
2025-03-12 17:32:46 +00:00
|
|
|
*
|
|
|
|
* Návratová hodnota:
|
2025-03-12 17:38:46 +00:00
|
|
|
* - Ukazovateľ na prvý znak, ktorý nie je whitespace.
|
2025-03-12 17:32:46 +00:00
|
|
|
*/
|
|
|
|
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) {
|
2025-03-12 17:43:59 +00:00
|
|
|
*error = 1; // Chyba: delenie nulou
|
2025-03-12 17:32:46 +00:00
|
|
|
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.
|
2025-03-12 17:38:46 +00:00
|
|
|
* 2. Predpokladá sa, že riadok nie je prázdny (kontrola prázdnoty sa vykoná v main).
|
2025-03-12 17:32:46 +00:00
|
|
|
* 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".
|
2025-03-12 17:43:59 +00:00
|
|
|
* 5. Vykoná operáciu a porovná vypočítaný výsledok so zadaným výsledkom s toleranciou EPSILON.
|
2025-03-12 17:32:46 +00:00
|
|
|
* - Ak sa výsledok zhoduje, nastaví output na "OK".
|
|
|
|
* - Ak sa výsledok nezhoduje, nastaví output na "ZLE".
|
2025-03-12 17:43:59 +00:00
|
|
|
* 6. V prípade delenia nulou, keď calculate vráti chybu, program nastaví output na "ZLE".
|
2025-03-12 17:32:46 +00:00
|
|
|
*
|
|
|
|
* Parametre:
|
|
|
|
* - line: Vstupný riadok (napr. "10.0 / 2.0 = 5.0").
|
2025-03-12 17:38:46 +00:00
|
|
|
* - output: Buffer, do ktorého sa uloží výsledný reťazec ("OK", "ZLE" alebo "CHYBA").
|
2025-03-12 17:32:46 +00:00
|
|
|
* - output_size: Veľkosť bufferu output.
|
|
|
|
*
|
|
|
|
* Príklad vstupu a výstupu:
|
2025-03-12 17:38:46 +00:00
|
|
|
* Vstup: "1 + 1 = 2"
|
2025-03-12 17:32:46 +00:00
|
|
|
* Výstup: "OK"
|
|
|
|
*/
|
|
|
|
void process_line(const char *line, char *output, size_t output_size) {
|
|
|
|
char buffer[256];
|
2025-03-12 17:38:46 +00:00
|
|
|
// Skopírujeme vstupný riadok do lokálneho bufferu
|
2025-03-12 17:32:46 +00:00
|
|
|
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) {
|
2025-03-12 17:43:59 +00:00
|
|
|
// V prípade delenia nulou (alebo inej chyby v calcultion) vypíšeme "ZLE"
|
|
|
|
snprintf(output, output_size, "ZLE");
|
2025-03-12 17:32:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-03-12 17:38:46 +00:00
|
|
|
// Porovnáme vypočítaný výsledok so zadaným výsledkom.
|
|
|
|
// Ak je absolútny rozdiel menší alebo rovný EPSILON, považujeme príklad za správny.
|
2025-03-12 17:32:46 +00:00
|
|
|
if (fabs(calculatedResult - givenResult) <= EPSILON) {
|
|
|
|
snprintf(output, output_size, "OK");
|
|
|
|
} else {
|
|
|
|
snprintf(output, output_size, "ZLE");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Hlavná funkcia programu.
|
|
|
|
* -------------------------
|
2025-03-12 17:38:46 +00:00
|
|
|
* Program načíta riadky zo štandardného vstupu. Každý riadok obsahuje matematický príklad vo formáte:
|
2025-03-12 17:32:46 +00:00
|
|
|
*
|
|
|
|
* ČÍSLO OPERÁCIA ČÍSLO = VÝSLEDOK
|
|
|
|
*
|
|
|
|
* Príklad vstupu:
|
|
|
|
* 10.0 / 2.0 = 5.0
|
|
|
|
* 1+2=3
|
|
|
|
* 3.333+4.667=8.0
|
|
|
|
*
|
2025-03-12 17:38:46 +00:00
|
|
|
* Program pre každý neprázdny riadok overí správnosť zápisu a výsledku a na štandardný výstup
|
|
|
|
* vypíše "OK", "ZLE" alebo "CHYBA".
|
|
|
|
*
|
|
|
|
* Poznámka: Ak sa načíta prázdny riadok (obsahuje iba medzery), program ho ignoruje a ukončí sa.
|
|
|
|
*
|
|
|
|
* Ako skompilovať:
|
|
|
|
* gcc program.c -o program -lm
|
2025-03-12 17:32:46 +00:00
|
|
|
*
|
2025-03-12 17:38:46 +00:00
|
|
|
* Ako spustiť:
|
|
|
|
* ./program
|
2025-03-12 17:32:46 +00:00
|
|
|
*/
|
|
|
|
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);
|
2025-03-12 17:38:46 +00:00
|
|
|
// Ak je riadok prázdny (iba medzery), ukončíme cyklus a teda program
|
|
|
|
if (*skip_spaces(buffer) == '\0') {
|
2025-03-12 17:32:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2025-03-12 17:38:46 +00:00
|
|
|
process_line(buffer, output, sizeof(output));
|
|
|
|
printf("%s\n", output);
|
2025-03-12 17:32:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2025-03-12 17:43:59 +00:00
|
|
|
}
|