Čtení z textového souboru v C Vyřešeno

Místo pro dotazy a rady ohledně programovacích jazyků (C++, C#, PHP, ASP, Javascript, VBS..) a tvorby webových stránek

Moderátor: Mods_senior

jaker
nováček
Příspěvky: 29
Registrován: listopad 11
Pohlaví: Nespecifikováno
Stav:
Offline

Čtení z textového souboru v C

Příspěvekod jaker » 16 bře 2014 10:40

Zdravím všechny programátory, mám pár dotazů ohledně programování v C. Vytvářím program pro překódování textového souboru z textu na ASCII kod a z pět z ASCII kodu na text. Z textu na ASCII kod mám program "skoro" hotový. Tento program by měl číst text z textového souboru in.txt po větách a poté do textového souboru out.txt uložit v ASCII znacích. Zatím jsem došel k tomu, že dokážu přečíst první větu a přeložit do ASCII, ale nevím jak mám udělat abych přečetl další větu a na dalším řádku v out.txt jí měl přeloženou na ty ASCII znaky.
FILE *text1;
FILE *text2;
text1 = fopen("in.txt", "r");
text2 = fopen("out.txt", "w+");

do
{
i= fgetc(text1);
fprintf(text2, "%i", i);
}
while (i!= '.');

fclose(text1);
return 0;
Dále mám problém s tím, že nevím jak mám udělat opačný překlad z ASCII kódu na text. Za jakoukoliv pomoc budu moc rád...

Reklama
Uživatelský avatar
faraon
Master Level 8.5
Master Level 8.5
Příspěvky: 7397
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

Re: Čtení z textového souboru v C

Příspěvekod faraon » 16 bře 2014 11:24

Pár poznámek na začátek:
  • Ty handle na soubory bych pojmenoval třeba vstup a výstup, nebo aspoň textin a textout, ta čísla jsou poněkud matoucí.
  • Nepoužívej %i, ale %d. Tím dáváš jasně najevo že to chceš desítkově, protože %i znamená integer a zvládá osmičkovou, desítkovou i šestnáctkovou soustavu. Mohl bys narazit.
  • Proměnná i (a po ní následující) je historicky vyhrazená pro index v cyklu, pro znak je lepší používat c (jako character) nebo třeba česky z.
  • Vždy kontroluj návratové hodnoty funkcí, zvlášť tak kritických jako fopen(). Zkus si co se stane když ten vstupní soubor nebude existovat!
  • Soubory po použití IHNED uzavírej, jinak jsou otevřené až do ukončení programu a ve výjimečných případech ještě déle.
  • Opravdu chceš text načítat jen po první tečku? Kdybys chtěl načíst celý soubor, bylo by lepší udělat to takhle:
    while ((c=fgetc(textin))!=EOF) { ... příkazy ... }
Makro EOF znamená End Of File, a je kvůli němu nutné znak deklarovat jako int a ne jako char. Ale on procesor se znaky stejně pracuje jako s inty, takže se mu tím aspoň ušetří práce při převádění.

A teď k věci. Umíš načíst znak, a vypsat ho jako číslo. Udělal jsi to takhle:

Kód: Vybrat vše

c=fgetc(textin);
fprintf(textout, "%d", c);

Umíš také načíst číslo, třeba z konzole? Ze souboru se to provede podobně, a potom do druhého souboru uložíš zase zakódovaný znak:

Kód: Vybrat vše

fscanf(textin, "%d", &c);
fputc(c,textout);


I tady je dobré myslet na návratovou hodnotu, funkce z rodiny scanf() vracejí počet úspěšně načtených položek, v tomhle případě jedničku za jedno načtené číslo. To se dá použít pro detekci chyb, jako když se na vstupu vyskytne znak který jako číslo nejde interpretovat. Třeba písmeno nebo konec souboru ;-)
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

jaker
nováček
Příspěvky: 29
Registrován: listopad 11
Pohlaví: Nespecifikováno
Stav:
Offline

Re: Čtení z textového souboru v C

Příspěvekod jaker » 16 bře 2014 14:37

1. Chtěl bych ti moc poděkovat za ochotu a hlavně za skvělý zpracování odpovědi. Je to přehledný a celkem pochopitelný :-)

2. Kontrolu návratových hodnot mám v plánu dodělat, ale primárně se zaměřuji na to co to má dělat, i tak díky za připomenutí...

3. S tím načítáním jsem to nemyslel jen po první tečku. Potřeboval bych to načítat po větách... v zadání mám: " a) program bude pracovat po větách - přečte větu ze vstupního textového programu b) překóduje podle vybrané tabulky a tak pokračuje až do konce vstupního souboru c) zapisuje do výstupního souboru"
nebo alespoň tak jsem to z toho pochopil já...

