Čtení z textového souboru v C Vyřešeno
Čtení z textového souboru v C
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...
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...
Re: Čtení z textového souboru v C
Pár poznámek na začátek:
A teď k věci. Umíš načíst znak, a vypsat ho jako číslo. Udělal jsi to takhle:
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:
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
- 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 ... }
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)
(pravil K. H. Borovský o cenzuře internetu)
Re: Čtení z textového souboru v C
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

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

Kód: Vybrat vše
fscanf(textin, "%d", &c);
fputc(c, textout);
Re: Čtení z textového souboru v C
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
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!

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

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)
(pravil K. H. Borovský o cenzuře internetu)
Re: Čtení z textového souboru v C
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? 

Re: Čtení z textového souboru v C
Příkaz na to není, je na to mezera
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:
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č.

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)
(pravil K. H. Borovský o cenzuře internetu)
Re: Čtení z textového souboru v C
Super mám to
díky moc, ještě tam musím dodělat pár věcí, nebude ti vadit když se ještě ozvu? 
--- 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...
moc díky :)


--- 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 :)
Re: Čtení z textového souboru v C
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:
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
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

"Král Lávra má dlouhé oslí uši, král je ušatec!
(pravil K. H. Borovský o cenzuře internetu)
(pravil K. H. Borovský o cenzuře internetu)
Re: Čtení z textového souboru v C
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.
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ý
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ý

Re: Čtení z textového souboru v C
První pokus o kompilaci, a hned celá stránka errorů 
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:
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.
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í:
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:
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$.

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
- 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.
- 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
- 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ů. - 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.
- A teď chyby. Funkce main() je typu int, takže musí int také vracet, chybí ti na konci return 0;
- 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!
- 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č.
- 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"); - 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?
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. - 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
- 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.
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)
(pravil K. H. Borovský o cenzuře internetu)
Re: Čtení z textového souboru v C
Takže
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á
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...

1. je neuvěřitelný, jakou máš se mnou trpělivost

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á

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...
Re: Čtení z textového souboru v C
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á
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í:
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á

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
"Král Lávra má dlouhé oslí uši, král je ušatec!
(pravil K. H. Borovský o cenzuře internetu)
(pravil K. H. Borovský o cenzuře internetu)
-
- Mohlo by vás zajímat
- Odpovědi
- Zobrazení
- Poslední příspěvek
-
- 10
- 3605
-
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
-
-
- 5
- 3294
-
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