Skip to content

Instantly share code, notes, and snippets.

@ericek111
Last active January 17, 2021 13:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericek111/6869f8e0bb540a6e20a56387ab6172d8 to your computer and use it in GitHub Desktop.
Save ericek111/6869f8e0bb540a6e20a56387ab6172d8 to your computer and use it in GitHub Desktop.
volakoho domaca uloha
#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