4. Ještě mi moc není jasný ten převod nazpátek... předpokládám, že k tomu je potřeba tato část programu, jenomže když jsem to zkusil, na vstupu jsem měl ASCII kod (6510411110646) = Ahoj, ale výstup mi zobrazil jenom text ö místo Ahoj. Můj názor je, že to přečte celý číslo a to pak přeloží na text, myslím si, že by to mělo nějak číst do 128 a to by byl jeden znak a pak znovu a znovu... nevím jestli nad tím přemýšlím správně, celkem v tom plavu :huh:

Kód: Vybrat vše

fscanf(textin, "%d", &c);
           fputc(c, textout);

Uživatelský avatar
faraon
Master Level 8.5
Master Level 8.5
Příspěvky: 7397
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

Re: Čtení z textového souboru v C

Příspěvekod faraon » 16 bře 2014 15:02

V Céčku jsou návratové hodnoty jediný způsob jak zjistit co se stalo, takže je lepší na nich rovnou založit celou strukturu programu. Hlavně ty cykly... ;-)

Jestli jsem to teda správně pochopil, tak máš každou větu uložit zakódovanou na jeden řádek, a potom zpětně každý řádek na původní větu. Tak to bude jednoduché, prostě se při kódování po tečce odřádkuje. Jeden if navíc.
A celý soubor se bude načítat až do toho EOF. Víš jak se v C udělá kopie souboru? Takhle:
while ((c=fgetc(textin))!=EOF) fputc(c,textout);
To je celé, zkus si to :P
A pokud mezi to načtení a uložení znaku vložíš nějakou operaci, třeba nahrazení mezery hvězdičkou, nebo vynechání uvozovek, máš takový maličký konverzní program. Ale ty potřebuješ spíš až po uložení znaku zjistit tečku a po ní zapsat '\n'.

Převod z ASCII nazpátek ti nemůže proběhnout správně, protože jestli máš v tom souboru 6510411110646, tak program nemá jak zjistit kde které číslo začíná a končí. Zkus mezi nimi dělat mezery!
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

jaker
nováček
Příspěvky: 29
Registrován: listopad 11
Pohlaví: Nespecifikováno
Stav:
Offline

Re: Čtení z textového souboru v C

Příspěvekod jaker » 16 bře 2014 16:00

Pochopil jsi to naprosto přesně...každou větu uložit zakódovanou na jeden řádek. Ještě mě napadla jedna věc... když dokážu ukládat zakódovanou větu na řádek, proč jí rovnou neuložit po znacích ascii kodu, který by byly oddělený mezerami, aby se poté dalo zpětně přeložit kód na text. Ještě se sice peru s tím "jednoduchým" if navíc, ale myslíš si, že by to šlo? oddělit to mezerama? je na to nějakej příkaz? :D

Uživatelský avatar
faraon
Master Level 8.5
Master Level 8.5
Příspěvky: 7397
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

Re: Čtení z textového souboru v C

Příspěvekod faraon » 16 bře 2014 22:00

Příkaz na to není, je na to mezera :lol:

Prostě místo tohohle příkazu
fprintf(textout, "%d", c);
napíšeš tenhle
fprintf(textout, "%d ", c);

Vidíš jí tam? Tím se ti za každým jednotlivým ASCII kódem napíše mezera, a ty se budeš dál starat jen o to jestli ten znak nebyla tečka, abys mohl odřádkovat:
if ('.'==c) printf("\n");

Pokud by někomu vadila mezera na konci řádku, tak by se použil ten první příkaz, a trochu se rozšířila ta podmínka, třeba takhle:

Kód: Vybrat vše

if ('.'==c)
   printf("\n");
else
   putchar(' ');

Přeloženo do lidštiny: "Za tečkou odřádkuj, za ostatními znaky udělej mezeru."

Ten fscanf() v druhé části programu načítá jednotlivé číslice a sestavuje z nich číslo, dokud nenarazí na nějaký nečíselný znak. Bílé znaky pak přeskakuje v libovolném počtu, takže je mu jedno jestli za/před číslem jsou mezery nebo konce řádků, bere je všechny dohromady jako jeden oddělovač.
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

jaker
nováček
Příspěvky: 29
Registrován: listopad 11
Pohlaví: Nespecifikováno
Stav:
Offline

Re: Čtení z textového souboru v C

Příspěvekod jaker » 17 bře 2014 16:03

Super mám to :D díky moc, ještě tam musím dodělat pár věcí, nebude ti vadit když se ještě ozvu? :D

