pvjc22/du4/program.c
2022-05-01 12:50:52 +02:00

157 lines
9.3 KiB
C

#include <stdio.h> //pripojím si potrebné knižnice
#include <stdlib.h>
#include <string.h>
#define VELKOST_VSTUPU 50 //zadefinujem konštanty
#define POCET_CISEL 500
int najdiNepovoleneZnaky(char* vstup); //inicializujem vlastné funkcie
char priklad(char *vstup, float *prveCislo, float *druheCislo, float *zadanyVysledok);
int kontrolaViacnasobnejOperacie(char* priklad, char matematickaOperacia, float* prveCislo, float* druheCislo, float* zadanyVysledok);
float vypocitaj(float cislo1, float cislo2, char matematickaOperacia);
void mazanie_znakov_v_retazci(char* vstup, char nepotrebnyZnak);
int main() {
int pocetRiadkov, i, obsahNepovolenychZnakov;
float prveCisla[POCET_CISEL]; //inicializujem polia, do ktorých budem ukladať potrebné čísla
float druheCisla[POCET_CISEL];
float vysledky[POCET_CISEL];
float kontrolneVysledky[POCET_CISEL];
memset(prveCisla, 0, POCET_CISEL * sizeof(float)); //vykonám počiatočnú inicializáciu pamäte
memset(druheCisla, 0, POCET_CISEL * sizeof(float));
memset(vysledky, 0, POCET_CISEL * sizeof(float));
memset(kontrolneVysledky, 0, POCET_CISEL * sizeof(float));
int chybovyStav[POCET_CISEL]; //do poľa budem ukladať záznam o správnosti formátu príkladu
memset(chybovyStav, 0, POCET_CISEL * sizeof(int));
char vstup[VELKOST_VSTUPU]; //inicializujem polia pre načítanie príkladov
char* stav_vstupu;
char matematickaOperacia; //do pamäte si individuálne zapíšem aritmetickú operáciu príkladu
for (i = 0; i < POCET_CISEL; i++) { //v cykle budem načítavať príklady
stav_vstupu = fgets(vstup, VELKOST_VSTUPU, stdin); //načítam príklad
if (stav_vstupu == NULL) return 0; //skontrolujem, či sa mi príklad podarilo úspešne načítať a ak nie, tak program ukončím
else if (strcmp(vstup, "\n") == 0) break;
mazanie_znakov_v_retazci(vstup, ' '); //zo zadaného príkladu odstránom všetky medzery zadané pri vstupe
obsahNepovolenychZnakov = najdiNepovoleneZnaky(vstup); //skontrolujem, či používateľ nazadal do príkladu nepovolené znaky
if (obsahNepovolenychZnakov == EXIT_FAILURE) chybovyStav[i] = obsahNepovolenychZnakov; //ak ich zadal, tak informáciu o danej skutočnosti zaznamená do poľa s výsledkami
else {
matematickaOperacia = priklad(vstup, &prveCisla[i], &druheCisla[i], &vysledky[i]); //v príklade vyhľadám príslušnú aritmetickú operáciu
obsahNepovolenychZnakov = kontrolaViacnasobnejOperacie(vstup, matematickaOperacia, &prveCisla[i], &druheCisla[i], &vysledky[i]); //následne ešte skontrolujem to, či bol príklad zadaný v správnom formáte
if (obsahNepovolenychZnakov == EXIT_FAILURE) chybovyStav[i] = obsahNepovolenychZnakov; //ak je príklad zapísaný v nesprávnom formáte, tak program ukončím
else if (matematickaOperacia == '/' && *druheCisla == 0) chybovyStav[i] = EXIT_FAILURE;
else kontrolneVysledky[i] = vypocitaj(prveCisla[i], druheCisla[i], matematickaOperacia); //vyčíslim skutočnú hodnotu príkladu
}
}
pocetRiadkov = i; //uložím si hodnotu načítaných vstupov, pretože nemusím zakaždým využiť celú pamäť a to potom môže spôsobiť nepredvidateľné správanie programu
for (i = 0; i < pocetRiadkov; i++) {
if (chybovyStav[i] == EXIT_FAILURE) printf("CHYBA\n");
else if (kontrolneVysledky[i] == vysledky[i]) printf("OK\n");
else printf("ZLE\n");
}
return 0;
}
int najdiNepovoleneZnaky(char* vstup) { //funkcia kontroluje výskyt nepovolených znakov v zadanom príklade
char nepovoleneZnaky[] = "abcdefghijklmnopqrstuvwxyz&\\|()°;ľščťžýáíéúäô§!_.:,?<>€ĐŁł[]{}&@#"; //vytvorím zoznam nepovoelných znakov
int pocetNepovolenychZnakov = strlen(nepovoleneZnaky), j; //zadefinujem si potrebné premenné a zistím počet nepovolených znakov
for (j = 0; j <= pocetNepovolenychZnakov - 1; j++) { //v cykle skontrolujem, či sa v zadanom príklade nachádza niektorý z nepovolených znakov
if (strchr(vstup, nepovoleneZnaky[j]) != NULL) return EXIT_FAILURE; //ak sa v príklade nachádza niektorý z nepovolených znakov, tak vrátim EXIT_FAILURE
}
return EXIT_SUCCESS; //inak vrátim EXIT_SUCCESS
}
char priklad(char* vstup, float *prveCislo, float *druheCislo, float *zadanyVysledok) { //funkcia načíta čísla do jednotlivých polí podľa príslušnosti a vypočíta kontrolných výsledok
char matematickaOperacia, rovnaSa;
sscanf(vstup, "%f %c %f %c %f", &*prveCislo, &matematickaOperacia, &*druheCislo, &rovnaSa, &*zadanyVysledok);
return matematickaOperacia;
}
int kontrolaViacnasobnejOperacie(char* priklad, char matematickaOperacia, float* prveCislo, float* druheCislo, float* zadanyVysledok) { //funkcia skontroluje viacnásobný výskyt nájdenej aritmetickej operácie, operácie = a výskytu iných predtým nezachytených nepovolených znakov iných operácií
int pocetRovnaSa = 0, pocetMatematickejOperacie = 0, h, pocetMinus = 0; //nainicializujem potrebné premenné
const int DLZKA_PRIKLADU = strlen(priklad); //dĺžka príkladu bude konštantná
for (h = 0; h < DLZKA_PRIKLADU; h++) { //skontrolujem, či sa nájdená matematická operácia a znamienko = nenachádzajú v príklade viackrát
if (priklad[h] == matematickaOperacia) pocetMatematickejOperacie++; //ak sa nachádza niektorí zo znakov v príklade, tak ho započítam do príslušnej premennej
else if (priklad[h] == '=') pocetRovnaSa++;
}
if (matematickaOperacia == '-') { //ak bude zadanou matematickou operáciou -, tak skontrolujem počet výskytov záporných čísel (operácia sa vyskytuje v príklade viackrát)
if (*prveCislo < 0) pocetMinus++; //ak nájdené číslo je záporné, tak ho započítam
if (matematickaOperacia == '-') pocetMinus++; //ak nájdem operáciu -, tak ju tiež započítam, pretože menšiteľ je v pamäti interpretovaný ako kladné číslo
if (*druheCislo < 0) pocetMinus++;
if (*zadanyVysledok < 0) pocetMinus++;
}
if (pocetMinus != 0) { //ak som našiel nejaké záporné číslo pri odčítaní
if (pocetMatematickejOperacie != pocetMinus) return EXIT_FAILURE; //skontrolujem, či sa počet záporných čísel v príklade (reťazci) zhoduje s počtom načítaných záporných čísel a ak sa nezhoduje, tak vrátim EXIT_FAILURE
if (pocetMinus > 3) return EXIT_FAILURE; //ak sa budú v príklade vyskytovať viac ako 3 záporné čísla, tak príklad nie je zadaný v požadovanom formáte a vrátim EXIT_FAILURE
} else {
if (pocetMatematickejOperacie != 1) return EXIT_FAILURE; //(platí pre ostatné operácie) ak sa daná matematická operácia vyskytuje v príklade viackrát, tak vrátim EXIT_FAILURE, pretože príklad nie je zapísaný v požadovanom formáte
}
if (pocetRovnaSa != 1) return EXIT_FAILURE; //ak sa v príklade nachádza viac ako 1 rovná sa, tak vrátim EXIT_FAILURE, pretože príklad nie je zadaný v požadovanom formáte
char matematickeOperacie[] = "+-*/"; //vytvorím zoznam matematických operácií
const int POCET_MATEMATICKYCH_OPERACII = strlen(matematickeOperacie); //a zistím ich počet
for (h = 0; h < POCET_MATEMATICKYCH_OPERACII; h++) { //skontrolujem, či sa okrem prvotne nájdenej matematickej operácie v príklade nenachádzajú aj iné matematické operácie
if (matematickeOperacie[h] == matematickaOperacia) continue; //ak sa hľadaná matematická operácia zhoduje s prvotne nájdenou matematickou operáciou, tak jej hľadanie preskočím, pretože kontrola tejto operácie už prebehla
if (strchr(priklad, matematickeOperacie[h]) != NULL) { //ak sa v príklade vyskytuje iná matematická operácia
if (matematickeOperacie[h] == '-') { //ak je danou operáciou -, tak skontrolujem, či niektoré zo zadaných čísel nie je záporné
if (*prveCislo < 0) continue; //ak je niektoré z čísel záporné, tak kontrolu preskočím
if (*druheCislo < 0) continue;
if (*zadanyVysledok < 0) continue;
else return EXIT_FAILURE; //ak ani jedno z čísel nie je záporné, tak vrátim EXIT_FAILURE, pretože príklad nie je zadaný v príslušnom formáte
}
else return EXIT_FAILURE; //inak vrátim EXIT_FAILURE, pretože príklad nie je zadaný v príslušnom formáte
}
}
return EXIT_SUCCESS; //ak kontrola prebehla úspešne, tak vrátim stavové hlásenie EXIT_SUCCESS
}
float vypocitaj(float cislo1, float cislo2, char matematickaOperacia) { //funkcia spočíta dve čísla podľa zvolenej matematickej operácie
switch (matematickaOperacia) { //switch zvolí podľa zadanej matematickej operácie
case '+': return cislo1 + cislo2;
break;
case '-': return cislo1 - cislo2;
break;
case '*': return cislo1 * cislo2;
break;
case '/': return cislo1 / cislo2;
break;
default: return EXIT_FAILURE; //ošetrenie pre prípad, že používateľ nezadá ako parameter matematickú operáciu
}
}
void mazanie_znakov_v_retazci(char* vstup1, char nepotrebnyZnak) { //funkcia vyhľadá v reťazci hľadaný znak a vymaže ho
int l, m, dlzkaRetazca = strlen(vstup1); //nainicializujem si potrebné premenné
for (l = 0; l < dlzkaRetazca; l++) { //prejdem celý reťazec znak po znaku
if (vstup1[l] == nepotrebnyZnak) { //ak nájdem v reťazci znak, ktorý má byť odstránený
for (m = l; m < dlzkaRetazca; m++) vstup1[m] = vstup1[m + 1]; //tak začnem posúvať o 1 miesto naspäť reťazec od aktuálnej pozície
dlzkaRetazca--; //skrátim ho odstránený znak
l--; //nastavím presúvač na pôvodnú pozíciu v rámci reťazca (cyklu)
}
}
}