Veľkonočná akcia je tu a s ňou aj extra kredity ZADARMO na náš interaktívny e-learning. Dobij si teraz kredity a posuň sa vo svojej kariére vpred!
Zarábaj až 6 000 € mesačne! Akreditované rekvalifikačné kurzy od 0 €. Viac informácií.

9. diel - Textové reťazce v jazyku C druhýkrát - Práca so znakmi

V minulej lekcii, Textové reťazce v jazyku C , sme si uviedli, že textový reťazec je vlastne len pole znakov ukončené nulovým znakom. Dnes budeme v tutoriálu pracovať práve s jednotlivými znakmi, naučíme sa používať ASCII hodnoty a vytvoríme analyzátor viet a šifrovací program.

Výpis textu po znakoch

Najprv si overíme, že môžeme naozaj pristupovať k textu ako k poľu char ov. Pre začiatok si iba vypíšeme jednotlivé písmená nejakého reťazca:

Klikni pre editáciu
  • int i;
    char veta[] = "Hello ITnetwork";
    
    for (i = 0; veta[i] != '\0'; i++)
        printf("%c ", veta[i]);
    
    • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

    Cyklus prejde všetky znaky reťazca, až narazí na nulový znak, ktorým je reťazec zakončený. Vo výsledku sú naozaj vypísané jednotlivé znaky reťazca, pre názornosť som za každý znak vypísal ešte medzeru:

    Konzolová aplikácia
    Hello ITnetwork

    Ascii hodnota

    Možno ste už niekedy počuli o ASCII tabuľke. Najmä v ére operačného systému MS-DOS prakticky nebola iná možnosť, ako zaznamenávať text. Jednotlivé znaky boli uložené ako čísla typu char, teda s rozsahom hodnôt od 0 do 255. V systéme bola uložená tzv. ASCII tabuľka, ktorá mala 256 znakov a každému ASCII kódu (číselnému kódu) priradzovala jeden znak.

    Asi je vám jasné, prečo tento spôsob nebol platný dodnes. Do tabuľky sa jednoducho nevošli všetky znaky všetkých národných abecied, teraz sa používa unicode (UTF-8) kódovanie, kde sú znaky reprezentované trochu iným spôsobom. Avšak v C sa v predvolenom nastavení stále pracuje s ASCII hodnotami jednotlivých znakov. Ak by sme chceli pracovať s UNICODE znaky (teda i UTF8), museli by sme použiť takzvané wide znaky. Hlavná výhoda ASCII zápisu je v tom, že znaky sú uložené v tabuľke za sebou, podľa abecedy. Napr. na pozícii 97 nájdeme 'a', 98 'b' a podobne. Podobne je to s číslami, diakritické znaky tam budú bohužiaľ len nejako rozhádzané.

    Skúsme si teraz previesť znak do jeho ASCII hodnoty a naopak podľa ASCII hodnoty daný znak vytvoriť:

    Klikni pre editáciu
    • char c; // znak
      int i; // ordinálna (ASCII) hodnota znaku
      // prevedieme znak na jeho ASCII hodnotu
      c = 'a';
      i = (int)c;
      printf("Znak %c sme previedli na ASCII hodnotu %d\n", c, i);
      
      // Prevedieme ASCII hodnotu na znak
      i = 98;
      c = (char)i;
      printf("Ascii hodnotu %d sme previedli na znak %c", c, i);
      
      • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

      Konzolová aplikácia
      Znak a sme previedli na ASCII hodnotu 97
      Ascii hodnotu 98 sme previedli na znak b

      Analýza výskytov vo vete

      Napíšme si jednoduchý program, ktorý nám analyzuje zadanú vetu. Bude nás zaujímať počet samohlások, spoluhlások, čísel a počet zvyšných znakov (napr. Medzera alebo !).

      Daný textový reťazec si najprv v programe zadáme napevno, aby sme ho nemuseli pri každom spustení písať. Keď bude program hotový, nahradíme reťazec za scanf(). Reťazec budeme prechádzať cyklom po jednom znaku. Rovno tu hovorím, že neapeluje na rýchlosť programu a budeme voliť názorná a jednoduché riešenia.

      Najprv si pripravme kód, definujme si samohlásky, spoluhlásky a čísla. Počet zvyšných znakov nemusíme počítať, bude to dĺžka reťazca mínus súčet samohlások, spoluhlások a písmen. Pripravíme si premenné, do ktorých budeme ukladať jednotlivé počty. Pretože sa jedná o zložitejší kód, nebudeme zabúdať na komentáre.

      // inicializácia pocítadiel
      int pocet_samozhlasek = 0;
      int pocet_souhlasek = 0;
      int pocet_cisel = 0;
      
      // retazec, ktory chceme analyzovať
      char retezec[] = "Programator sa zasekne vo sprche, pretoze inštrukcie na šampónu boli: namydliť, umytý, opakovať.";
      
      // definícia typu znaku
      char samohlasky[] = "aeiouyAEUOUY";
      char souhlasky[] = "bcdfghijklmnpqrstvwxzBCDFGHIJKLMNPQRSTVWXZ";
      char cisla[] = "0123456789";
      
      // indexy
      int i;
      
      printf("Povodnej sprava: %s\n",retezec);
      
      // hlavni cyklus pokracuje, kým nenarazí na znak konca retazca
      for (i = 0; retezec[i] != '\0'; i++)
      {
      
      }

      Najskôr počítadlo vynulujeme. Na definícia znakov nám postačí obyčajné pole znakov ako ho poznáme. Hlavný cyklus nám prejde jednotlivé znaky v reťazci. Poďme plniť počítadla, pre jednoduchosť už nebudem opisovať zvyšok kódu a presunu sa len k cyklu:

      // hlavni cyklus pokracuje, kým nenarazí na znak konca retazca
      for (i = 0; retezec[i] != '\0'; i++)
      {
          if (obsahuje_znak(retezec[i], samohlasky) == 1)
              pocet_samohlasek++;
          else if (obsahuje_znak(retezec[i], souhlasky) == 1)
              pocet_souhlasek++;
          else if (obsahuje_znak(retezec[i], cisla) == 1)
              pocet_cisel++;
      }

      Všimnite si, že využívame funkciu obsahuje_znak(), ktorá zistí či reťazec obsahuje určitý znak. K funkciám sa síce dostaneme až na konci kurzu, však dnes predbehnú a pridáme si práve funkciu obsahuje_znak(), aby sme mohli vytvoriť nejaké zaujímavé programy.

      Nasledujúci blok kódu vložte nad funkciu main(), ak budete mať s jeho začlenením problémami, pozrite sa na priložené zdrojové kódy.

      int obsahuje_znak(char znak,char pole[])
      {
          int i;
          for (i = 0; pole[i] != '\0'; i++)
          if (pole[i] == znak)
              return 1;
          return 0;
      }

      Funkciu si zatiaľ popisovať nebudeme, vráťme sa k nášmu kódu vo funkcii main(). Aktuálny znak našej vety teda najprv skúsime vyhľadať v reťazci samohlásky a prípadne zvýšiť ich počítadlo. Ak v samohláskach nie je, pozrieme sa do spoluhlások a prípadne opätovne zvýšime ich počítadlo. To isté vykonáme s číslami. Teraz nám chýba už len výpis na koniec:

      Klikni pre editáciu
      • #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        
        int obsahuje_znak(char znak,char pole[])
        {
            int i;
            for (i = 0; pole[i] != '\0'; i++)
            if (pole[i] == znak)
                return 1;
            return 0;
        }
        
        int main(int argc, char** argv)
        {
        
            // inicializácia pocítadiel
            int pocet_samohlasek = 0;
            int pocet_souhlasek = 0;
            int pocet_cisel = 0;
        
            // retazec, ktory chceme analyzovať
            char retezec[] = "Programator sa zasekne vo sprche, pretoze inštrukcie na šampónu boli: namydliť, umytý, opakovať.";
        
            // definícia typu znaku
            char samohlasky[] = "aeiouyAEUOUY";
            char souhlasky[] = "bcdfghijklmnpqrstvwxzBCDFGHIJKLMNPQRSTVWXZ";
            char cisla[] = "0123456789";
        
            // indexy
            int i;
        
            printf("Povodnej sprava: %s\n",retezec);
        
            // hlavni cyklus pokracuje, kým nenarazí na znak konca retazca
            for (i = 0; retezec[i] != '\0'; i++)
            {
                if (obsahuje_znak(retezec[i], samohlasky) == 1)
                    pocet_samohlasek++;
                else if (obsahuje_znak(retezec[i], souhlasky) == 1)
                    pocet_souhlasek++;
                else if (obsahuje_znak(retezec[i], cisla) == 1)
                    pocet_cisel++;
            }
            printf("Pocet samohlások: %d\n", pocet_samohlasek);
            printf("Pocet spoluhlások: %d\n", pocet_souhlasek);
            printf("Počet čísiel: %d\n", pocet_cisel);
            printf("Pocet zvyšných znaku: %d\n",
                    strlen(retezec) - pocet_samohlasek - pocet_souhlasek - pocet_cisel);
            return (EXIT_SUCCESS);
        }
        
        • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

        výsledok:

        Konzolová aplikácia
        Povodnej sprava: Programator sa zasekne vo sprche, pretoze inštrukcie na šampónu boli: namydliť, umytý, opakovať.
        Pocet samohlások: 31
        Pocet spoluhlások: 45
        Počet čísiel: 0
        Pocet zvyšných znaku: 17

        Cézarova šifra

        Vytvoríme si jednoduchý program pre šifrovanie textu. Ak ste niekedy počuli o Cézarově šifre, bude to presne to, čo si tu naprogramujeme. Šifrovanie textu spočíva v posúvaní znaku v abecede o určitý, pevne stanovený počet znakov. Napríklad slovo "ahoj" sa s posunom textu o 1 preloží ako "bipk". Posun umožníme užívateľovi vybrať. Algoritmus tu máme samozrejme opäť vysvetlený a to v článku Cézarova šifra. Program si dokonca môžete vyskúšať v praxi - Online cézarova šifra.

        Vráťme sa k programovaniu a pripravme si kód. Budeme potrebovať premenné pre pôvodné text a pre posun. Zašifrovaným textom nahradíme pôvodnú správu. Ďalej cyklus prechádzajúce jednotlivé znaky a výpis zašifrované správy. Správu si necháme zapísanú napevno v kóde, aby sme ju nemuseli pri každom spustení programu písať. Po dokončení nahradíme obsah premennej funkcií scanf(). Šifra nepočíta s diakritikou, medzier a interpunkčných znamienok. Diakritiku budeme bojkotovať a budeme predpokladať, že ju užívateľ nebude zadávať. Pre zjednodušenie vynecháme aj veľké písmená. Ideálne by sme mali diakritiku pred šifrovaním odstrániť, rovnako tak hocičo okrem písmen.

        // retazec k zašifrovanie
        char s[] = "cernediryjsoutamkdebuhdelilnulou"; // čierne diery sú tam, kde Boh delilo nulou
        int posun = 1;
        int i;
        
        printf("Povodnej sprava: %s\n", s);
        
        // hlavni cyklus
        for (i = 0; s[i] != '\0'; i++)
        {
        
        }
        
        printf("Zašifrovanú správu: %s\n", s);

        Teraz sa presunieme dovnútra cyklu. Hodnotu aktuálneho znaku zvýšime o posun a uložíme miesto pôvodného znaku.

        Klikni pre editáciu
        • // hlavni cyklus
          for (i = 0; s[i] != '\0'; i++)
          {
              s[i] = s[i] + posun;
          }
          
          • Skontroluj, či výstupy programu zodpovedajú predlohe. S inými textami testy neprejdú.

          Konzolová aplikácia
          Povodnej sprava: cernediryjsoutamkdebuhdelilnulou
          Zašifrovanú správu: dfsofejszktpvubnlefcviefmjmovmpv

          Program si vyskúšame. Výsledok vyzerá celkom dobre. Skúsme si však zadať vyššiu posun alebo napísať slovo "zebra". Vidíme, že znaky môžu po 'z' pretiecť do ASCII hodnôt ďalších znakov, v texte teda už nemáme len písmená, ale ďalšie škaredé znaky. Uzavrieme znaky do kruhu tak, aby posun plynule po 'z' prešiel opäť k 'a' a ďalej. Postačí nám k tomu jednoduchá podmienka, ktorá od novej ASCII hodnoty odpočíta celú abecedu tak, aby sme začínali opäť na 'a'.

          // hlavni cyklus
          for (i = 0; s[i] != '\0'; i++)
          {
              s[i] = s[i] + posun;
              if (s[i] > 'z') // kontrola pretečeniu
                  s[i] = s[i] - 26;
          }

          Ak hodnota presiahne ASCII hodnotu 'z', znížime ju o 26 znakov (toľko znakov má anglická abeceda). Je to jednoduché a náš program je teraz funkčná. Všimnime si, že nikde nepoužívame priame kódy znakov, v podmienke je 'z', aj keď by sme tam mohli napísať rovno 122. Je to z dôvodu, aby bol náš program plne odtienený od explicitných ASCII hodnôt a bolo lepšie viditeľné, ako funguje. Cvične si skúste urobiť dešifrovanie.

          V budúcej lekcii, Riešené úlohy k 8.-9. lekciu Céčka , si povieme o jednej z najzákladnejších konštrukcií jazyka C - o funkciách :)

          V nasledujúcom cvičení, Riešené úlohy k 8.-9. lekciu Céčka, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.


           

          Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

          Stiahnuť

          Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

          Stiahnuté 126x (126.1 kB)
          Aplikácia je vrátane zdrojových kódov v jazyku C

           

          Ako sa ti páči článok?
          Pred uložením hodnotenia, popíš prosím autorovi, čo je zleZnakov 0 z 50-500
          Predchádzajúci článok
          Textové reťazce v jazyku C
          Všetky články v sekcii
          Základné konštrukcie jazyka C
          Preskočiť článok
          (neodporúčame)
          Riešené úlohy k 8.-9. lekciu Céčka
          Článok pre vás napísal Patrik Valkovič
          Avatar
          Užívateľské hodnotenie:
          2 hlasov
          Věnuji se programování v C++ a C#. Kromě toho také programuji v PHP (Nette) a JavaScriptu (NodeJS).
          Aktivity