--- Doplnění předchozího příspěvku (17 Bře 2014 20:03) ---

Tak se ozývám dřív než jsem myslel :).... prosím tě, ještě chci přidat jednu věc do toho programu a to takovou, že text ve vstupním texťáku se bude zadávat psaním do toho programu. Už dokážu napsat slovo a uložit ho, ale jakmile napíšu větu, tak všechno co je hned za první mezerou mi to už nepřepíše... mohl by jsi mi ještě pomoct? Tady je kód co umí přečíst a uložit jedno slovo ale ne celou větu...

Kód: Vybrat vše

char *c[128];
           FILE *text;
           text = fopen("in.txt", "w+");
           printf("Zadej text: ");
           scanf("%s", &c);
           fprintf(text, "%s", c);
           printf("Ulozeno: %s", c);

           fclose(text);
            if (text== EOF)
                printf("Soubor in.txt se nepodarilo uzavrit!\n");

moc díky :)

Uživatelský avatar
faraon
Master Level 8.5
Master Level 8.5
Příspěvky: 7397
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

Re: Čtení z textového souboru v C

Příspěvekod faraon » 17 bře 2014 22:15

Pokud chceš načíst celý řádek najednou, tak můžeš použít funkci gets(), nebo radši bezpečnější fgets(), kde se zadává i maximální délka, kterou je možné do pole uložit. Ta první je nebezpečná protože nehlídá přetečení pole, takže před ní i překladače automaticky varují, pokud máš zapnuté warningy.
Zato s tou druhou můžeš dokonce mít společný kód pro načítání ze souboru i z konzole, protože klávesnice je také soubor. V okamžiku spuštění programu se ti totiž automaticky otevírají tři streamy, vstupní stdin, a výstupní stdout a stderr. Ten poslední je určený speciálně pro hlášení chyb!

Takže pokud otevřeš nějaký soubor se vstupním textem, náš v handle text ukazatel na jeho stream. Ale pokud ho neotevřeš, stačí do handle text zkopírovat ukazatel na handle stdin, a místo z disku načítáš z klávesnice. Pak je také dobré vědět že existuje způsob jak na klávesnici napsat speciální znak znamenající konec souboru, který můžeš testovat pomocí toho EOF, v Linuxu je to unixové Ctrl+D, ve Windowsu Ctrl+Z.

Vyzkoušej si tohle:

Kód: Vybrat vše

int main(void)
    {
    char radek[1000];
    FILE *text;

    text=stdin;        /* tady je to kouzlo */

    fgets(radek,999,text);
    printf("%s",radek);

    return 0;
    }

Bacha na jednu věc, gets() a fgets() načítají celý řádek včetně Enteru na konci! Pokud ho tam nechceš, musíš si ho sám odstranit. Nebo napsat vlastní funkci která bude dělat něco podobného, ale přesně podle tvých představ :lol:
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

jaker
nováček
Příspěvky: 29
Registrován: listopad 11
Pohlaví: Nespecifikováno
Stav:
Offline

Re: Čtení z textového souboru v C

Příspěvekod jaker » 28 bře 2014 22:06

Zdravím, promiň že jsem se dlouho neozval, měl jsem toho teď moc, ale už se zase vracím k programování, a řeším další problém... :) Zkouším si udělat takové malé menu... kde si uživatel nejdřív vybere směr překladu, a potom si vybere jestli bude chtít překládat text ze složky, nebo zadáním textu do programu... no a mám problém s tím, že nevím přesně jak funguje switch - case... zdali ho můžu použít vícekrát, nebo proč mi to při použití blbne.

Kód: Vybrat vše

int vstupD()                            //dopředný překlad
{
        char podvolbaa;

        system("cls");

        printf("Nacteni: \n\n");

        printf("  s - ze slozky\n");
        printf("  t - zadanim textu\n");
        printf("  z - zpet\n");

        podvolbaa = getch();                                     // nactu znak z klavesnice
        system("cls");                                              // smazu obsah obrazovky


        switch(podvolbaa)                                         //switch pro druhé menu dopředného překladu
         {
            default: printf("Zmackni s, t nebo z!");      //při stisku jakéhokoli jiného tlačítka než je nadefinované se vypíše text

            case 's':{                                                //při stisku s poběží program pro překlad ze složky
                        int i; int u;

                        FILE *textin;
                        FILE *textout;
                        textin = fopen("in.txt", "r");
                        textout = fopen("out.txt", "w+");

                        printf("\n");
                        printf("Prekladany - prelozeny text: \n");

                        if ( textin == NULL )
                                printf("Soubor neexistuje\n");

                        while ((i= fgetc(textin))!=EOF)
                            {
                                if('.'==i)
                                    fprintf(textout, "\n");

                                else
                                    putchar(' ');

                                fprintf(textout, "%d ", i);
                                printf("%d", i);
                            }
                        printf("\n\n");
                        printf("Preklad je ulozen v textovem souboru out.txt \n");

                        fclose(textin);
                        fclose(textout);
                        if (textin== EOF)
                            printf("Soubor se nepodarilo uzavrit!\n");
                        if (textout== EOF)
                            printf("Soubor se nepodarilo uzavrit!\n");
                        getch();                                                              // cekat na stisk klavesy
                        return;
                    }                     

            case 't':{                                                                        // při stisku tlačítka t poběží program pro překlad zadaného textu v  programu
                     zde bude program pro zadání textu v programu 
                    }

            case 'z': return (main('void'));                                          //  vrácení zpet na předchozí menu
        }
}

int vstupZ()                                                                    // zpětný překlad
{
        char podvolbab;

        system("cls"); // smazu obsah obrazovky

        printf("Nacteni: \n\n");
        printf("  s - ze slozky\n");
        printf("  t - zadanim textu\n");
        printf("  z - zpet\n");

        podvolbab = getch();                                           // nactu znak z klavesnice
        system("cls");                                                     // smazu obsah obrazovky

        switch(podvolbab)                                               //switch pro druhé menu zpětného překladu
        {
        default: printf("Zmackni s, t nebo z!");
        case 's':{                                                            //při stisku tlačítka s bude probíhat překlad ze složky
                    int Preklad2[128];
                    int c;

                    FILE *textout2;
                    FILE *textout;
                    textout = fopen("out.txt", "r");
                    textout2 = fopen("out2.txt", "w+");

                    if ( textout == NULL )
                        printf("Soubor neexistuje\n");

                    while ((c=fgetc(textout))!=EOF)
                        {
                            fscanf(textout, "%d", &c);
                            fputc(c, textout2);
                        }
                    printf("\n");
                    printf("Hotovo! Preklad najdete v textovem souboru out2.txt \n");

                    fclose(textout);
                    fclose(textout2);
                    if (textout== EOF)
                        printf("Soubor se nepodarilo uzavrit!\n");
                    if (textout2== EOF)
                        printf("Soubor se nepodarilo uzavrit!\n");
                 }

        case 't':{                                                                                            //při stisku t se provede toto
                       //zde bude program pro zpětný překlad ze zadání asci kódu
                 }

        case 'z': return (main('void'));                                                             // z zase zpět na předchozí menu
         }
}

int main(void)
{
    char volba;
                system("cls");                            // smazu obsah obrazovky

                printf("Zadej smer prekladu: \n\n");

                printf("  d - dopredny \n");
                printf("  z - zpetny\n");

                printf("  k - konec\n");


        volba = getch();                          //načtení znaku
      system("cls");                           // smazu obsah obrazovky

    switch(volba)                                          // hlavní menu
            {
          default:
            printf("Zmackni d, z nebo k! \n");

         case 'd': vstupD(); break;                           // při stisku d bude probíhat dopředný překlad
         case 'z': vstupZ(); break;                           // při stisku z zpětný překlad

         case 'k': return 0;                                     // pokud zadal k, ukoncim main
            }
}


Problém mám s tím, že jakmile ten program spustím a stisknu jakékoli tlačítko, které není definované, tak se mi nezobrazí hodnota default, ale skočí mi to rovnou do druhého menu vstupD() a jakmili znovu zmáčknu nenadefinované tlačítko, tak se mi zobrazí default ze switche definovaného ve vstupD() a zároveň mi to provede i dopředný převod z texťáku jako kdybych zmáčknul s.... Za jakoukoliv radu jsem moc vděčný :-)

Uživatelský avatar
faraon
Master Level 8.5
Master Level 8.5
Příspěvky: 7397
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

Re: Čtení z textového souboru v C

Příspěvekod faraon » 29 bře 2014 15:46

První pokus o kompilaci, a hned celá stránka errorů :lol:
Co máš za IDE? Nejde ti tam nějak zapnout zobrazování všech warningů? Ono to může být dost užitečné, protože tě to upozorní i na potenciálně nebezpečné konstrukce, jako if(a=b), ty to sice takhle můžeš chtít, ale aby kompilátor měl jistotu že jsi jen nezapomněl druhé rovnítko ==, tak je potřeba mu napsat if((a=b)), tím z toho přiřazení uděláš současně logický výraz. Pokochej se tím co na mě vysypal GCC:

Kód: Vybrat vše

