Last active
January 17, 2021 13:51
-
-
Save ericek111/6869f8e0bb540a6e20a56387ab6172d8 to your computer and use it in GitHub Desktop.
volakoho domaca uloha
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ctype.h> | |
#include <errno.h> | |
#include <stdio.h> | |
#include <stdbool.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <string.h> | |
#define MAX_WORD_LEN 20 | |
// gcc -o naruby naruby.c | |
int main(int argc, char const *argv[]) { | |
// 20 znakov + znamienko + null terminator treba pre zapis int64_t | |
// pre citanie poctu mozeme pouzit jeden buffer, netreba plytvat | |
#if MAX_WORD_LEN < 22 | |
char word[22]; | |
#else | |
// nikdy nebudeme buffer pouzivat ako string, ale len ako stack, | |
// cize LIFO (last in, first out) buffer, *word je spodok zasobnika | |
char word[MAX_WORD_LEN]; | |
#endif | |
// ocakavany pocet slov na vstupe | |
long words = 0; | |
// pomocna premenna pri zahadzovani odpadu | |
char chr; | |
/* precitaj riadok s poctom slovicok | |
* pozor, fgets precita aj newline na konci. pre strtol to nevadi. | |
* ak v bufferi nebude newline, znamena to, ze sa cislo nezmestilo. | |
* ono by sa zmestit malo, lebo pri normalnom vstupe zaberie int32_t | |
* v dekadickom zapise najviac log_10(2^32) = ~10 znakov + znamienko */ | |
if (fgets(word, sizeof word, stdin) == NULL) { | |
// ak zlyha (vid manual), skonci a vrat chybu 1 | |
perror("Chyba pri nacitavani poctu slov."); | |
return 1; | |
} | |
// nastavme si specialnu premennu errno na 0, aby sme vedeli odchytit | |
// chyby vo volani strtol (napriklad cislo mimo rozsahu) | |
errno = 0; | |
// preved riadok s cislom v desiatkovej sustave na long int | |
words = strtol(word, NULL, 0); | |
// pri uspesnom volani bude errno bez zmeny, cize 0, nepravdiva hodnota | |
if (errno) { | |
// ak nastala chyba, vypis nasu hlasku + popis chyby v errno | |
perror("Chyba pri parsovani poctu slov."); | |
// tentokrat ukoncime program s chybou 2 | |
return 2; | |
} | |
// nie je nic na konverziu, skonci predcasne, ale uspesne | |
if (words == 0) { | |
return 0; | |
} | |
// pocet slov je zaporny, uzivatel je debil | |
if (words < 0) { | |
// stderr pre chybovy vystup, nechceme miesat validny vystup | |
// programu s chybovymi hlaskami | |
fprintf(stderr, "Pocet slov musi byt kladny)\n"); | |
return 3; | |
} | |
// kedze sme lenivi, zvysok riadka (ak nejaky zvysok je) zahodime | |
if (strchr(word, '\n') == NULL) { | |
//'v podmienke najprv priradime hodnotu premennej `chr`, | |
// potom ju porovname -- pozor! `=` nie je `==`! | |
while (((chr = fgetc(stdin)) != '\n') && (chr != EOF)) | |
; | |
} | |
// na dalsom riadka vstupu budu uz len slova, riesit pocet slov je | |
// uplne zbytocne, da sa to efektivne a lahko aj bez jeho znalosti. | |
// + sme si mohli usetrit 50 riadkov, ale zadanie je zadanie... | |
// -------------------------- N A R U B Y -------------------------- // | |
// nacitany znak zo vstupu | |
char charin; | |
// ukazatel aktualnej pozicie v LIFO bufferi | |
char* cursor = word; | |
// adresa konca zasobnika, ukladame si len pre potreby porovnania | |
char* const bufend = word + MAX_WORD_LEN; | |
// priznak pre vylucenie vsetkych dalsich znakov v nevyhovujucom slove | |
bool ignoreNext = false; | |
while ((charin = fgetc(stdin)) != EOF) { | |
if (isspace(charin)) { | |
// konecne medzera, dalsi znak bude zaciatok noveho slova | |
ignoreNext = false; | |
// nizsie sa da pouzit na testovanie: | |
// fprintf(stderr, "%d = %c\n", (int) (cursor - word), *cursor); | |
/* cursor == word vtedy, ak sme nacitali medzeru a neposunuli | |
* kurzor. Toto mozu byt opakujuce sa medzery alebo whitespace | |
* na zaciatku riadka. Je to odpad, vyhodme to. | |
*/ | |
/* Tu bolo povodne: | |
* if (cursor != word) && (--words == 0) | |
* No uplne to nesedelo (treba vypisat za slovom este medzeru). | |
* Nechavam tu tento sialeny vyklad, lebo nejaku chvilu zabral. | |
* | |
* Ak mame znaky v slovicku a natrafili sme na medzeru | |
* (a teda ukoncili slovo), odcitajme z pocitadla. Podmienky | |
* sa v programovani vyhodnocuju zlava doprava. Ak prva | |
* neplati, nezacne sa ani porovnavanie druhej. No a v druhej | |
* podmienke odcitavame z poctu priamo v porovnani. | |
* | |
* `--` je unarny operator, ma teda len jeden operand, samotnu | |
* premennu, ktoru znizi o 1. Ak stoji `--` (alebo `++`) | |
* PRED nazvom premennej (berme `i`), najprv sa znizi o 1, | |
* potom sa pouzije pri porovnani (teda akoby pred celym | |
* `if`-om stal vyraz "i = i - 1;" a v podmienke bolo len `i` | |
* bez operatora). Vtedy hovorime o pre-increment alebo | |
* pre-decrement operatore (podla typu operacie, +1, resp. -1). | |
* Naopak, ak je operator ZA nazvom (i++), najprv sa pouzije | |
* stara hodnota a bez ohladu na pravdivost vyroku sa premenna | |
* hned po porovnani zvysi/znizi o 1. To je post-increment, | |
* resp. post-decrement unarny operator. | |
* | |
* Aby sa vsak vobec k samotnemu zvysovaniu a porovnavaniu | |
* program dostal, musia v pripade AND (&&) logickych | |
* operatorov byt splnene vsetky predchadzajuce podmienky. | |
* Pre operator OR (||) sa naopak budu vyhodnocovat vyrazy | |
* zlava doprava postupne, az kym program nenatrafi na taky, | |
* ktoreho vysledok je pravda (true). Vtedy sa tok programu | |
* dostane do tela `if`-u. | |
*/ | |
if (cursor != word) { | |
/* Ak mame nieco | |
* v bufferi (nazbierane znaky), posuvajme kurzor dozadu | |
* a vypisujme pismenka pod kurzorom, az kym nenarazime | |
* na zaciatok samotneho bufferu. | |
*/ | |
while (cursor != word) { | |
// naposledy sme posunuli kurzor na prazdnu poziciu | |
// treba ho posunut naspat tam, kde konci pismenko | |
cursor--; | |
fputc(*cursor, stdout); | |
} | |
if (--words == 0) { | |
// pretocili sme urceny pocet slov, papa | |
fputc('\n', stdout); | |
return 0; | |
} | |
fputc(' ', stdout); | |
} | |
if (charin == '\n') { | |
// Ukoncime to na novom riadku. Bez podmienky by sa nove | |
// riadky odignorovali a caḱalo by sa na words == 0. | |
fputc('\n', stdout); | |
return 0; | |
} | |
continue; | |
} else if (ignoreNext) { | |
// dalsi znak nie je medzera, ale zvysok slova ignorujeme | |
continue; | |
} | |
// sme na uplnom konci a stale sme nedosli na medzeru? to moze | |
// znamenat len jedno -- nejake slovicko je dlhsie ako MAX_WORD_LEN | |
if (cursor == bufend) { | |
// vyresetuj kurzor na zaciatok, s takym slovom sa nekasleme | |
cursor = word; | |
// nastav priznak, nech preskocime zvysok pismeniek | |
ignoreNext = true; | |
// mozeme program ukoncit s chybovou hlaskou alebo pokracovat | |
continue; | |
} | |
// ulozime znak na vrch zasobnika | |
*cursor = charin; | |
// posunme kurzor na dalsiu poziciu | |
cursor++; | |
} | |
return 0; | |
} | |
/* Kedze nam niekto vymyslel prihorete zadanie, musime ho splnit. Nastastie | |
* je zadanie derave a nedava nam za podmienku tuto funkciu pouzit, len | |
* naprogramovat. Naozaj nema zmysel umyselne kazit eleganciu. | |
* | |
* Input must be a null-terminated C string. It will be reversed in place. | |
*/ | |
void opacne(char* str) { | |
if (!str || !*str) { | |
// prazdne stringy neberieme | |
return; | |
} | |
// adresa posedlneho znaku v retazci | |
char* end = strchr(str, '\0') - 1; | |
// dlzka retazca | |
size_t len = str - end; | |
// sem si odlozime znak z konca, ktory nahradime znakom zo zaciatku | |
char old; | |
while (end > str) { | |
old = *str; | |
*str = *end; | |
*end = old; | |
end--; | |
str++; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment