Posted in: Studijní materiály, Vývoj počítačů

Úvodní vhled do jazyka C

Zpracování programu

Editor Slouží pro zápis zdrojového kódu programu a ukládá ho s příponou .c. Preprocesor Předzpracuje zdrojový kód. Vkládá hlavičkové soubory s příponou .h, vynechává komentáře, rozvíjí makra atd. Compiler Převede zdrojový kód do relativního kódu počítače tak, že adresy proměnných a funkcí nejsou známy a jsou relativně zapsány do souboru *.obj. Soubor *.lis je protokol o překladu. Linker Přidělí relativním adresám adresy absolutní, najde adresy neznámých identifikátorů a připojí všechny potřebné knihovny *.lib. Debuger Hledá chyby nastávající při běhu programu a po nalezení chyby se celé zpracování programu opakuje. První program
Pro ilustraci toho jak vypadá program v C si uvedeme jednoduchý program který vypisuje text: „Hurá, můj první program v C!!!“

//Můj první program 
#include <stdio.h> 
int main()
{ 
   printf("Hura, muj prvni program v C!!!");
   getch(); 
   return(0);
}

V prvním řádku s vyskytuje komentář. V jazyce C se zapisuje jednořádkový komentář ve tvaru //jednořádkový komentář. Víceřádkový se zapisuje /* viceřádkový komentář */. Dále se v kódu vyskytuje direktiva (příkaz preprocesoru) #include , která zajišťuje připojení knihovny funkcí. V tomto případe stdio.h pro standardní formátovaný vsup a výstup. Hlavní program je zapsán do funkce main(), kterou musí obsahovat každý program. Začátek a konec programu zapisujeme pomocí tzv. bloku { … }. Definice funkcí (i hlavní funkce main()) většinou obsahují nepovinný příkaz return. V těle programu je funkce pro tisk na standardní výstup printf() a po ní funkce getch(), která je zde jen proto, aby se okno programu nezavřelo hned po spuštění. Místo této funkce lze použít elegentnější řešení s pomocí system(„pause“). V tomto programu se jednalo o pouhé nastínění toho, jak má program v C vypadat. V dalších lekcích se dozvíte vše podrobněji. Klíčová slova Je to množina slov, kterým překladač jazyka C rozumí a má je ve své slovní zásobě. Proto je nelze použít jako identifikátor či název funkce.

  • auto
  • break case char
  • const
  • double int else
  • long
  • extern return float
  • short
  • continue for default do
  • goto if
  • struct switch
  • enum register typedef union
  • unsigned signed void
  • sizeof volatile static while

Proměnné

Proměnné jsou paměťová místa přístupná prostřednictvím identifikátoru. Hodnotu proměnných můžeme během výpočtu měnit. Pro deklaraci proměnné používejte tento obecný formát: typ identifikátor; Pro deklaraci více proměnných stejného datového typu se používá tento zápis: typ identifikátor_1, identifikátor_2, identifikátor_3; V deklaraci může být proměnná současně inicializována, tj. můžeme jí přiřadit počáteční hodnotu: typ identifikátor=hodnota; Proměnné deklarované mimo všechny funkce jsou globální, můžeme je použít kdekoli v programu a jsou implicitně nulové. Proměnné deklarované ve funkcích či v bloku se nazývají lokální proměnné, můžeme je použít jen v dané funkci či bloku a jsou implicitně nenulové.

Datové typy

Datové typy určují rozsah hodnot, velikost alokované paměti a množinu přípustných operací. Dělíme je na: Jednoduché

bez hodnoty void
celočíselné: short (16b), int (16b|32b dle tzpu CPU), long (32b), char (8b)
výčtový typ: enum (8b|16b|32b)
reálné: float (32b), double long (64b), double (80b)

Strukturované

struktura: struct
unie: union
soubor: FILE
pole a řetězec nemají klíčové slovo, jsou složeny ze základních datových typů. Velikost proměnné a rozsah jejich hodnot závisí na implementaci překladače v operačním systému. Typy float, double a long double se používají pro reálná čísla. Typ int a z něj odvozené typy short int a long int pracují s celými čísly. Poněkud překvapivě patří k celočíselným typům i char. Je sice určen pro uložení jednoho znaku, ten je však v jazyce c reprezentován jako číslo. Všechny celočíselné typy mohou být prefixem unsigned deklarovány jen pro čísla bez znaménka. Implicitně jsou deklarovány jako signed. Pro zjištění velikosti daného datového typu se používá operátor sizeof. Operandem je buď datový objekt (např. proměnná nebo pole) sizeof identifikátor; nebo název typu uzavřený do závorek. sizeof (datový typ); Výsledek je v bajtech.

Konstanty

Konstanta je datový prvek jehož hodnota je neměnná. Překladač přiřadí konstantě typ odpovídající hodnotě. Uvozuje se klíčovým slovem const. Dělíme je na:
Celočíselné

druhzápis
desítkovédesítkové_číslo
osmičkové0osmičkové_číslo
šestnáctkové0xšestnáctkové_číslo

C umožňuje určit typ číselných konstant pomocí sufixu. Celá čísla můžeme zapsat jako long pomocí sufixu ‘l’ nebo ‘L’, nebo bez znaménka čili unsigned pomocí ‘u’ nebo ‘U’.

Reální

druhzápis
Desetinný zápiscelá_část.desetiná_část
semilogaritmický zápismantisaeexponent nebo mantisaEexponent

Implicitní typ racionální konstanty je double. Pro typ float uvedeme číslem ‘f‘ nebo ‘F‘. Pokud za číslo dáme ‘l’ nebo ‘L’ stane se z čísla long double.

Znakové

zápisvýznam
‚znak‘řetězec

Znakové konstanty jsou jeden znak obklopený apostrofy. Proto abychom mohli ve znakových a také řetězcových konstantách zapisovat speciální a negrafické znaky používají se tzv. escape sekvence. Začínají lomítkem a využívají se zejména ve výstupních funkcích jako např. printf. Jejich seznam je následující:

zápisvýznam
\0prázdný znak (je na konci každého řetězce)
\apípnutí
\bnávrat o jeden znak zpět
\fnová stránka nebo obrazovka
\npřesun na začátek nového řádku
\rpřesun na začátek aktuálního řádku
\tpřesun na následující tabelační pozici
\vpřesun dolů
\\obrácené lomítko
\‘apostrof
\“uvozovky
\?otazník

Řetězcové

Zapisují se jako posloupnost znaků obklopená uvozovkama.

Operátory

Operátory určují operaci, kterou hodláme provést s operandem. Např.: a + b, ‚a‘ a ‚b‘ jsou operandy a ‚+‘ je operátor Dělení:dle počtu operandů: unární (1), binární (2), ternární (3) dle funkce operátorů: aritmetické, relační, logické, bitové, přiřazovací, ternární, inkrementace a dekrementace a ostatní Aritmetické

zápisvýznam
+, -, *sčítání, odčítání, násobení
/celočíselné dělení (když jsou oba operandy celé číslo), reálné dělení (když je alespoň jede operand reální číslo)
%dělení modulo, neboli zbytek po celočíselném dělení

Relační

zápisvýznam
<, <=, >, >=menší než, menší nebo rovno, větší než, větší nebo rovno
==rovnost
!=nerovnost

Logické

zápisvýznam
&&logický součin (AND)
||logický součet (OR)
!negace

Bitové

zápisvýznam
>>, <<bitovém posunu vpravo a vlevo
&logický součin (AND)
|logický součet (OR)
~negace
^XOR

Přiřazovací

zápisvýznam
=přiřazení
+=, -=, *=, /=zkrácený výraz pro proměnná=proměnná+číslo atd.
!negace

Inkrementace a dekrementace

zápisvýznam
++inkrementace, zkrácený zápis pro proměnná=proměnná+1
dekrementace, zkrácený zápis pro proměnná=proměnná-1

Ostatní operátory

zápisvýznam
(datový_typ)operátor přetypování
sizeofoperátor pro zjištění velikosti datového typu či datového objektu
&operátor adresy
()operátor volání funkce
[]operátor prvku pole
.výběr prvku struktury
->výběr prvku struktury zadané ukazatelem

Vstupní/výstupní funkce

Aby uživatel mohl s programem aktivně pracovat používáme vstupní a výstupní funkce. Formátovaný vstup a výstup zajišťují tyto funkce: scanf(„formátovacířetězec“, adresy); printf(„formátovacířetězec“, proměnné_či_výrazy); Protože jazyk C má malé jádro, musí většinu funkcí připojovat. K tomu abychom je připojili musíme do zdrojového kódu zapsat názvy hlavičkových souborů obsahující potřebné funkce. Zapisujeme je do hlavičky programu. V případě formátovaného vstupu/výstupu to je stdio.h. Přidáme jí takto:

#include <stdio.h>

Formátovaný výsup printf()

printf(„formátovacířetězec“, proměnnéči_výrazy); Formátovací řetězec se skládá z úseků textu, které se beze změny objeví na výstupu, a formátové specifikace (konverze) určující, v jakém tvaru se hodnoty proměnných či výrazů zobrazí. Každá formátová specifikace začíná znakem % a končí písmenem, které musí odpovídat typu vypisované hodnoty Výrazy či proměnné jsou čteny z leva doprava. Vkládáme-li do formátovacího řetězce více výrazů či proměnných, oddělíme je čárkami. Forátovaný vstup scanf() scanf(„formátovací_řetězec“, adresa); Formátovacím řetězcem je určena formátová specifikace vstupní hodnoty (pomocí % a odpovídajícího písmene). Adresa určuje paměťovou oblast, do níž bude odpovídající vstupní hodnota uložena a zapisuje se ve tvaru &identifikátor_proměnné. V praxi jde nejčastěji o adresu proměnné, nebo o ukazatel na pole znaků. Čtení ze vstupu probíhá tak, že první formátová specifikace je použita pro vstup první hodnoty, která se uloží na první adresu po stisku klávesy Enter atd. Čteme-li více hodnot oddělujeme adresy proměnných čárkami. Formátová specifikace Formátová specifikace má obecně tento tvar: %[.přesnost][modifikátor]konverze Konverze je označena jedním znakem, mezi znakem % a označením konverze mohou být umístěné další (nepovinné) parametry jako modifikátor či přesnost. Konverze pro printf() a scanf() jsou stejné.

konverze

Modifikátory

Přesnost

Zapisuje se desetinou tečkou. Přesnost je dekadické číslo, které pro konverze d, i, o, u, x, X znamená minimální počet cifer na výstupu, pro konverze f, e, E, znamená počet cifer za desetinnou tečkou, pro konverze g, G znamená počet významových cifer a pro konverzi s maximální počet znaků. Formátovaný vstup a výstup může vypadat třeba takto:

#include <stdio.h> 
int x,y; 
int main(){ 
   printf("Zadejte dve cisla: \n"); 
   scanf("%d %d", &x, &y); 
   printf("Soucet %d a %d je roven: %d\n", x, y, x+y); 
   printf("Rozdil %d a %d je roven: %d\n", x, y, x-y); 
   printf("Soucin %d a %d je roven: %d\n", x, y, x*y); 
   printf("Podil %d a %d je roven: %.2f\n", x, y, (float)x/y); 
   getch(); 
   return(0);
}

Znak ‚\n‘ je zde interpretován jako přechod na novou řádku. Kombinace %d, %f jsou konverze určené pro výstup hodnot po řadě typu int a float. Vstup a výstup znaků Pro vstup znaků je určena funkce getchar() ze standardního vstupu. Pro výstup znaků na standardní výstup je určena funkce putchar(). Používá se pro ně následující zápis: getchar(znak); putchar(znak); Pro vstup znaku je taky možno použít funkci getch(), která se nachází v hlavičkovém souboru conio.h. Rozdíl mezi getch() a getchar() je takový, že getch čeká na stisknutí klávesy Enter, kdežto getch() okamžitě reaguje na vstup. Sekvence Sekvencí nebo blokem se rozumí posloupnost příkazů ohraničená znaky { }. Mezi těmito závorkami mohou být libovolné jiné příkazy včetně dalších bloků. Používá se ve větvení, cyklech a funkcích. Na začátku sekvence je vhodné definovat lokální proměnné. Blok se chová jako jeden příkaz.

Větvení

Alternativa neboli větvení nám zajišťuje provedení příkazu za určité podmínky. Rozlišujeme 3 typy: úplná, neúplné, vícenásobná

Úplné

Obecný zápis vypadá takto: if (podmínka) příkaz_1; else příkaz_2; Za klíčovým slovem if následuje podmínka povinně uzavřená do závorek. Je-li podmínka pravdivá (nenulová), potom se provede příkaz_1, je-li nepravdivá (nulová), pak se provede příkaz_2 Alternativy můžeme do sebe navzájem vnořovat. Vnořená alternativa vypadá takto: if (podmínka) příkaz_1; else if (podmínka) příkaz_2; else příkaz_3; V následujícím programu se pomocí úplné vnořené alternativy zjisti zda je číslo kladné, záporné nebo nula.

#include <stdio.h> 
int a; 
int main(){ 
   printf("Zadej cislo: "); 
   scanf("%d",&a); 
   if (a>0) 
   {
      printf("Cislo je kladne"); 
   }else if (a<0) 
       {
         printf("Cislo je zaporne"); 
       }else 
       {
         printf("Cislo je nula");
       }
   getch(); 
   return(0);
}

Neúplné

Obecný zápis vypadá takto: if (podmínka) příkaz_1; Je shodná s úplnou alternativou s tím rozdílem, že v ní chybí příkaz else. Je-li podmínka nepravdivá (nulová) pokračuje se v programu dále. V tomto programu se pomocí neúplné alternativy zjisti zda je číslo kladné, záporné nebo nula.

#include <stdio.h> 
int a; 
int main()
{ 
   printf("Zadej cislo: "); 
   scanf("%d",&a); 
   if (a>0) 
   {
      printf("Cislo je kladne"); 
   }if (a<0) 
   {
     printf("Cislo je zaporne");
   }if (a==0) 
   {
      printf("Cislo je nula"); 
   }
   getch();
   return(0);
}

Vícenásobné

Zápis vícenásobné alternativy vypadá následovně: switch(selektor) { case hodnota_1: příkaz_1; break; case hodnota_2: příkaz_2; break; … case hodnota_n: příkaz_n; break; default: příkaz; } Vícenásobná alternativa switch neboli přepínač se vyhodnocuje tak, že se porovná selektor s celočíselnými nebo znakovými hodnotami ze seznamu a dojde-li ke shodě provede se příslušný příkaz. Příkaz break způsobí ukončení provádění příkazu switche. Za jeho absence by se provedly příkazy následujících case. Příkaz default není povinný a provede se v případě že podmínce nevyhovuje žádná hodnota za nabízených case. Pomocí vícenásobné alternativy můžeme zpracovat program takovéhoto zadání: Uživatel zadá počet mobilů, které chce zakoupit. Cena za jeden mobil je 6999Kč, při odběru dvou nebo tří mobilů je cena 5999Kč,při odběru 4,5, nebo 6 kusů je cena 4999Kč a při odběru nad 7 kusu je cena jednoho 3999Kč. Určete celkovou částku, kterou kupující zaplatí.

#include <stdio.h> 
int pocet,cena; 
int main(){ 
   printf("Zadej pocet mobilu: "); 
   scanf("%d",&pocet); 
   switch(pocet) {}{
      case 1:cena=6999; 
             break; 
      case 2:
      case 3:cena=5999; 
             break; 
      case 4:
      case 5: 
      case 6:cena=4999; 
             break; 
     default:cena=3999;
   } 
   printf("Cena za kus: %dKc\n",cena); 
   printf("Celkova cena: %dKc\n",pocet*cena); 
   getch(); 
   return(0);
}

Cykly

Cykly používáme v případě, že potřebujeme nějakou činnost provádět opakovaně. U cyklů používáme nějakou podmínku, která říká, kolikrát se daná činnost provede. Rozlišujeme dva typy cyklů: s podmínkou na začátku a s podmínkou na konci.

Cyklus s podmínkou na konci

Cyklus s podmínku na konci se zapisuje pomocí klíčových slov do a while. Jeho obecný zápis vypadá následovně: do příkaz; while(podmínka); Pracuje tak, že se provede tělo cyklu a poté se vyhodnotí podmínka, je-li pravdivá (nenulová) opakuje se tělo cyklu. Je-li podmínka nepravdivá (nulová) cyklu se ukončí. Tento cyklus se používá v případech, kdy potřebujeme tělo cyklu vykonat alespoň jednou. Příkladem cyklu s podmínkou na konci může být zjištění ciferného součtu zadaného čísla:

#include <stdio.h> 
int n, cislo; 
int main(){ 
   printf("Zadej cislo pro vyocet ciferneho souctu \n"); 
   scanf("%d",&n); 
   do {}
   {
      cislo=n%10+cislo; 
      n=n/10;
   }
   while((n%10)!=0); 
   printf("Ciferny soucet je %d",cislo); 
   getch(); 
   return(0);
}

Cyklus s podmínkou na začátku

Cyklus s podmínku na začátku se zapisuje pomocí klíčového slova while. Jeho obecný zápis vypadá následovně: while(podmínka) příkaz; Nejprve se vyhodnotí podmínka. Když je pravdivá (nenulová) je provedeno tělo cyklu. Když je nepravdivá (nulová) cyklus se ukončí Cyklus while se dá například použít pro výpočet faktoriálu zadaného čísla.

#include <stdio.h> 
int n, faktorial=1; 
int main()
{ 
   printf("Zadej cislo pro vyocet faktorialu \n"); 
   scanf("%d",&n); 
   if(n<0) 
   {
      printf("Faktorial zaporneho cisla neni mozny!"); 
   }else{
      while(n>0){
         faktorial=faktorial*n; 
         n--;
      }
   printf("Faktorial je %d",faktorial); 
   }
   getch(); 
   return(0);
}

Cyklus s pevným počtem opakováním

Cyklus s podmínku na začátku se může zapsat také pomocí klíčového slova for. Jeho obecný zápis vypadá takto: for(inicializace; podmínka; iterace) příkaz; Cyklus for pracuje tak, že se nejprve inicializuje proměnná, poté se vyhodnotí podmínka (je většinou tvořena relačními operátory) a při její pravdivosti se provede tělo cyklu. Při nepravdivosti se cyklus ukončí. Pak se provede iterace (nejčastěji inkrementace či dekrementace). Použijeme jej tehdy, známe-li předem počet opakování průchodů. V cyklu for můžeme inicializaci, podmínku a iteraci vynechat. Pak vytvoříme nekonečný cyklus ve tvaru: for(;;) příkaz; Cyklus for může mít třeba použití v programu ve kterém máme načíst celé kladné číslo a zjistit kterými čísly je celočíselně dělitelné.

#include <stdio.h> 
int i, cislo; 
int main()
{
   printf("Zadej cislo pro zjisteni delitelu \n"); 
   scanf("%d",&cislo); 
   for(i=1;i<cislo;i++) 
   {
      if(cislo%i==0) 
      {
        printf("%d ",i); 
      }
   }
   getch();
   return(0);
}

Break a continue

Tyto příkazy lze použít ve všech cyklech. Mění provádění cyklu. break Způsobí ukončení cyklu. Díky příkazu break dochází k větší efektivitě a pružnosti cyklů. Můžeme například upravit příklad uváděný u cyku for a vyjmout všechny jeho atributy.

#include <stdio.h> 
int i=1, cislo;
int main()
{
   printf("Zadej cislo pro zjisteni delitelu \n"); 
   scanf("%d",&cislo); 
   for(;;){
    if(i>cislo) break; 
    if(cislo%i==0) 
    {
       printf("%d ",i); i++;
    }
   } 
   getch(); 
   return(0);
}

continue

Ukončí aktuální průchod cyklem. Cyklus není ukončen a pokračuje se dalším průchodem cyklu. goto Způsobí nepodmíněný skok na návěští. Není příliš používaný, jelikož porušuje zásadu strukturovaného programování. Dal by se použít třeba takto: goto návěští; příkazy_které_se neprovedou návěští: příkaz;

Funkce

unkce je základní programovou jednotkou v jazyce C. Každý program obsahuje alespoň jednu funkci – main(). Obecně by se definice funkce dala zapsat takto: návratový_typ identifikátor_fce(formální parametry) { . . . return návratová_hodnota; } Definice funkce se skládá z hlavičky a těla. Pokud není určen návratový typ je implicitně int. Formální parametry jsou lokální proměnné platné jen v dané funkci. Čtou se zprava do leva a proto je nutné u každého uvést datový typ. Formální parametry se proto zapisují takto: dat_typ identifikátor_1, dat_typ identifikátor_2, … Jsou volány hodnotou, tedy neovlivňují hodnotu načtených skutečných parametrů. Pro volání adresou (odkazem), tedy pro předání hodnoty skutečným parametrům ve funkci užíváme pointery. Příkaz return ukončí funkci a předá nepovinnou návratovou hodnotu programové jednotce, která funkci vyvolala. Funkce může obsahovat libovolné množství příkazů return nebo ani jeden. Funkci můžeme definovat před funkcí main() nebo za main(). Definujeme-li funkci za main() musíme uvést deklaraci funkce v hlavičce programu, aby kompilátor při průchodu programem věděl o použití funkce. Deklarace vypadá stejně jako hlavička definice funkce se středníkem: návratový_typ identifikátor_fce(formální parametry); V programu pak funkci zavoláme takto: identifikátor_fce(skutečné parametry); Následujíc příklad ukazuje jak vytvořit funkci definovanou před main(). Funkce vrací absolutní hodnotu zadaného čísla.

#include <stdio.h>
float abs_hodnota(float x){
   if(x>0) return(x); 
   else return(-x);
} 
float cislo; 
int main()
{ 
   printf("Zadej cislo pro absolutni hodnotu\n"); 
   scanf("%f", &cislo); 
   printf("Absolutni hodnota cisla %.4f je %.4f", cislo, abs_hodnota(cislo)); 
   getch(); 
   return;
}

V dalším programu je funkce definována za main(), tudíž je v programu deklarace funkce.

#include <stdio.h> 
int nsd(int a, int b); 
int cislo1, cislo2; 
int main(){ 
   printf("Zadej dve cela kladna cisla\n"); 
   scanf("%d %d", &cislo1, &cislo2); 
   if(cislo1>0 && cislo2>0) 
   {
     printf("Nejvetsi spolecny delitel cisla %d a %d je %d", cislo1,
     cislo2, nsd(cislo1, cislo2)); 
   }else printf("Bylo zadano zaporne cislo!"); 
   getch(); 
   return;
} 
int nsd(int a, int b)
{ 
   int i, max; 
   for(i=1;i<=((a<b)?a:b);i++) 
   {
      if ((a%i==0)&&(b%i==0)) max=i; 
   }
   return(max);
}

Pokud chcete aby funkce nevracela žádnou hodnotu, čili vytvořit proceduru, stačí uvést jako návratovou hodnotu funkce datový typ void jako v následujícím příkladu

#include <stdio.h>
void oddelovac();
int main()
{
   oddelovac(); 
   printf("Cecko je fajn\n");
   oddelovac(); 
   printf("A mam ho strasne rad\n"); 
   oddelovac(); 
   getch(); 
   return;
} 
void oddelovac(){
   int i; 
   for(i=1;i<=20;i++) printf("*"); 
   printf("\n");
   return;
}

Rekurzivní funkce

Je funkce která při svém běhu volá sama sebe. Musí obsahovat podmínku která určí kdy se má vnoření zastavit.

#include <stdio.h> 
int faktorial(int n); 
int cislo; 
int main(){ 
   printf("Zadej ciso pro faktorial\n"); 
   scanf("%d", &cislo); 
   if(cislo<0) printf("Faktorial zaporneho cisla neni mozny!"); 
   else printf("Faktorial je %d", faktorial(cislo)); 
   getch(); 
   return;
} int faktorial(int n){
   if(n>1) return(n*faktorial(n-1)); 
   else return(1);
}

Preprocesor

Preprocesor jazyka C slouží k předpřipravení zdrojového kódu pro kompilátor. Jeho úkolem je odstraňování komentářů, vkládání hlavičkových souborů, rozvoj maker a provádění podmíněného překladu. Činnost preprocesoru řídíme pomocí tzv. direktiv preprocesoru. Direktiva preprocesoru není příkaz jazyka C, proto za ní neuvádíme středník. Každá direktiva je uvozena znakem ‚#‘ , který musí být uveden hned jako první znak na řádku. Tak určíme, že zbytek řádku je určen preprocesoru. Chceme li ovšem ať preprocesor zpracuje i text na druhém řádku musíme přidat na konec řádku znak ‚\‘.

Makra

Makro je text, který je v podstatě zdrojovým kódem. Jako se zdrojovým kódem se s ním však
pracuje až po zpracování preprocesoru, kdy se výskyt identifikátoru makra ve zdrojovém kódu nahradí textem makra. Pro definici makra používáme direktivu #define Máme dva typy maker: bez parametrů a s parametry

Makra bez parametrů

Používají se pro definování symbolických konstant, kdy místo konstanty používáme nějaké symbolické jméno. Ustáleným pravidlem je psát identifikátor makra bez parametru velkými písmeny. Zápis vypadá takto: #define identifikátor_makra text_makra Volání makra bez parametrů se provádí takto: identifikátor_makra

Makra s parametry

Obsahují formální parametry se kterými se v textu makra dále pracuje. Používají se mnohdy místo funkcí. Narozdíl od funkcí jsou rychlejší a za formální parametry mohou být načteny hodnoty libovolných datových typů. Ustáleným pravidlem je psát identifikátor malými písmeny. Obecný zápis je takovýto: #define identifikátor_makra(seznam formálních parametrů) text_makra Volají se následovně: identifikátor_makra(seznam skutečných parametrů) V tomto programu je shrnuta práce s makry na jednoduchém výpočtu objemu válce. Obsahuje makra s a bez parametru, vnořování maker a zápis makra na více řádků

#include <stdio.h> 
#define PI 3.141592653 
#define na_2(x) (x)*(x) 
#define obem_valce(r,v) PI*na_2(r)*v 
#define oddelovac for(i=1;i<=40;i++) printf("*");\ 
    printf("\n");