jaker.c: In function ‘vstupD’:
jaker.c:9:9: warning: implicit declaration of function ‘system’ [-Wimplicit-function-declaration]
jaker.c:17:9: warning: implicit declaration of function ‘getch’ [-Wimplicit-function-declaration]
jaker.c:55:35: warning: comparison between pointer and integer [enabled by default]
jaker.c:57:36: warning: comparison between pointer and integer [enabled by default]
jaker.c:60:25: warning: ‘return’ with no value, in function returning non-void [enabled by default]
jaker.c:26:36: warning: unused variable ‘u’ [-Wunused-variable]
jaker.c:69:13: warning: implicit declaration of function ‘main’ [-Wimplicit-function-declaration]
jaker.c:69:36: warning: multi-character character constant [-Wmultichar]
jaker.c: In function ‘vstupZ’:
jaker.c:112:32: warning: comparison between pointer and integer [enabled by default]
jaker.c:114:33: warning: comparison between pointer and integer [enabled by default]
jaker.c:91:25: warning: unused variable ‘Preklad2’ [-Wunused-variable]
jaker.c:122:32: warning: multi-character character constant [-Wmultichar]
/tmp/ccAo4IT1.o: In function `vstupD':
jaker.c:(.text+0x43): undefined reference to `getch'
jaker.c:(.text+0x192): undefined reference to `getch'
/tmp/ccAo4IT1.o: In function `vstupZ':
jaker.c:(.text+0x1ed): undefined reference to `getch'
/tmp/ccAo4IT1.o: In function `main':
jaker.c:(.text+0x354): undefined reference to `getch'
collect2: error: ld returned 1 exit status


  1. Příště mi to pošli i s hlavičkou, ať vím jaké knihovny používáš. Doufám že jí tam píšeš a nespoléháš na nějaký automat.
  2. Komentáře // nebyly v Céčku původně povolené, používá je až norma C99. To není chyba, akorát to pro mě znamená napsat při kompilaci jeden parametr navíc :lol:
  3. Funkci getch() tady na Linuxu nemám, to je DOSová specialita a pěkná prasárna, naneštěstí moc rozšířená. Dá se nahradit getchar(), ale pokud jí použiješ pro čekání, dá se odpálit jen Enterem. Je také dobré předtím napsat uživateli pokyn co má dělat, například "Stiskni Enter", aby neseděl a nečuměl na blikající kurzor. Existuje o tom výborná a dnes už špatně sehnatelná kniha Dialog s počítačem, právě se jedna vyskytuje na Aukru za korunu!
    Ukázkové programy jsou v ní sice v BASICu, ale ty popisy okolo jsou slušná sbírka člověčí psychologie a programátorských omylů.
  4. Totéž platí pro system("cls"), to je příkaz DOSu, u mě neudělá nic. Sice to ničemu nevadí, ale je to dobré vědět.
  5. A teď chyby. Funkce main() je typu int, takže musí int také vracet, chybí ti na konci return 0;
  6. Totéž platí pro vstupD(), v case 's' máš return bez hodnoty. Buď musíš vrátit nulu nebo jiné číslo jako chybový kód, je jedno jestli si to pak někdo vyzvedne, na tom už nezáleží. Ale kdyby naopak byla nějaká hodnota očekávaná a ty jsi jí nevrátil, průser by byl na světě, protože by se tam objevilo nějaké náhodné hausnumero!
  7. A stejně jako deklaruješ main(void), deklaruj i ostatní funkce bez parametrů: vstupD(void), vstupZ(void). V Céčku totiž prázdná závorka v definici funkce znamená libovolný počet parametrů, na rozdíl třeba od C++, kde naopak znamená funkci bez parametrů. Takže vždy void, až budeš používat prototypy funkcí, pochopíš proč.
  8. Tohle je nesmysl:

    Kód: Vybrat vše

                        fclose(textout);
                        fclose(textout2);
                        if (textout== EOF)
                            printf("Soubor se nepodarilo uzavrit!\n");
                        if (textout2== EOF)
                            printf("Soubor se nepodarilo uzavrit!\n");

    Nemůžeš porovnávat ukazatel na stream a znak. Od toho jsou návratové hodnoty, a man fclose říká:
    Upon successful completion 0 is returned. Otherwise, EOF is returned and errno is set to indicate the error.
    Takže funkce fclose() vrací nulu nebo error, správné použití je třeba takhle:

    Kód: Vybrat vše

                        if (fclose(textout))
                           printf("Soubor se nepodarilo uzavrit!\n");
                        if (fclose(textout2))
                           printf("Soubor se nepodarilo uzavrit!\n");

  9. A zůstává nám už jen pár nepoužitých proměnných a jakási podivnost:

    Kód: Vybrat vše

    jaker.c: In function ‘vstupD’:
    jaker.c:27:36: warning: unused variable ‘u’ [-Wunused-variable]
    jaker.c:68:13: warning: implicit declaration of function ‘main’ [-Wimplicit-function-declaration]
    jaker.c:68:36: warning: multi-character character constant [-Wmultichar]
    jaker.c: In function ‘vstupZ’:
    jaker.c:90:25: warning: unused variable ‘Preklad2’ [-Wunused-variable]
    jaker.c:119:32: warning: multi-character character constant [-Wmultichar]

    Co to return (main('void')) jako mělo znamenat? 8-O
    Když je funkce int, tak return musí přece vracet číslo (třeba jako výsledek výrazu, ale číselný), a ty vracíš výsledek volání main() a ještě se znakem 'void' místo prázdné závorky! Tady ti bohatě bude stačit return 0.
  10. Nepoužité proměnné nejsou žádný problém, ale můžou signalizovat že jsi na něco zapomněl. Jen bacha na to že to co deklaruješ uvnitř vnořeného bloku, také platí jen uvnitř vnořeného bloku, nikoliv v celé funkci. Což může být i výhoda :-)
  11. No a nakonec mi to při spuštění vyhodí segfault, protože vstupní soubor neexistuje! Žádný tu nemám.
    Ty sice testuješ jestli se zavřel stdin který máš otevřený jen pro čtení (to snad ani nejde nezavřít), ale netestuješ jestli se ti vstupní soubory vůbec otevřely... Takže BUM - program spadne.
    To uzavírání se testuje proto, že v reálu zapisuješ jen do cache, která se až po zaplnění ukládá celá najednou na disk. Ale pokud je disk plný, nemůže se cache zapsat a k uzavření nedojde, aby se neztratila už vypsaná data (to u vstupu jaksi nehrozí). Ty se musíš rozhodnout co s tím provedeš, když se to stane, protože jako programátor víš co jsi zapisoval, program nebo operační systém to neví, nemůže správně reagovat.

Teď konečně k tomu switch(). V Céčku totiž funguje dost zvláštním způsobem, pochopitelným lépe pokud aspoň trochu ovládáš assembler. Patriarchové ho totiž vytvořili tak, aby se dal používat bez jakýchkoliv omezení, jaká jsou v jiných jazycích.
Třeba v Pascalu je příkaz case(), který dělá podobnou věc. Ale tam funguje jako vícenásobné větvení, prostě když skočíš do kterékoliv větve, tak z ní vypadneš až za koncem toho větvení.
Jenže v Céčku je to úplně jinak, switch() tady funguje jako vícenásobné GOTO do souvislé sekvence příkazů! Proto v ní nemusíš psát složené závorky { } kolem každého case. A teprve na konci té sekvence z ní vypadneš, pokud to chceš udělat dřív, musíš použít break, tak jak to máš v main(). Nebo return pro návrat tam odkud jsi funkci se switchem volal.
Když to neuděláš, pokračuje se normálně dalším case v pořadí! Stejně jako by se pokračovalo další instrukcí strojového kódu, pokud bys před ní nedal nějaký Jump. Ono se z řady různých důvodů včetně tohohle říká že Céčko není programovací jazyk, ale strukturovaný přenositelný assembler ;-)
Bacha na to že v novějších jazycích odvozených z C (Java, C#, Python, PHP...) může switch fungovat zase jinak i když se stejně jmenuje! On totiž ten Céčkový dělá řadě "programátorů" problémy, a tak se různě "vylepšuje". Většina těch rozdílů ale znamená jen to, že se s ním některé věci nedají udělat. V Céčku se dá udělat cokoliv, i šíleně nebezpečná prasárna, ale vždy to musí mít autor pod kontrolou. Tady má prostě programátor absolutní volnost, ale i absolutní zodpovědnost, jazyk za něj nic neudělá, všechno si musí uhlídat sám.

switch.jpg


Rozdíl je, jak vidíš, hodně velký. Stejná věc jako nahoře by se v Pascalu dala udělat také, ale výsledný kód by byl o něco delší, a některé věci se nedají udělat vůbec. V tomhle případě je to schválně, protože Pascal je výukový jazyk pro začátečníky, a tak většinu prasáren neumožňuje dělat.

Ono je sice GOTO ve strukturovaném programování skoro sprosté slovo, takže se používá jen ve výjimečných příkazech (prostě zapomeň že existuje, dokud nebudeš psát programy delší než nějakých 10000 řádků), ale ve skutečnosti je zakuklené do jiných příkazů, jako je ten switch, break nebo continue. Je to tak bezpečnější, navíc na první pohled vidíš co se má stát, což z prostého goto label nepoznáš.
Pohled do historie - ten způsob jakým switch funguje je převzatý z klasického FORTRANu z roku 1956, tady je ještě trochu vylepšený, takže můžeš vybírat podle různých hodnot, ne jen podle pořadového čísla.

No a nakonec ten default, ono je ho lepší mít až nakonec, zejména kvůli přehlednosti, ale také abys dřív vyhodnotil platné možnosti kterých bývá obvykle méně, a teprve potom řešil ty ostatní neplatné. Představ si to tak že překladač má seznam těch hodnot case, a postupně ho prochází, dokud nenajde shodu. Potom skočí někam do těla toho switche, podle toho na kterém místě seznamu se řídící proměnná a seznam shodly. To procházení mu samozřejmě chvíli trvá, pokud ho budeš opakovat v cyklu milionkrát za sekundu, bude to znát, takže je dobré myslet na pořadí vyhodnocování. Nemusí to takhle ale být vždy, protože při optimalizacích s tím kódem překladač občas provádí dost šílené věci, zvlášť když to provádí pro tak šílený křáp jako je x86.

Také je užitečné reagovat i na velká písmena, což tenhle způsob pojetí switche přímo nabízí:

Kód: Vybrat vše

    switch (volba)                                                    // hlavní menu v main()
           {
           case 'D': vstupD(); printf("Vypni si CapsLock!\n");        // upozorní troubu na problém a pokračuje dalším case
           case 'd': vstupD();                                        // při stisku d nebo D volá funkci ...
                     break;                                           // potom vyskočí ze switche ven

           case 'Z': vstupZ(); printf("Vypni si CapsLock!\n");        // upozorní troubu na problém a pokračuje dalším case
           case 'z': vstupZ();                                        // při stisku z nebo Z volá funkci ...
                     break;                                           // potom vyskočí ze switche ven

           case 'K':                                                  // neudělá nic, rovnou pokračuje dalším case
           case 'k': return 0;                                        // ukončí aktuální funkci, tady přímo celý program

           default:  printf("Zmackni d, z nebo k! \n");               // nakopne toho troubu, aby sundal kočku z klávesnice :-D
           }

Switch můžeš do switche samozřejmě vnořit kolikrát chceš, stejně jako to platí pro kteroukoliv jinou programovou strukturu. To je princip strukturovaného programování. Jen musíš dodržet to, že je to blok s jedním vstupem a jedním výstupem, z čehož existuje jediná výjimka, return, který můžeš použít v libovolném místě. Ale protože ten ukončí celou funkci, tak ta se také zvenku jeví jako blok s jedním vstupem a jedním výstupem...
I když by se dalo říct že právě switch tohle také porušuje, protože umožňuje víc vstupů do sekvence příkazů! O těch break nemluvě. Ale zvenku je to opět jeden blok s jedním vstupem a jedním výstupem, takže to platí. Vyzkoušej si tohle:

Kód: Vybrat vše

#include <stdio.h>



int main(void)
    {
    int cislo;

    printf("Kolik sekund: ");
    scanf("%d",&cislo);
    switch (cislo)
           {
           case 10: printf("10\n");
                    sleep(1);
           case  9: printf("9\n");
                    sleep(1);
           case  8: printf("8\n");
                    sleep(1);
           case  7: printf("7\n");
                    sleep(1);
           case  6: printf("6\n");
                    sleep(1);
           case  5: printf("5\n");
                    sleep(1);
           case  4: printf("4\n");
                    sleep(1);
           case  3: printf("3\n");
                    sleep(1);
           case  2: printf("2\n");
                    sleep(1);
           case  1: printf("1\n");
                    sleep(1);
           case  0: printf("\aBUM\n");
                    break;

           default: printf("WTF: %d\n",cislo);
           }

    return 0;
    }

Ty asi budeš muset tu hodnotu sleep(1) změnit na sleep(1000), protože v unixových systémech se zadává v sekundách a v dosových v milisekundách. Ale protože je to odvozené od časovače který posílá přerušení 18,2 krát za sekundu, tak to pro nějaké přesné časování stejně nejde použít. Je to jen atrapa jako spousta dalších věcí od M$.
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)

jaker
nováček
Příspěvky: 29
Registrován: listopad 11
Pohlaví: Nespecifikováno
Stav:
Offline

Re: Čtení z textového souboru v C

Příspěvekod jaker » 30 bře 2014 14:50

Takže :D
1. je neuvěřitelný, jakou máš se mnou trpělivost :-) a toho si moc vážím... díky
2. mám Windowsy a IDE mám CodeBlocks (s tím děláme ve škole...)
3. rád bych to getch() změnil, jenomže když napíšu getchar(), tak mi ten rogram nedělá to co potřebuju... při getch() uživatel nemusím mačkat entr a rovnou to provede, kdežto při getchar() se musí mačkat entr a to je zdlouhavý :-)
4. to return (main()); má znamenat vrácení se zpět do main menu, když tam dám return 0; tak mi skončí program a to jsem nechtěl. Kdežto s tímto zápisem se mi to vrátí do mainu a můžu pokračovat...
5. za ten switch moc díky, už mi to funguje jak má :D teda alespoň u mě
6. ještě jsem chtěl poslední věc a to aby se to zeptalo na konci programu jestli to chceme opakovat(a/n)... zkoušel jsem to udělat přes if, a ne že by to nefungovalo, ale funguje to jenom 1x a potom už ne... porvé se mi to zeptá jestli to chci opakovat, když dám ne tak to skončí, když ano tak mi to skočí zpět do mainu a začínám odznova, jenomže když udělám tu samou věc podruhý, tak už mi to jenom vypíše text jestli to chci opakovat ale program se mi už ukončí jako by to část toho ifu přeskočilo...
V CodeBlocks mi to nehlásí žádný errory ani warningy, zkusím ti poslat komplet co mám hotový, jenom tam nemám dodělaný komentáře...
http://leteckaposta.cz/567888246 tady je to kompletní, doufám že to nezablokuje antivirák...

Uživatelský avatar
faraon
Master Level 8.5
Master Level 8.5
Příspěvky: 7397
Registrován: prosinec 10
Pohlaví: Muž
Stav:
Offline

Re: Čtení z textového souboru v C

Příspěvekod faraon » 30 bře 2014 15:02

Jenže return (main()) tě nevrátí do mainu, ale naopak ho zavoláš jako podprogram. Takže jsi vlastně vytvořil vzájemnou rekurzi pomalu zaplňující zásobník!
Tohle je zajímavá vlastnost Céčka, že main() je funkce jako každá jiná a dá se volat odjinud přímo z programu. Třeba v C++ je tohle naopak přímo zakázané. Holt modernější a omezenejší jazyk, kde se spousta zajímavých věcí nedá :lol:

Zkus ještě zapřemýšlet nad tím hlavním cyklem v main(), jak ho udělat lépe včetně toho ukončení a ano/ne. Já se v tom večer pohrabu a dám vědět.




Pár dalších zjištění:
  • Při zpětném překladu se špatně dekóduje první písmeno, nenačte se první číslice ze souboru.
  • Nejde mi vkládání textu z konzole, tohle není dobrý nápad: while ((b=getch())!= 13)
    U tebe Enter produkuje CR LF, tedy dva kódy 13 a 10, u mě jen ten druhý - LF. Akorát Mac používá CR, stejné jsem to měl například před lety na mém osmibitovém Didaktiku.
    Vyzkoušej co ti bude dělat tohle: while ((b=getch())!= '\n')
  • Když zadávám čísla pro zpětný překlad, dává mi to přímo kódy stisknutých kláves, takže to funguje úplně jinak než při načítání ze souboru. Ale první písmeno to stejně zprasí.
  • Jak to kompiluješ že máš čtyřiatřicet kilobajtů? Já jsem kvůli tomu getch() musel použít navíc curses a mám jenom jedenáct, po stripnutí debuggovacích informací dokonce devět :-o
"Král Lávra má dlouhé oslí uši, král je ušatec!

(pravil K. H. Borovský o cenzuře internetu)


  • Mohlo by vás zajímat
    Odpovědi
    Zobrazení
    Poslední příspěvek
  • Blokování stahovaných souborů
    od Riviera kid » 07 čer 2025 16:47 » v Windows 11, 10, 8...
    10
    3589
    od Riviera kid Zobrazit poslední příspěvek
    16 čer 2025 06:56
  • Program na hledání poškozených souborů JPG Příloha(y)
    od Rosta_Kolmix » 09 lis 2024 11:01 » v Design a grafické editory
    2
    4525
    od Minapark Zobrazit poslední příspěvek
    15 lis 2024 11:04
  • IDM hláška o nemožném stažení souboru Příloha(y)
    od bluenite » 04 črc 2024 11:08 » v Vše ostatní (inet)
    2
    4361
    od bluenite Zobrazit poslední příspěvek
    06 črc 2024 19:40
  • Velikost souboru a složek na disku
    od L.L » 05 úno 2025 11:50 » v Vše ostatní (sw)
    5
    3293
    od L.L Zobrazit poslední příspěvek
    05 úno 2025 17:42

Zpět na “Programování a tvorba webu”

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 1 host