float polomer,vyska; 
int i; 
int main(){
  oddelovac printf("Zadej polomer a vysku valce\n"); 
  oddelovac scanf(" %f %f",&polomer,&vyska); 
  oddelovac printf("Obem valce je %.2f * %.2f * %.2f =
  %.2f\n",PI,na_2(polomer),vyska,obem_valce(polomer,vyska)); 
  oddelovac getch(); 
  return;
}

Vkládání souborů

Proto abychom mohli do našeho souboru se zdrojovým kódem připojit další soubory, ať už knihovny funkcí či další části našeho programu používáme tyto dva zápisy příkazu #include: #include #include „název_souboru“ První zápis znamená že soubor název_souboru je hledán ve standardním adresáři pro include. Takto se zpravidla začleňují standardní hlavičkové soubory. Není-li soubor nalezen, je ohlášena chyba. Druhý zápis znamená že soubor název_souboru je hledán v pracovním adresáři. Není-li tam nalezen, postupuje se podle první možnosti. Takto se zpravidla začleňují uživatelské hlavičkové soubory.

Alokace paměti

Alokace paměti je vymezení místa v paměti pro proměnnou. Každé proměnné musí být během své existence přidělen paměťový prostor, který je dán datovým typem. Jméno proměnné je vlastně symbolická adresa tohoto prostoru. Data dělíme na: statické a dynamické

Statické

sou to data u nichž známe v době překladu jejich velikost a identifikátor. Jsou to globální proměnné, které mají tu vlastnost, že se automaticky nulují, vznikají spuštěním programu a zanikají na jeho konci. Ke statickým proměnným se řadí také lokální proměnné, které mají tu vlastnost, že nejsou automaticky nulované a jejich platnost končí koncem funkce či bloku.

Dynamické

Dynamické data jsou data které nemají předem stanovenou velikost. Alokaci provádíme speciálním příkazem za běhu programu. Dynamické proměnné nemají svůj identifikátor. Přistupujeme k nim pomocí pointerů.

Paměťové třídy

Kromě identifikátoru a datového typu jsou proměnné určeny ještě paměťovou třídou, které náleží. Paměťová třída určuje kde bude proměnná v paměti uložena, jakou bude mít viditelnost a jakouživotnost. Paměťové třídy se zapisují v následujícím formátu: název_pam_třídy datový_typ identifikátor_proměnné; Existují tyto paměťové třídy: auto, extern, statis, register auto Paměťová třída je implicitně používána pro všechny lokální proměnné. Paměť se pro ně alokuje automaticky až při vstupu do bloku, ve kterém jsou definovány. Po opuštění bloku je tato paměť zase uvolněna. Tato proměnná je viditelná jen v rámci bloku, ve kterém je definována. Existuje– li vedle této automatické proměnné i nějaká globální proměnná se stejným identifikátorem, je zastíněna automatickou proměnnou.

extern

Implicitní paměťová třída pro globální proměnné. Má využití při odděleném překladu. Je-li třeba, aby dva či více modulů sdílelo tutéž proměnnou v jednom souboru bude definována proměnná bez slova extern a ve všech ostatních zapíšeme klíčové slovo extern. Proměnné s paměťovou třídou extern nelze inicializovat! static Tato paměťová třída je použitelná jak pro lokální tak pro globální proměnné. Statické lokální proměnna je viditelná jen ve funkci, kde je definována. Paměť pro takovou proměnnou je alokována při spuštění dané funkce a uvolněna je až po skončení programu. Z toho vyplývá, že, máme-li statickou proměnnou a opustíme blok, ve kterém byla definována, tato proměnná nezaniká, pouze již není viditelná (ponechává si svou hodnotu mezi jednotlivými voláními funkce) Pro globální proměnné má paměťová třída static poněkud odlišný význam. Používá se při odděleném překladu. Při jejím použití by jsme nadefinovali globální neexportovatelnou proměnnou. To znamená že globální proměnné paměťové třídy static jsou viditelné pouze v modulu ve kterém jsou definovány. register Používá se pro lokální proměnné. Proměnná je viditelná pouze v bloku ve kterém je definována. Je alokována do registru, není-li v něm místo alokuje se do zásobníku. Pro nejasnost alokace nelze použít operátor adresy &. Jelikož třída register zvyšuje rychlost přístupu, používá se pro často používané proměnné (např. řídící proměnné cyklu). Program ukazuje použití modifikátoru register a static pro lokální proměnné.

#include <stdio.h> 
void fce(void); 
int main()
{ 
   register int i; 
   for(i=0;i<5;i++) fce(); 
   getch(); 
   return;
} 
void fce(void)
{ 
   static int x=0; 
   x++; 
   printf("Funkce byla volana %dx \n",x);
}

Pointery

Ukazatel (pointer) je v Céčku statická celočíselná proměnná obsahující adresu jiné statické či dynamické proměnné. Nese sebou současně informaci o datovém typu, který se na této adrese nachází. Pointer na proměnnou určitého datového typu se deklaruje pomocí operátoru dereference ‚*‘: datový_typ *identifikátor_pointeru; Uložení adresy do pointeru se liší dle toho zda pointer ukazuje na statickou či dynamickou proměnnou. Díky operátoru reference ‚&‘ uložíme do pointeru adresu statické proměnné: identifikátor_pointeru=&identifikátor_proměnné;

A takto do pointeru uložíme adresu a vyalokujeme prostor pro dynamickou proměnnou: identifikátor_pointeru=(datový_typ *)malloc(sizeof(datový_typ)); Výše uvedený zápis se dá přeložit následovně. Funkce malloc() je funkce, která alokuje paměťový prostor v haldě. Jejím parametrem je počet bytů potřebný pro alokaci. Ten jsme zjistili operátorem pro zjištění velikosti datového typu sizeof(). Jelikož funkce malloc() vrací ukazatel na datový typ void (generický pointer na libovolný datový typ) je nutné tento pointer přetypovat pomocí operátoru přetypování (datový_typ *). V případě, že se nepodaří požadovanou paměť alokovat, vrací funkce hodnotu NULL. Proto lze do programu zapsat následující test zda alokace proběhla: if(identifikátor_pointeru==NULL) printf(„Chybna alokace pameti\n“);
Pro samotné uložení hodnoty na místo kde ukazuje pointer se používá tento zápis: *identifikátor_pointeru=hodnota; Při použití pointeru na dynamickou proměnnou se musíme po ukončení práce s pointerem postarat o uvolnění paměti: free(identifikátor_pointeru); A proto aby pointer neodkazoval na místo, které již neexistuje měli bychom ho ukotvit: identifikátor_pointeru=NULL; Následující příklad ukazuje jak pracovat s dynamickými pointery.

#include <stdio.h> 
int main(){ 
   float *a,*b; 
   a=(float *)malloc(sizeof(float)); 
   b=(float *)malloc(sizeof(float)); 
   printf("Zadej dve cisla\n"); 
   scanf("%f %f",a,b); 
   (*a > *b)?printf("%f je vetsi nez %f \n", *a, *b):printf("%f je mensi nez %f \n",   *a, *b); 
   printf("Soucet: %.2f\n",*a+*b); 
   printf("Rozdil: %.2f\n",*a-*b); 
   printf("Soucin: %.2f\n",*a**b); 
   printf("Podil: %.2f\n",(*a)/(*b)); 
   getch(); 
   return;
}

Pointery a funkce

Pomocí pointerů realizujeme funkce které vracejí více hodnot. Realizuje se to pomocí
proměnných, které jsou vně funkce a my s nimi ve funkci můžeme pomocí pointerů pracovat neboli přidat jim určitou hodnotu. Hovoříme o formálních parametrech volaných adresou. V kapitole Funkce jsme vždy používali tzv. formální parametry volané hodnotou, které nemají vliv na skutečný parametr. Definice funkce, která vrací více hodnot by mohla vypadat takto: návratový_typ identifikátor_fce(formální parametry, dat_typ *pointer) { .. .
*pointer=výstupní_hodnota; return návratová_hodnota; }
A v programu by jsme takovouto funkci volali následovně: identifikátor_fce(skutečné parametry, &identifikátor_proměnné); Následující program demonstruje použiti pointerů realizujících návrat více hodnot z funkce.

#include <stdio.h> 
void vypocty(int a, int b, int *sou, int *roz, int *souc, float *pod); 
int main()
{ 
   int x,y,soucet,rozdil,soucin; 
   float podil; 
   printf("Zadejte prosim dve cela cisla\n"); 
   scanf("%d %d",&x,&y); 
   vypocty(x,y,&soucet,&rozdil,&soucin,&podil); 
   printf("%d + %d = %d\n",x,y,soucet); 
   printf("%d - %d = %d\n",x,y,rozdil); 
   printf("%d * %d = %d\n",x,y,soucin); 
   printf("%d / %d = %.2f\n",x,y,podil); 
   getch(); 
   return;
} 
void vypocty(int a, int b, int *sou, int *roz, int *souc, float *pod)
{ 
   *sou=a+b; 
   *roz=a-b; 
   *souc=a*b; 
   *pod=(float)a/b; 
   return;
}

Pole

Je strukturovaný homogenní datový typ. To znamená že, obsahuje několik prvků stejného datového typu se kterými můžeme pracovat. Pole je v podstatě pointer obsahující adresu nultého prvku pole. Může být statické či dynamické. Statické pole U statického pole je nutné znát počet prvků během překladu. Deklarujeme ho následovně dat_typ identifikátor[počet_prvků]; Pole může nabývat hodnot kteréhokoli základního datového typu. K hodnotám pole přistupujeme pomocí indexů. Jelikož C indexuje od nuly můžeme přistupovat k prvkům od indexu 0 až počet_prvků-1. Takový přístup by vpadal takto: identifikátor[index]

Hodnoty pole pod jednotlivými indexy jsou v paměti ukládány za sebou. Je třeba si uvědomit, že překladač jazyka C neprovádí kontrolu mezí. Proto je možné pracovat indexy pole, které jsou větší než námi nadefinovaný nejvyšší index. To ovšem může způsobit katastrofální následky, jelikož pracujeme s části paměti, která nebyla alokována. Pole je možno hned při deklaraci inicializovat: dat_typ identifikátor[počet_prvků]={hodnota_1, hodnota_2, …}; Chceme-li pole setřídit použijeme nějakou třídící metodu. Nejjednodušší, ale zároveň docela pomalou je Bubble Sort:

for(i=0; i<pocet_prvku-1;i++)
for(j=0; j<pocet_prvku-1;j++)
if(pole[j]<pole[j+1]){ pom=pole[j];
pole[j]=pole[j+1];
pole[j+1]=pom;
}

Dynamické pole

Není nutné znát během překladu počet prvků, můžeme je vyalokovat až při samotném běhu programu. Při překladu je ovšem nutné znát bázový typ pole. Deklaruje se stejně jako pointer, tedy takto: dat_typ *identifikátor; Alokace pole se obecně zapisuje následně: identifikátor=(datový_typ *)malloc(sizeof(datový_typ)*počet_prvků); Samotná práce s dynamickým polem je shodná s prací se statickým polem. Dynamické pole ovšem musíme jakožto dynamickou proměnnou uvolnit: free(identifikátor); a také zakotvit: identifikátor=NULL; Příklad pro práci s dynamickým polem je obdoba příkladu pro statické pole:

#include <stdio.h> 
int main()
{ 
   int i,j,*pole,pocet,max,min,sum=0,pom; 
   printf("Zadej pocet prvku pole: "); 
   scanf("%d",&pocet); 
   pole=(int *)malloc(sizeof(int)*pocet); 
   printf("Zadavej prvky pole: \n"); 
   for(i=0;i!=pocet;i++) scanf("%d",&pole[i]); 
   max=pole[0]; 
   min=pole[0]; 
   for(i=0;i!=pocet;i++) 
   { 
      if(pole[i]>max) max=pole[i]; 
      if(pole[i]<min) min=pole[i]; 
      sum+=pole[i]; 
   }
   printf("\nMaximum je %d\n",max); 
   printf("Minimum je %d\n",min); 
   printf("Stredni hodnota je %.2f\n",(max+min)/2.0); 
   printf("Aritmetricky prumer je %.2f\n",(float)sum/i);
   for(i=0;i!=pocet-1;i++) 
   for(j=0;j!=pocet-1;j++) if(pole[j]>pole[j+1]) { 
      pom=pole[j+1]; 
      pole[j+1]=pole[j]; 
      pole[j]=pom; 
   }
   printf("\nSetrizene pole: "); 
   for(i=0;i!=pocet;i++) printf("%d ",pole[i]); 
   free(pole); 
   pole=NULL; 
   getch(); 
   return;
}

Pole a funkce

Je-li proměnná typu pole (tzn. ukazatel na první prvek) parametrem funkce užíváme adresu pole
(volání odkazem). To proto aby se změna pole zachovala i po návratu z funkce. Obecný zápis hlavičky funkce jejíž parametr je statické pole je takovýto: dat_typ id_fce(dat_typ pole[], int pocet, …) Hlavička funkce jejíž parametr je dynamické pole s e zapisuje obdobně: dat_typ id_fce(dat_typ *pole, int pocet, …) Z těchto zápisů je zřejmé, že je nutné zavést jako parametr funkce taky celočíselnou proměnnou pocet, která uchovává informaci o počtu prvků pole a slouží tak pro kontrolu mezí. Volání funkce v hlavní části programu se provádí takto: id_fce(pole,pocet, …); Pro ilustraci pole jakožto parametru funkce je užit příklad pro statické pole s tím, že načítání, výpis, setřízení a zjišťování maxima a minima je zajištěno funkcemi.

#include <stdio.h> 
#define POCET 8 const nil=0; 
void nacti(int pole[], int poc); 
void vypis(int pole[], int poc); 
void zjisti(int pole[], int poc, int *max, int *min, int *sum); 
void setrid(int pole[], int poc); 
int main()
{ 
	int pole[POCET],max,min,soucet=0; 
	printf("Zadej prvky pole:\n"); 
	nacti(pole,POCET); max=pole[nil];
	min=pole[nil]; 
	zjisti(pole,POCET,&max,&min,&soucet); 
	printf("\nMaximum je %d\n",max); 
	printf("Minimum je %d\n",min); 
	printf("Stredni hodnota je %.2f\n",(max+min)/2.0); 
	printf("Aritmetricky prumer je %.2f\n",(float)soucet/POCET); 
	printf("\nSetrizene pole:\n"); 
	setrid(pole,POCET); 
	vypis(pole,POCET); 
	getch(); 
	return;
} 
void nacti(int pole[], int poc)
{
	int i; 
	for(i=nil;i<poc;i++) scanf("%d",&pole[i]); 
	return;
} 
void vypis(int pole[], int poc)
{
	int i; 
	for(i=nil;i<poc;i++) printf("%d ",pole[i]); 
	return;
} 
void zjisti(int pole[], int poc, int *max, int *min, int *sum)
{
	int i; 
	for(i=nil;i!=poc;i++) { 
		if(pole[i]>*max) *max=pole[i];
	if(pole[i]<*min) *min=pole[i]; 
	*sum+=pole[i]; 
	}
	return;
} 
void setrid(int pole[], int poc) 
{
	int i,j,pom; 
	poc--; 
	for(i=nil;i!=poc;i++) 
	for(j=nil;j!=poc;j++) 
	if(pole[j]>pole[j+1]) { 
		pom=pole[j+1]; 
		pole[j+1]=pole[j]; 
		pole[j]=pom; 
	}
	return; 
}

Matice

Je to pole polí, přičemž prvky jsou uloženy v paměti za sebou. Indexuje se od nuly. Deklaruje se takto: dat_typ id_matice[řádky][sloupce]; Inicializuje se tímto způsobem: id_matice[][3]={{1,2,3},{4,5,6},{7,8,9},{10,11,12},…}Z tohoto zápisu vyplývá že uvedení počtu sloupců je povinné, uvedení počtu řádků je nepovinné.

Dynamická matice se realizuje třemi způsoby: jako pole pointerů, pointer na pole nebo pointer na pointer.

Pointer na pole

Je realizováno pomocí ukazatele který ukazuje na souvislý blok v haldě. Při deklaraci je nutné znát počet sloupců na řádek. Deklarace je takováto: dat_typ (id_pole)[počet_sloupců]; Alokace v dynamické paměti se zapisuje takto: id_pole=(typ ()[])malloc(sizeof(typ)počet_sloupcůpočet_řádků); Po ukončení práce je nutné místo v paměti odalokovat a pointer ukotvit: free(id_pole); id_pole=NULL;

#include <stdio.h> 
#define S 3
int main()
{ 
	int i,j; 
	int (*matice)[S]; /* pocet sloupcu je znam pri prekladu */
	srand((long)time(NULL)); 
	printf("\nMatice - pointer na pole:"); 
	printf("\n");
	matice=(int(*)[])malloc(2*S*sizeof(int));
	for (i=0;i<2;i++)
	{
		for (j=0;j<S;j++)
		{
			matice[i][j]=rand()%100; printf("%4d",matice[i][j]);
		} 
		printf("\n");
	}
	getch(); 
	return 0;
}

Pointer na pointer

Je to pointer který ukazuje na dynamické pole pointerů v haldě (symbolizuje řádků), jednotlivé prvky pole obsahují pointery ukazující na další dynamické pole (symbolizuje sloupce). Jednotlivé řádky nemusí být v paměti uloženy za sebou. Deklaruje se takto: dat_typ **id_pole; Pro alokaci dynamického pole symbolizující počet řádků se užije tento zápis: id_pole=(typ **)malloc(sizeof(typ *)*počet_řádků); Alokace jednotlivých řádků se zapíše následně: id_pole[index]=(typ *)malloc(sizeof(typ)*počet_sloupců); Ukončení-li práci odalokujeme oblast v dynamické paměti, která zabírá jednotlivé řádky: free(id_pole[index]); Poté musíme odalokovat pole obsahující pointery: free(id_pole); A pak už jen ukotvit pointer id_pole=NULL;

#include <stdio.h> 
int main()
{ 
	int i,j; int **matice; /* pocet radku, sloupcu neni znam pri prekladu */
	srand((long)time(NULL)); 
	printf("\nMatice - pointer na pointer:"); 
	printf("\n");
	matice=(int**)malloc(2*sizeof(int*)); /* radky */
	matice[0]=(int*)malloc(3*sizeof(int)); /* pocet prvku na radce */ 
	matice[1]=(int*)malloc(3*sizeof(int));
	for (i=0;i<2;i++)
	{ 
		for (j=0;j<3;j++)
		{
			matice[i][j]=rand()%100; 
			printf("%4d",matice[i][j]);
		} 
		printf("\n");
	}
	getch(); 
	return 0;
}

Řetězce

V jazyku C není definován datový typ řetězce, místo toho je využíváno pole znaků ukončené nulovým znakem, čili znakem s ASCII hodnotou nula (Zapisujeme ho takto: ‚\0‘). Skutečnost ukončení nulovým znakem znamená, že musíme nadefinovat pole o jeden byte delší, aby zbylo místo pro nulový znak. Řetězec deklarujeme takto: char id_řetězce[velkost]; Inicializovat lze dvěma způsoby, buď takto: char id_řetězce[]={‚a‘,’h‘,’o‘,’j‘,’\0′}; nebo takto: char id_řetězce[]=“ahoj“; Tento zápis je zcela ekvivalentní s předchozím. Pro pole je vyhrazeno 5 bytů, do kterých je uložen řetězec „ahoj“ včetně nulového znaku. Načítání a výpis řetězce můžeme provádět pomocí scanf() a printf(), ale taky pomocí funkcí přímo určených pro čtení a výpis řetězců gets() a puts(). Funkce gets() při načítání čte narozdíl od scanf(), která načítá pouze po první výskyt bílého znaku, vše co zapíšeme. Práce s řetězcem je shodná jako práce s polem, lze tedy například užít pointerovou aritmetiku.

Funkce pro řetězce

Pro řetězec jsou v C předdefinovány funkce strcpy(),strcat(),strcmp(),strlen(). Pro jejich použití je nutno připojit hlavičkový soubor string.h.

strcpy() Slouží pro překopírování obsahu zdroje do cíle, přičemž zdroj zůstane nezměněn. Musíme zajistit to aby byl cíl dostatečně velký. Má obecný tvar: strcpy(zdroj,cíl);

strcat() Slouží pro přidávání obsahu zdroje k obsahu cíle (zřetězení). Musíme zajistit to, že je cílové pole dostatečně velké. Obecný zápis: strcat(zdroj,cíl);

strcmp() Funkce porovnává dva řetězce. Řetězce jsou porovnávány lexikograficky, tj. ve slovníkovém pořadí. Jsou-li řetězce shodné, vrací funkce nulu. Je-li první větší než druhý, vrací 1 a je-li první menší než druhý vrátí funkce -1. Obecný zápis: strcmp(řetězec_1,řetězec_2);

strlen() Tato funkce vrací délku řetězce ve znacích. Do délky řetězce se nezapočítává koncový nulový znak. Zapisuje se následně: strlen(řetězec); Příklad uvedený níže ukazuje varianty načítání řetězce, zjišťování délky a porovnání.

#include <stdio.h> 
#include <string.h> 
int main()
{ 
	int indikace; 
	char retezec_1[20],retezec_2[20],vysledek; 
	gets(retezec_1); 
	scanf("%s",retezec_2); 
	printf("retezec_1 (%s) ma delku %d\n",retezec_1,strlen(retezec_1)); 
	printf("retezec_2 (%s) ma delku %d\n",retezec_2,strlen(retezec_2)); 
	indikace=strcmp(retezec_1,retezec_2); 
	if(indikace==0) puts("Retezce jsou shodne"); 
	else if (indikace==1) puts("retezec_1 je lexikograficky vetsi nez retezec_2"); 
	else if (indikace==-1) puts("retezec_2 je lexikograficky vetsi nez retezec_1");
	getch(); 
	return;
}

Soubory

V programovacím jazyku C se provádí diskové I/O pomocí logického rozhraní nazývaného datový proud. Datové proudy mají podobné vlastnosti a jsou zpracovávány stejnými I/O funkcemi. Soubor je skutečný fyzický výskyt, který přijímá nebo poskytuje data. V C existují dva typy souborů. Textový a Binární, liší se použitím I/O funkcí. Základní rozdíl mezi těmito dvěma typy souborů je v tom, že v binárním souboru jsou data ukládána stejným způsobem jako v paměti. Kdežto do textového souboru se musí data převést na posloupnost znaků. V hlavičkovém souboru stdio.h je pro práci s nimi zaveden datový typ FILE, který je strukturou obsahující různé informace o souboru, například velikost, aktuální pozici a jeho přístupové režimy, které určují jak k souboru přistupovat. Proměnnou soubor si nadeklatujeme jako ukazatel na typ FILE. FILE *id_souboru Před tím než budeme se souborem pracovat musíme ho nejdřív otevřít. To provedeme pomocí funkce fopen(), která vrací ukazatel na daný soubor. Je-li tato funkce neúspěšná, vrací NULL. id_souboru=fopen(„jméno.přípona“,“režim“); Pro textové souory existují následující režimy:

režimvýznamrežim pro binární soubory
rotevře textový soubor pro čtenírb
wvytvoří textový soubor pro zápis (přepíše existující)wb
aotevře textový soubor pro připisováníab
R+otevře textový soubor pro čtení/zápisrb+
W+vytvoří textový soubor pro čtení/zápiswb+
A+otevře textový soubor pro čtení/připisováníab+

Pokud soubor neexistuje, při většině režimech se vytvoří. Pouze při r,r+,rb,rb+ se soubor nevytvoří a fopen() selže. Jelikož operace otevření nemusí proběhnout je vhodné ji ošetřit testem a raději používat tento zápis: if(id_souboru=fopen(„jméno.přípona“,“režim“)==NULL){printf(„Chyba pri otevreni souboru“); return;} Pro ukončení práce se souborem použijeme funkci fclose(), která zavře soubor a odpojí datový proud. Je nutné soubor zavřít jestliže chceme ať se v něm projeví změny. fclose(id_souboru); Při úspěchu vrací nulu, při chybě vrací symbolickou konstantu EOF. Pro kontrolu úspěšnosti je vhodnější používat tento zápis: if(fclose(soubor)==EOF){printf(„\nChyba pri uzavreni souboru“); return;} Další funkce souborového systému Patří mezi ně funkce rename(), remove(), rewind(), feof() a fflush().

rename() Slouží pro přejmenování souboru. Obecně se zapisuje: rename(„staré_jméno“,“nové_jméno“); Při úspěchu vrací funkce nulu, při neúspěchu nenulovou hodnotu.

remove() Smaže daný soubor. Zápis je: remove(„jméno_souboru“); Při úspěchu vrací funkce nulu, při neúspěchu nenulovou hodnotu.

rewind() funkce přesune aktuální pozici v souboru na jeho začátek.

rewind(id_souboru); Je bez návratové hodnoty jelikož každý úspěšně otevřený soubor lze nastavit na začátek.

feof() Tato funkce se používá k zjišťování konce souboru. Je-li aktuální pozice na konci vrací nenulovou hodnotu. Jestliže ne vrací nulu. feof(id_souboru);

fflush() Funkce slouží k vyprázdnění diskového bufferu. fflush(datový_proud) Využívá se pro vyprázdnění standardního datového proudu pro čtení z klávesnice stdin (standardní vstup).

Pro souborový vstup/výstup znaku se užívají funkce getc(), putc(). Tento postup se užívá jak pro textové, tak pro binární soubory getc() nebo fgetc() Tato funkce je určena pro vstup znaků ze souboru. Zapisuje se takto: fgetc(id_souboru); Má jediný parametr typu ukazatel na FILE, návratovou hodnotou této funkce je kód znaku, přečtený z určeného souboru. Při konci souboru či chybě vrací symbolickou konstantu EOF. putc() nebo fputc() Funkce je určena pro výstup znaků do souboru. fputc(znak,id_souboru); Má jako první argument kód znaku, který má být zapsán do souboru, který je identifikován druhým parametrem. Návratová hodnota funkce je kód zapsaného znaku, nebo EOF pokud při výstupu došlo k chybě. V následující ukázce nejprve zapíšeme do souboru text a poté se vytvoří kopie tohoto souboru.

#include <stdio.h> 
#include <conio.h>
int main(void)
{ 
	FILE *fr,*fw; char c;
	fw=fopen("original.txt","w"); 
	printf("Zapiste text ukonceny '.'\n"); 
	do 
	{ 
		scanf("%c",&c); 
		putc(c,fw);
	} while (c!='.'); 
	fclose(fw);
	fr=fopen("original.txt","r"); 
	fw=fopen("kopie.txt","w"); 
	while (feof(fr)==0) putc(getc(fr),fw); 
	fclose(fr); 
	fclose(fw);
	printf("\nSoubor byl zkopirovan!"); 
	fflush(stdin); 
	getch(); 
	return(0);
}
Back to Top