Skočiť na obsah


Programovanie v jazyku C a C#

Návody pre začiatočníkov a pokročilých



Fórum: Škôlka jazyka C
- - - - -
Fotografia

9. lekcia C (Štruktúry, uniony a výčtové typy) základná škola


9 Štruktúry, uniony a typy vymenovaním

9.1 Štruktúry

Zatiaľ čo pole je homogénny údajový typ - všetky jeho prvky sú rovnakého typu - je štruktúra údajový typ heterogénny. Heterogénny znamená, že údajový typ je zložený (v podstate ľubovolne) z údajových prvkov rôznych typov, čo je ale jeho vnútorná záležitosť, pretože navonok vystupuje ako jednoliaty celok.

struct {

	polozky;

} a;
9.1.1 Definície a základne schopnosti

V C je možné definovať štruktúru a definovať premenné typu štruktúra piatimi nasledujúcimi spôsobmi. Budeme požadovať štruktúru zlozenú z dvoch položiek - výška a váha a chceme mať tri premenné typu štruktúra - Pavol, Jozef a Karol.


Päť spôsobov definície štruktúry:

1) Základny spôsob. Vytvorená štruktúra nie je pomenovaná a nedá sa teda nikde ďalej v programe využiť. Dajú sa však využívať definované premenné Pavol, Jozef a Karol.

struct {

	int vyska;

	float vaha;

} Pavol, Jozef, Karol;
2) Modifikácia základného spôsobu, kde je štruktúra pomenovaná mierami a dá sa teda využiť aj neskôr v programe (viď tiež nasledujúci spôsob)
struct miery {

	int výška;

	float váha;

} Pavol, Jozef, Karol;
3) Je to predchádzajúci spôsob, kde je len oddelená definícia štruktúry od definície premenných. Je vidieť, že definícia premenných sa môže urobiť i viackrát, čo nebolo v prvom prípade možné.
struct miery { /* definícia štruktúry */

	int výška;

	float váha;

};

struct miery Pavol; /* definícia premenných */

struct miery Jozef, Karol;
Pozor na častú chybu - nie je možné definovať premenné tymto spôsobom:
miery Pavol, Jozef, Karol; /* chyba */
4) Definícia nového typu štruktúry pomocou príkazu typedef. Štruktúra nie je pomenovaná, čo nám príliš nevadí, pretože nový typ štruktúry je pomenovaný (MIERY) a dá sa teda ďalej ľubovolne používať, napr. pre definície premenných, pretypovanie, ...
typedef struct { /* definícia typu štruktúry */

	int výška;

	float váha;

	} MIERY;

MIERY Pavol, Jozef, Karol; /* definícia premenných */
Všimnite si, že v definícii premenných, na rozdiel od predchádzajúceho spôsobu, nie je použité kľúčove slovo struct.

5) Modifikácia predchádzajúceho spôsobu, kde je pomenovaná ako štruktúra, tak aj nový typ štruktúry. Pre použitý príklad nemá tento spôsob opodstatnenie, ale je nutné ho použiť, keď štruktúra odkazuje sama na seba - viď ďalší text.
typedef struct miery { /* definícia typu štruktúry */

	int výška;

	float váha;

} MIERY;

MIERY Pavol, Jozef, Karol; /* definícia premenných */
Odporúča sa pomenovávať štruktúru aj nový typ rovnako, poprípade ich rozlíšiť iba veľkosťou písmen.

Poznamka:
* Prax ukazuje, že je najvýhodnejšie používať dva naposledy uvedené typy, pretože kľúčove slovo struct použijeme iba raz, a potom už pracujeme iba s novým typom - zdrojový text je kratší a prehladnejší. Tieto spôsoby definície štruktúry budú v ďalšom texte výhradne použivané.

Prístup k prvkom štruktúry je pomocou bodkovej notácie.

Pavol.vyska = 186;

Karol.vaha = 89.5;

Jozef.vyska = Pavol.vyska;
Štruktúry sa často používajú v kombinácii s poliami. Väčšinou sa jedná o pole štruktúr, ale je samozrejme možný i opačný spôsob - pole v štruktúre. Pole štruktúr sa definuje úplne rovnako, ako akékoľvek iné pole, napr.:
MIERY ludia[100];
potom je pristup k prvkom štruktúry:
ludia[50].výška = 176;
K & R verzia jazyka C neumožňovala pracovať naraz s celou štruktúrou. Napr. príkaz: Jozef = Karol; nebol možný. Toto obmedzenie už v ANSI C nie je, takže v programe je možný napr. príkaz, ktorý skopíruje obsah jednej štruktúry do druhej pomocou jedného priraďovacieho príkazu.

Priklad:
typedef struct {

	int vyska;

	float vaha;

} MIERY;



typedef struct {

	int a[10];

} STR_POLE;



main() {

	MIERY Pavol, Jozef;

	STR_POLE aaa, bbb;



	Pavol.vyska = 186;

	aaa.a[1] = 5;

	Jozef = Pavol;

	bbb = aaa;

}
Poznamka:
* Všimnite si triku so STR_POLE, pomocou ktorého je možné pracovať s celým poľom naraz.


9.1.2 Štruktúry a pointery

Pointery na štruktúry majú dve veľké oblasti použitia:

* pri práci so štruktúrami v dynamickej pamäti,
* pri práci so štruktúrou vo funkcii.

Pointer na štruktúru sa definuje už známym spôsobom:
typedef struct {

	char meno[30];

	int rocnik;

} STUDENT;



STUDENT s, *p_s;
Kde s je štruktúra typu STUDENT a p_s je pointer na štruktúru typu STUDENT, ktorá nemá samozrejme zatiaľ pridelenú pamäť. Pamäť pre štruktúru je možné dynamicky prideliť opäť pomocou funkcie malloc(), napr.:
p_s = (STUDENT *) malloc(sizeof(STUDENT));
Pointer je možné samozrejme použiť pre odkaz na už existujúcu štruktúru, teda napr.:
p_s = &s;
Občas sa definuje aj nový typ pointer na štruktúru, napr.:
typedef struct {

	char meno[30];

	int rocnik;

} STUDENT, *P_STUDENT;



STUDENT s;

P_STUDENT p_s;

p_s = (P_STUDENT) malloc(sizeof(STUDENT));
Ak máme definície:
STUDENT s, *p_s = &s;
potom je možné do štruktúry s pristupovať:

* pomocou mena strutkury s ( s.rocnik = 3; )
* pomocou pointeru p_s - komplikovane ( (*p_s).rocnik = 4; )
* pomocou pointeru p_s - jednoduchšie ( p_s->rocnik = 4; )

Pozor:
príkaz
*p_s.rocnik = 4;
je chybný, pretože operátor bodka (.) má vyššiu prioritu ako operátor (*).
V tomto prípade by bol príkaz vyhodnotený ako *(p_s.rocnik) = 4; čo znamená:
"na adresu, kde ukazuje obsah premennej p_s.rocnik zapíš hodnotu 4"

Prístup k prvkom statickej a dynamickej štruktúry:
s.rocnik = 4;

p_s->rocnik = 4;
9.1.3 štuktúry odkazujúce samy na seba

Jazyk C nedovoľuje v definícii štruktúry priamy odkaz sám na seba - rekurziu, napr.:

struct data {

	struct data d;	/* chyba */

	...

}
Tento nedostatok je možné ale jednoducho obísť pomocou pointeru, keď je možné v štruktúre definovať odkaz sám na seba.
typedef struct polozka {

	int hodnota;

	struct polozka *p_dalsi;

} POLOZKA;
Pozor:
Častou chybou býva táto definícia:
typedef struct {

	int hodnota;

	POLOZKA *p_dalsi;	/* chybne */

} POLOZKA;
pretože, v okamihu, keď definujeme položku štruktúry p_dalsi, nie je ešte známy typ štruktúry POLOZKA.

Poznámka:
* Prvku *p_dalsi štruktúry POLOZKA sa občas hovorí dynamický prvok štruktúry. Je to protiklad ku statickému prvku štruktúry z nasledujúcej podkapitoly.

Priklad:
Nasledujúci program predstavuje spojový zoznam. Najprv sa zoznam vytvorí a inicializuje hodnotami 1n. Potom sa zoznam prejde a vynechá sa každá položka, ktorej hodnota je deliteľná k. Nakoniec sa zoznam vytlačí. Využíva sa tu skutočnosť, že posledný prvok zoznamu ukazuje na NULL.
#include <stdio.h>

#include <stdlib.h>



typedef struct prvok {

	int hodnota;

	struct prvok *p_dalsi;

} PRVOK;



PRVOK *alokuj_a_testuj(void)

{

PRVOK *p_pom;

p_pom = (PRVOK *) malloc(sizeof(PRVOK));

if (p_pom == NULL) {

	printf("Malo pamati\n");

	exit(1);

}

return p_pom;

}



int main(void)

{

	int i, n, k;

	PRVOK *p_akt, *p_prv, *p_pred;



	printf("Zadaj pocet prvkov zoznamu : ");

	scanf("%d", &n);



	printf("Kazdy k-ty vyradit ( 1 <= k <= %d): ", n);

	scanf ("%d", &k);



	/* vytvorenie prveho prvku */

	p_prv = alokuj_a_testuj();

	p_prv->hodnota = 1;

	p_prv->p_dalsi = NULL;

	p_akt = p_prv;



	/* vytvorenie vsetkych ostatnych provkov */

	for (i = 2; i <= n; i++) {

		p_akt->p_dalsi = alokuj_a_testuj();

		p_akt = p_akt->p_dalsi;

		p_akt->hodnota =i;

		p_akt->p_dalsi = NULL;

	}

	for (p_pred = p_akt = p_prv; p_akt != NULL; ) {

		if ((p_akt->hodnota % k) == 0) {

			if (p_prv == p_akt) {

				p_prv = p_akt->p_dalsi;

				p_pred = p_prv;

			}

			else {

				p_pred->p_dalsi = p_akt->p_dalsi;

			}

			free((void *) p_akt);

			p_akt = p_pred;

		}

		else { /* nic sa nevyhadzovalo - normalny prechod na dalsi */

		 p_pred = p_akt;

		 p_akt = p_akt->p_dalsi;

		}

	}

	for (p_akt = p_prv; p_akt != NULL; p_akt = p_akt->p_dalsi) {

		printf("%2d [%p]\n", p_akt->hodnota, p_akt);

	}



	/* zaverecne uvolnenie pamati */

	for (p_akt = p_prv; p_akt != NULL; ) {

		p_prv = p_akt;

		p_akt = p_akt->p_dalsi;

		free((void *) p_prv);

	}

	return 0;

}
9.1.4 Štruktúra v inej štruktúre

V praktických príkladoch je častý prípad, keď potrebujeme mať ako prvok štruktúry inú štruktúru.

Poznámky:
* Prvkom štruktúry je tu myslený ako statický prvok vo význame, že celá štruktúra, ktorej typ musí byť definovaný skôr, je uložená vnútri inej štruktúry. V predchádzajúcej podkapitole sme si ukázali ako by vyzeral dynamický prvok - v štruktúre bol uložený iba pointer na inú štruktúru, ktorá však nebola časťou štruktúry pôvodnej.
* Štruktúra. ktorá je prvkom inej štruktúry, sa označuje ako vhniezdená štruktúra.

Predpokladajme, že údaje o zamestnancoch budú uložené v poli nasledujúcich štruktúr:

typedef struct {

	char ulica[30];

	int cislo;

} ADRESA;



typedef struct {

	char meno[20];

	ADRESA adresa;

	float plat;

} OSOBA;

OSOBA ludia[1000];
a chceme vytlačiť adresu človeka s najvyšším platom. Predpokladáme, že položky ulica a meno su reťazce, teda ukončené znakom '\0'.
int i, kto = 0;

float pom, max = 0;



for (i = 0; i < 1000; i++) {

	if ((pom = ludia[i].plat > max) {

		max = pom;

		kto = i;

	}

}

printf("Zamestnanec s najvacsim platom byva v : %s %d \n",

	ludia[kto].adresa.ulica, ludia[kto].adresa.cislo);
Iný spôsob riešenia tohoto problému je pomocou pointerov, vďaka ktorým sa budú efektívnejšie (rýchlejšie) počítať adresy:
float max = ludia[0].plat;

OSOBA *p_pom, *p_kto;



for (p_pom = p_kto = ludia; p_pom < ludia + 1000; p_pom++) {

	if ((p_pom->plat) > max) {

		p_kto = p_pom;

		max = p_pom->plat;

	}

}

printf("Zamestnanec s najvacsim platom byva v : %s %d \n",

	p_kto->adresa.ulica, p_kto->adresa.cislo);
Vysvetľujúce poznámky:

* p_pom je inicializované ako bázová adresa poľa štruktúr
* vyraz p_pom++ znamená ďalší prvok poľa ludia, teda ďalšiu štruktúru
* p_pom++ teda neznamená, že sa k p_pom pripočíta jednička, ale že sa pripočíta 1 * sizeof(OSOBA)


9.1.5 Položky štruktúry sú pointery

Pokiaľ sú prvky štruktúry pointery a navyše štruktúra obsahuje vhniezdené štruktúry, začína byť pomerne veľký zmätok v tom, kde používať botkovú (.) notáciu a kde prístup pomocou ->

Našťastie existuje jedna mnemotechnická pomôcka.
Dôsledne pomenúvajte identifikátory pointerov tak, aby začínali p_. Potom za každým identifikátorom začínajúcim na p_ použijete -> a za ostatnými botku (.).

Celú problematiku budeme ilustrovať na príkladoch podobných predchádzajúcemu príkladu. Rozdiel bude v tom, že reťazce pre ulica a pre meno budeme alokovať dynamicky. To by bol v reálnom príklade pravdepodobne nutný prístup, aby sme na jednu stranu neboli závislí na dĺžke reťazca a na druhej šetrili pamäť.

Poznámka:
* Vo všetkých 4 príkladoch bude prvý človek vypisovaný pomocou prístupu do indexovaného poľa a druhý človek pomocou pointeru na druhý prvok poľa.
* Všetky 4 príklady zhodne vypíšu:
clovek 1: Karol, Dlha 10, 20000

clovek 2: Jano, Kratka 20, 21000
Príklad 1:
meno je reťazec s pevnou dĺžkou, ulica je dynamický reťazec. Preň sa musí najprv alokovať dynamická pamäť a až potom sa doňho dá nakopírovať meno ulice - v našom prípade "Dlha". Pre druhého človeka využijeme skutočnosť, že p_adresa môže ukazovať na už existujúci reťazec, takže pre "Kratka" pamäť nealokujeme, ale iba priradíme pointer.
#include <stdio.h>

#include <stdlib.h>

#include <string.h>



typedef struct {

char *p_ulica;

int cislo;

} ADRESA;



typedef struct {

	char meno[20];

	ADRESA adresa;

	float plat;

} OSOBA;



OSOBA ludia[2];



int main(void)

{

	char *ulica[] = { "Dlha", "Kratka" };

	OSOBA *p_o;



	ludia[0].plat = 20000.0;

	strcpy(ludia[0].meno, "Karol");

	ludia[0].adresa.cislo = 10;

	ludia[0].adresa.p_ulica = (char *) malloc(strlen(ulica[0]) + 1);

	strcpy(ludia[0].adresa.p_ulica, ulica[0]);



	ludia[1].plat = 21000.0;

	strcpy(ludia[1].meno, "Jano");

	ludia[1].adresa.cislo = 20;

	ludia[1].adresa.p_ulica = ulica[1];



	printf("clovek 1: %s, %s, %d, %.0f\n", ludia[0].meno, ludia[0].adresa.p_ulica,

			ludia[0].adresa.cislo, ludia[0].plat);



	p_o = &ludia[1];

	printf("clovek 2: %s, %s, %d, %.0f\n", p_o->meno, p_o->adresa.p_ulica,

		 p_o->adresa.cislo, p_o->plat);

	return 0;

}
Príklad 2:
meno je dynamický reťazec, ulica je reťazec s pevnou dĺžkou. Porovnajte si ho s predchádzajúcim.
#include <stdio.h>

#include <stdlib.h>

#include <string.h>



typedef struct {

char ulica[30];

int cislo;

} ADRESA;



typedef struct {

	char *p_meno;

	ADRESA adresa;

	float plat;

} OSOBA;



OSOBA ludia[2];



int main(void)

{

	char *ulica[] = { "Dlha", "Kratka" };

	OSOBA *p_o;



	ludia[0].plat = 20000.0;

	ludia[0].p_meno = (char *) malloc(strlen("Karol") + 1);

	strcpy(ludia[0].p_meno, "Karol");

	ludia[0].adresa.cislo = 10;

	strcpy(ludia[0].adresa.ulica, ulica[0]);



	ludia[1].plat = 21000.0;

	ludia[1].p_meno = (char *) malloc(strlen("Jano") + 1);

	strcpy(ludia[1].p_meno, "Jano");

	ludia[1].adresa.cislo = 20;

	strcpy(ludia[1].adresa.ulica, ulica[1]);





	printf("clovek 1: %s, %s, %d, %.0f\n", ludia[0].p_meno, ludia[0].adresa.ulica,

			ludia[0].adresa.cislo, ludia[0].plat);



	p_o = &ludia[1];

	printf("clovek 2: %s, %s, %d, %.0f\n", p_o->p_meno, p_o->adresa.ulica,

		 p_o->adresa.cislo, p_o->plat);

	return 0;

}
Príklad 3:
meno je dynamický reťazec, ulica je dynamický reťazec. Porovnajte si ho s predchádzajúcimi.
#include <stdio.h>

#include <stdlib.h>

#include <string.h>



typedef struct {

char *p_ulica;

int cislo;

} ADRESA;



typedef struct {

	char *p_meno;

	ADRESA adresa;

	float plat;

} OSOBA;



OSOBA ludia[2];



int main(void)

{

	char *ulica[] = { "Dlha", "Kratka" };

	OSOBA *p_o;



	ludia[0].plat = 20000.0;

	ludia[0].p_meno = (char *) malloc(strlen("Karol") + 1);

	strcpy(ludia[0].p_meno, "Karol");

	ludia[0].adresa.cislo = 10;

	ludia[0].adresa.p_ulica = (char *) malloc(strlen(ulica[0]) + 1);

	strcpy(ludia[0].adresa.p_ulica, ulica[0]);



	ludia[1].plat = 21000.0;

	ludia[1].p_meno = (char *) malloc(strlen("Jano") + 1);

	strcpy(ludia[1].p_meno, "Jano");

	ludia[1].adresa.cislo = 20;

	ludia[1].adresa.p_ulica = ulica[1];



	printf("clovek 1: %s, %s, %d, %.0f\n", ludia[0].p_meno, ludia[0].adresa.p_ulica,

			ludia[0].adresa.cislo, ludia[0].plat);



	p_o = &ludia[1];

	printf("clovek 2: %s, %s, %d, %.0f\n", p_o->p_meno, p_o->adresa.p_ulica,

		 p_o->adresa.cislo, p_o->plat);

	return 0;

}
Príklad 4:
Najzaujímavejší príklad je teda, keď vhniezdená štruktúra vzniká dynamicky a jej položka ulica je dynamický reťazec. Hlavne z príkazu tlače je vidno ako pomáha mnemotechnická pomôcka párujúca p_ a ->
#include <stdio.h>

#include <stdlib.h>

#include <string.h>



typedef struct {

char *p_ulica;

int cislo;

} ADRESA;



typedef struct {

	char *p_meno;

	ADRESA *p_adresa;

	float plat;

} OSOBA;



OSOBA ludia[2];



int main(void)

{

	char *ulica[] = { "Dlha", "Kratka" };

	OSOBA *p_o;



	ludia[0].plat = 20000.0;

	ludia[0].p_meno = (char *) malloc(strlen("Karol") + 1);

	strcpy(ludia[0].p_meno, "Karol");

	ludia[0].p_adresa = (ADRESA *) malloc(sizeof(ADRESA));

	ludia[0].p_adresa->cislo = 10;

	ludia[0].p_adresa->p_ulica = (char *) malloc(strlen(ulica[0]) + 1);

	strcpy(ludia[0].p_adresa->p_ulica, ulica[0]);



	ludia[1].plat = 21000.0;

	ludia[1].p_meno = (char *) malloc(strlen("Jano") + 1);

	strcpy(ludia[1].p_meno, "Jano");

	ludia[1].p_adresa = (ADRESA *) malloc(sizeof(ADRESA));

	ludia[1].p_adresa->cislo = 20;

	ludia[1].p_adresa->p_ulica = ulica[1];



	printf("clovek 1: %s, %s, %d, %.0f\n", ludia[0].p_meno, ludia[0].p_adresa->p_ulica,

			ludia[0].p_adresa->cislo, ludia[0].plat);



	p_o = &ludia[1];

	printf("clovek 2: %s, %s, %d, %.0f\n", p_o->p_meno, p_o->p_adresa->p_ulica,

		 p_o->p_adresa->cislo, p_o->plat);

	return 0;

}
9.1.6 Alokácia pamäti pre jednotlivé položky štruktúry

Ak chceme celkom využiť možnosti jazyka C, potom je vhodné, aby sme sa - rovnako ako u polí - zoznámili s tým, ako sú prvky štruktúry uložené v pamäti.
Položky štruktúry obsadzujú pamäť v poradí definícií zhora dole a na riadku zľava doprava, napr.:

typedef struct {

	char c;

	int i, j, k;

	char d;

} PRIKLAD;

PRIKLAD pokus;
V štruktúre pokus ležia položky v tomto poradi:
c i j k d
Poradie uloženia položiek platí vždy, ale situáciu v pamäti komplikujú skutočnosti, že:
1) Položky štruktúry sú väčšinou zarovnávané na párne adresy (memory alignment), teda za položkou c je väčšinou 1 bajt prázdna výplň.
2) Štruktúra väčšinou končí na rovnako zarovnanej (párnej) adrese ako začínala, teda za položkou d môže byť opäť 1 bajt prázdna výplň.

Ak predpokladáme sizeof(int) == 2, potom uvedená štruktúra pokus môže alokovať 8 alebo 9 alebo aj 10 bajtov pamäti a nie len 8 bajtov, ako by nám vyšlo jednoduchým spočítaním veľkosti všetkých položiek.

Z toho plynú dve ponaučenia:
1) Veľkosť štruktúry sa zásadne zisťuje pomocou operátora sizeof pre celú štruktúru naraz.
2) Programy, kde sa k prvkom štruktúry pristupuje nie pomocou operátora bodka (.) alebo operátora ->, ale priamo pomocou nejako získaného offsetu (tzn. posunutie od počiatočnej adresy štruktúry danej jej menom - v našom prípade pokus), sú absolútne neprenositelné. Pri ich vytvaraní je nutné presne zistiť, ako sú prvky v pamäti uložené.
Takýmto programom sa vyhýbame!


9.1.7 štruktúry a funkcie

Návratová hodnota funkcie môže byť štruktúra a štruktúra môže byť odovzdaná funkcii ako skutočný parameter hodnotou. Je to zložito povedané - význam je, že funkcia pracuje so štruktúrou rovnako ako napr. so základným dátovým typom int.

Je tiež možné, že funkcia vracia pointer na štruktúru a taktiež štruktúra môže byť parametrom funkcie pomocou volania odkazom, teda pomocou pointeru.

V nasledujúcom príklade si ukážeme obidve možnosti.

Príklad:
Funkcia pre sčítanie komplexných čísiel.
typedef struct {

	double re, im;

} KOMP;



KOMP scitaj(KOMP a, KOMP f)

{

	KOMP c;



	c.re = a.re + f.re;

	c.im = a.im + f.im;

	return ( c );

}



int main(void)

{

	KOMP x, y, z;



	x.re = 1.1; x.im = 3.14;

	y = x;

	z = scitaj(x, y);

	return 0;

}
Tento spôsob je výhodný iba v prípade, že štruktúry majú malú veľkosť. Uvedomme si totiž, že ak odovzdávame štruktúru hodnotou, musí sa v zásobníku (stack) vytvoriť jej lokálna kópia. Ak má takto odovzdávaná štruktúra viac položiek, potom je toto kopírovanie samozrejme časovo náročné a zaberá v zásobníku veľa pamäti.
Je taktiež nutné si uvedomiť, že sa jedná o odovzdávanie hodnotou, takže akákoľvek zmena prvku štruktúry - ako skutočného parametra vo funkcii - sa mimo funkcie neprejaví.
Podobné pravidlo o vytváraní kópie štruktúry platí aj pri vracaní hodnoty štruktúry ako návratového typu funkcie. Tu sa opäť musí kopírovať - v našom prípade lokálna štruktúra c - niekam do pamäti.
Z týchto dôvodov sa veľmi často používa len spôsob, keď odovzdávame parametre odkazom pomocou pointerov. V tomto prípade sa totiž kopíruje do zásobniku iba jedna adresa, čo je v prípade väčších štruktúr značná úspora času a miesta. Ďalšou výhodou je, že sa skutočné parametre dajú vo funkcii trvalo zmenit.

Príklad:
Predchádzajúci príklad prepísaný pomocou pointerov. Všimnite si, že vlastná definícia štruktúry KOMP sa nezmenila.
typedef struct {

	double re, im;

} KOMP;



void scitaj(KOMP *p_a, KOMP *p_f, KOMP *p_c) {

	p_c->re = p_a->re + p_f->re;

	p_c->im = p_a->im + p_f->im;

}



int main(void)

{

KOMP x, y, z;



x.re = 1.1; x.im = 3.14;

y = x;

scitaj(&x,&y,&z);

return 0;

}
Poznámka:
* Všimnite si, že ak odovzdávame funkcii štruktúru odkazom (skutočný parameter funkcie je teda adresa štruktúry, teda vlastne pointer na štruktúru), je vo fukcii nutné pristupovať k prvkom štruktúry pomocou operátora ->.

Príklad:
Nasledujúci program je trochu zložitejší a ukazuje už reálne použitie štruktúr vo funkciach.
Funkcie vytvor1() a vytvor2() alokujú miesto pre štruktúru typu STUDENT rovnakým spôsobom - pomocou malloc(), ale s touto adresou pracuje každá inakšie:

× vytvor1() vracia pointer na novo alokovanú štruktúru
× vytvor2() nastaví adresu novej štruktúry do svojho parametra

Funkcia nastav() priradí meno a ročník a vôbec nerozlišuje, či pracuje so štruktúrou vzniknutou staticky alebo dynamicky.
#include <stdio.h>

#include <stdlib.h>

#include <string.h>



typedef struct {

	char meno[30];

	int rocnik;

} STUDENT;



STUDENT *vytvor1(void) {

	STUDENT *p_pom;



	p_pom = (STUDENT *) malloc(sizeof(STUDENT));

	if (p_pom == NULL)

		printf("Malo pamäti \n");

	return (p_pom);

}



void vytvor2(STUDENT **p_s) {

	*p_s = (STUDENT *) malloc(sizeof(STUDENT));

	if (*p_s == NULL)

		printf("Malo pamäti \n");

}



void nastav(STUDENT *p_s, char *jmn, int rok) {

	p_s->rocnik = rok;

	strcpy(p_s->meno, jmn);

}



int main(void)

{

	STUDENT s, *p_s1, *p_s2;



	p_s1 = vytvor1();

	vytvor2(&p_s2);



	/* praca s položkami štruktúr */

	s.rocnik = 3;

	p_s1->rocnik = s.rocnik + 1;

	p_s2->rocnik = 5;

	nastav(&s, "Pavol", 1);

	nastav(p_s1, "Karol", 2);

	nastav(p_s2, "Jozef", 3);

	return 0;

}
9.1.8 Zhrnutie poznatkov o práci so štruktúrami

* Statická štruktúra môže byť skutočným parametrom funkcie odovzdávaným hodnotou a môže to byť aj návratový typ funkcie, čo je ale vhodné iba pri malej veľkosťi štruktúry.

- funkčný prototyp:

KOMP scitaj(KOMP a, KOMP f);
- prístup k prvkom štruktúry vo funkcii:
c.re = a.re + f.re;
- volanie funkcie:
z = scitaj(x, y); /* bez & */
* Statická štruktúra sa často odovzdáva ako skutočný parameter odkazom, čo je vhodné pri väčšej veľkosťi štruktúry.

- funkčný prototyp:
void scitaj(KOMP *p_a, KOMP *p_f, KOMP *p_c);
- prístup k prvkom štruktúry vo funkcii:
p_c->re = p_a->re + p_f->re;
- volanie funkcie:
scitaj(&x,&y,&z); /* s & */
* Kombinácie predchádzajúcich spôsobov su možné.
* U dynamicky vytvorenej štruktúry sú taktiež možné obidva spôsoby (hodnotou a odkazom), ale v absolútnej väčšine prípadov sa používa len druhy spôsob - odkazom, pretože pointer nás k tomu priamo vyzýva.

- funkčný prototyp:
void scitaj(KOMP *p_a, KOMP *p_f, KOMP *p_c);
- prístup k prvkom štruktúry vo funkcii:
p_c->re = p_a->re + p_f->re;
- volania funkcie:
scitaj(p_x, p_y, p_z); /* bez & */
9.1.9 Pole štruktúr

Podobne ako viacrozmerné polia je možné alokovať pole štruktúr minimálne 4 rôznymi spôsobmi. Každý z nich má svoje výhody a nevýhody a z toho vyplývajúce vhodné a nevhodné použitie. Preto budú postupne ukázané na 4 programoch.
Všetky budú využívať rovnaký dátový typ štruktúry:

typedef struct {

int k;

char c;

} TYP;
Všetky programy vytvoria pole týchto štruktúr o veľkosti MAX (10 prvkov), naplní ich hodnotami (0, 'A')(1, 'B')......(9, 'J') a vypíšu tromi rôznymi spôsobmi obsah tretieho prvku poľa. Na výpise budeme vidieť rôzne spôsoby prístupu k prvkom, a to:

- pomocou mena poľa a indexov,
- s využitím pomocného pointeru p_tmp nastaveného na adresu tretieho prvku,
- pomocou pointerovej aritmetiky - súčtu mena poľa a poradia.

Poznámka:
* Samozrejme pri použití malloc() musí byť test, či sa pamäť podarilo priradiť.

Výpis bude mať vždy nasledujúcu podobu, bude sa meniť len meno pola "sa" na samom začiatku riadku:
sa[2].k = 2, .c = C

sa[2].k = 2, .c = C

sa[2].k = 2, .c = C
Príklad 1:
Statické pole štruktúr sa je najjednoduchším prípadom. Vytvára sa jednou definíciou a manipulácia s ním je najľahšia. Jeho nevýhodou je, že veľkosť poľa musí byť známa v dobe prekladu.
#include <stdio.h>

#include <stdlib.h>



#define MAX 10

#define DVA 2



typedef struct {

	int k;

	char c;

} TYP;



int main(void)

{

	int i;

	TYP *p_tmp;

	TYP sa[MAX];



	for (i = 0; i < MAX; i++) {

		sa[i].k = i;

		sa[i].c = 'A' + i;

	}

	printf("%s[%d].k = %d, .c = %c\n", "sa", DVA, sa[DVA].k, sa[DVA].c);



	p_tmp = &sa[DVA]; /* to iste ako p_tmp = sa + DVA; */

	printf("%s[%d].k = %d, .c = %c\n", "sa", DVA, p_tmp->k, p_tmp->c);



	printf("%s[%d].k = %d, .c = %c\n", "sa", DVA, (sa + DVA)->k, (*(sa +DVA)).c);



	return 0;

}
Príklad 2:
Dynamické pole štruktúr p_sb je veľmi podobné poľu sa. Líši sa nutnosťou jednorázovo alokovať potrebnú pamäť pomocou funkcie malloc(), čo dáva výhodu, že veľkosť poľa sa stanoví počas behu programu. Po vytvorení sa práca s poľom p_sb nelíši od sa.
#include <stdio.h>

#include <stdlib.h>



#define MAX 10

#define DVA 2



typedef struct {

	int k;

	char c;

} TYP;



int main(void)

{

	int i;

	TYP *p_tmp;

	TYP *p_sb;

	p_sb = (TYP *) malloc(MAX * sizeof(TYP));

	if (p_sb == NULL) {

		printf("Malo pamäti \n");

		return;

	}

	/* odtialto je to ako pole p_sb */

	for (i = 0; i < MAX; i++) {

		p_sb[i].k = i;

		p_sb[i].c = 'A' + i;

	}

	printf("%s[%d].k = %d, .c = %c\n", "p_sb", DVA, p_sb[DVA].k, p_sb[DVA].c);



	p_tmp = &p_sb[DVA]; /* to iste ako p_tmp = p_sb + DVA; */

	printf("%s[%d].k = %d, .c = %c\n", "p_sb", DVA, p_tmp->k, p_tmp->c);



	printf("%s[%d].k = %d, .c = %c\n", "p_sb", DVA, (p_sb + DVA)->k, (*(p_sb +DVA)).c);



	return 0;

}
Príklad 3:
Statické pole desiatich pointerov na štruktúry p_sc sa použije v prípade, keď máme znalosť o maximálnej možnej veľkosti poľa. Pole pointerov je vytvorené staticky, ale pretože sa jedná o pointery, nezaberá toľko pamäti ako pole sa. Jednotlivé prvky poľa (štruktúry) sa vytvárajú až v prípade potreby dynamicky.
#include <stdio.h>

#include <stdlib.h>



#define MAX 10

#define DVA 2



typedef struct {

	int k;

	char c;

} TYP;



int main(void)

{

	int i;

	TYP *p_tmp;

	TYP *p_sc[MAX];



	/* odtialto je to ako pole sa */

	for (i = 0; i < MAX; i++) {

		p_sc[i] = (TYP *) malloc(sizeof(TYP));

		p_sc[i]->k = i;

		p_sc[i]->c = 'A' + i;

	}

	printf("%s[%d].k = %d, .c = %c\n", "p_sc", DVA, p_sc[DVA]->k, p_sc[DVA]->c);



	p_tmp = p_sc[DVA]; /* to iste ako p_tmp = *(p_sc + DVA); */

	printf("%s[%d].k = %d, .c = %c\n", "p_sc", DVA, p_tmp->k, p_tmp->c);



	printf("%s[%d].k = %d, .c = %c\n", "p_sc", DVA, (*(p_sc + DVA))->k, (*(*(p_sc +DVA))).c);



	return 0;

}
Príklad 4:
Najkomplikovanejším spôsobom je pointer na pointer na štruktúry p_sd. Najkôr je treba vytvoriť pole pointerov na štruktúry a od tejto chvíle sa chová ako pole p_sc.
Jedná sa o najuniverzálnejšie pole, ktoré najviac šetrí pamäť, ale jeho vytváranie je veľmi ťažké.
#include <stdio.h>

#include <stdlib.h>



#define MAX 10

#define DVA 2



typedef struct {

	int k;

	char c;

} TYP;



int main(void)

{

	int i;

	TYP *p_tmp;

	TYP **p_sd;

	p_sd = (TYP **) malloc(MAX * sizeof(TYP *));

	if (p_sd == NULL) {

		printf("Malo pamäti \n");

		return;

	}

	/* odtialto je to ako pole p_sc */

	for (i = 0; i < MAX; i++) {

		p_sd[i] = (TYP *) malloc(sizeof(TYP));

		p_sd[i]->k = i;

		p_sd[i]->c = 'A' + i;

	}

	printf("%s[%d].k = %d, .c = %c\n", "p_sd", DVA, p_sd[DVA]->k, p_sd[DVA]->c);



	p_tmp = p_sd[DVA]; /* to iste ako p_tmp = *(p_sd + DVA); */

	printf("%s[%d].k = %d, .c = %c\n", "p_sd", DVA, p_tmp->k, p_tmp->c);



	printf("%s[%d].k = %d, .c = %c\n", "p_sd", DVA, (*(p_sd + DVA))->k, (*(*(p_sd + DVA))).c);



	return 0;

}
9.1.10 Inicializacia štruktúr

Štruktúry sa inicializujú podobne ako polia uvedením zoznamu inicializačných hodnôt uzavretym v zlozených zátvorkach { a }.

typedef struct {

	int i, j;

	float f;

} PRIKLAD;

PRIKLAD a = {1, 2, 6.4};
Podobne je možné inicializovať aj pole štruktúr:
PRIKLAD pole[] = {

				{4, 5, 1.2},

				{2, 8, 9.6},

				{1, 1, 1.0}

			 };
Poznámka:
*Počet prvkov - jednotlivých štruktúr - tohoto poľa je možné zistiť pomocou príkazu:
pocet = sizeof( pole) / sizeof(PRIKLAD);
Rovnako ako u polí je možné i u štruktúr inicializovať iba globálne alebo statické lokálne štruktúry.
/* ukážka chybnej inicializácie */

main() {

	PRIKLAD a = {1, 2, 6.4};			/* automaticka	 */

}



/* ukážka správnej inicializácie */

main() {

	static PRIKLAD a = {1, 2, 6.4};	 /* staticka lokálna */

}



/* ukážka spravnej inicializácie */

PRIKLAD a = {1, 2, 6.4};				/* staticka globalna */

main() {

}
9.2 Výčtový typ

Výčtový typ (enumerate type), ktorý je podobný typu vymenovaním v Pascale, sa v C programoch využíva veľmi často. Dovoľuje totiž veľmi sprehľadniť program a zvýšiť jeho modularitu.
Výčtový typ v C má síce podobnú konštrukciu ako skôr prebraná štruktúra, ale celkom inú filozofiu práce. Pomocou neho je možné ľahko definovať zoznam symbolických konštánt, ktoré môžu byť - a najčastejšie sú - vzájomne závislé.
Výčtový typ je možné opäť definovať rôznymi spôsobmi, z ktorých preferujeme vždy definíciu pomocou typedef, teda napr.:

typedef enum {

	MODRA, CERVENA, ZELENA, ZLTA		 /* ziadna bodkociarka */

} FARBY;



FARBY c, d;

c = MODRA;

d = CERVENA;
Poznámky:
* Položky výčtového typu nie sú l-hodnoty.
* Pretože sú položky v podstate to isté, ako symbolické konštanty, píšeme ich z konvencie veľkými písmenami.
* Pokiaľ explicitne nepriradíme číselné hodnoty jednotlivým prvkom typu, potom majú tieto prvky implicitné hodnoty 0, 1, 2 atď..
* Výčtový typ sa použije vždy, ak majú konštanty nejakú vzájomnú súvislosť, napr. booleovské hodnoty TRUE a FALSE nebudú definované ako:
#define FALSE	 0

#define TRUE	 1
ale skôr ako:
typedef enum {

	FALSE, TRUE

} BOOLEAN;
Takto definované konštanty je potom možné používať v najrôznejších prípadoch napr.:
if(isdigit(a) == FALSE)
teda nie je vôbec nutné definovať premennú tohto výčtového typu. Stačí iba definícia výčtového typu BOOLEAN.

Jednotlivé definované premenné typu enum sú vnútorne reprezentované ako pamäťovo najmenej náročný znamienkovo chápany celočíselný typ, ktorý ešte môže obsahovat hodnoty daneho typu enum. Ak by sme definovali premennú dobre ako: BOOLEAN dobre; potom bude premenná dobre vnútorne reprezentovaná typom signed int.

Občas sa tiež u výčtového typu používajú explicitné inicializácie. Je nutné poznamenať, že je možné explicitne inicializovať len niektoré prvky a pre zostávajúce prvky inicializované implicitne potom platí, že ich hodnota je vždy o 1 väčšia než hodnota predchádazjúceho prvku, napr.:
typedef enum{

	MODRA = 0,

	CERVENA = 4,

	ZELENA = 2,

	ZLTA		 /* neinicializovaná */

} FARBY;
Tu má položka ZLTA hodnotu 3.

Toto je najhorší možný príklad inicializácie, pretože:
1) Keď už položky inicializujeme, potom sa snažíme zrovnať položky podľa veľkosťi.
2) Ak použijeme explicitnú inicializáciu potom inicializujeme vždy všetky prvky.

Pozor:
Častou chybou je predstava, že je možné vytlačiť meno položky výčtového typu ako reťazec, teda napr.:
c = MODRA;

printf("Farba bola %s \n", c);	/* chybne */
Je možné vytlačiť iba hodnotu položky výčtového typu a je vhodné ju predtým pretypovať na int, teda napr.:
printf("Farba mala cislo %d \n", (int) c);
Ak potrebujeme naozaj vytlačiť meno položky, vtedy je vhodným riešením napr. použitie prepínača switch, čo je univerzálne, ale dosť rozťahané riešenie. Je výhodné v prípade, že sú položky inicializované rôznymi hodnotami napr.:
typedef enum{

	MODRA = 5,

	CERVENA = 8,

	ZELENA = 11,

	ZLTA = 15

} FARBY;



switch (FARBA) {

	case MODRA: printf("Bola to modra farba");

				break;
Druhou, častejšie využívanou možnosťou, ako vytlačiť meno položky, je využitie poľa pointerov na char. Tento spôsob je elegantný, ale prakticky použiteľný len pre neinicializovaný výčtový typ, kedy položky majú hodnoty od 0, teda napr.:
typedef enum{

	MODRA, CERVENA, ZELENA, ZLTA

} FARBY;



FARBY farba = MODRA;

char *nazvy[] = { "Modra", "Cervena", "Zelena", "Zlta"};

printf("Bola to farba %s \n", nazvy[farba]);
9.3 Uniony

Dátový typ union znamená, že sa vyhradí pamäť pre najväčšiu položku zo všetkých položiek v unione definovanych, pretože všetky položky unionu sa prekrývajú (v štruktúre by ležali v pamäti za sebou), čo znamená, že v unione môže byť v jednom okamihu iba jedna položka.
Uniony sa v praxi používajú málokedy a ak sa použijú, mal by pre to byť dostatočný dôvod. Jedným z dôvodou môže byť potreba šetriť pamäť a union sa teda používa hlavne vo veľkých poliach.
Syntax unionu je veľmi podobný už známemu syntaxu štruktúry.

union typ {

	/* spolocne polozky nie su */



	varianta_1;

	...

	varianta_n;

}
Rovnako ako u štruktúr, aj typ union a premenná typu union môžu byť definované rôznymi spôsobmi. Opäť sa preferuje definícia pomocou typedef, ktorá bude ďalej výhradne používaná, napr.:
typedef union{

	char c;

	int i;

	float f;

} ZN_INT_FLT;

ZN_INT_FLT a, *p_a = &a;
K jednotlivým položkám unionu sa prístupuje úplne rovnako ako k položkám štruktúry, napr.:
a.c = '#';

p_a->i = 1;	 /* premaze znak '#' */

a.f = 2.6;		/* premaze cislo 1 */
Pozor:
Je nutné si uvedomiť, že union neposkytuje informáciu o type prvku, ktorý bol do neho naposledy uložený!
Tento problém sa často rieši tak, že sa union vloží do štruktúry, ktorej prvá položka je výčtový typ a druha položka union, napr.:
typedef enum {

	ZNAK, CELE, REALNE

}TYP;



typedef union{

	char c;

	int i;

	float f;

} ZN_INT_FLT;



typedef struct {

	TYP typ;

	ZN_INT_FLT položka;

} LEPSI_UNION;
Ako sa podobná konstrukcia používa, je ukázané v nasledujúcom príklade.

Príklad:
Program číta 10 krat z klávesnice. Vždy je najskôr prečítaný jeden znak. Ak je to "I" alebo "i" bude nasledovať celé číslo, ak je to "C" alebo "c" bude nasledovať znak. Načítane hodnoty sa ukladajú do poľa pomocou unionu. Na záver sa celé pole vytlačí.
Je použitý union v štruktúre, aby bolo možné zaznamenať, aký typ prvku je v unione uložený.
#include <stdio.h>

#include <ctype.h>



#define POCET	 10

/* vyprazdnenie bufferu klavesnice - ukoncujuca bodkociarka sa doda pri volani */

#define cisti() while (getchar() != '\n')



typedef enum {

	CISLO = 'I',

	ZNAK = 'C'

} TYP;



typedef union {

	char c;

	int i;

} CHARINT;



typedef struct{

CHARINT hodnota;

TYP typ;

} PRVOK;



PRVOK pole[POCET];



int main(void)

{

	int i, c;



	for (i = 0; i < POCET; i++) {

		printf("%d. položka : \ntyp : ", i + 1);

		c = toupper(getchar());

		cisti();

		switch© {

			case CISLO : pole[i].typ = CISLO;

						 printf("Cislo : ");

						 scanf("%d", &pole[i].hodnota.i);

						 break;

			case ZNAK : pole[i].typ = ZNAK;

						 printf("znak : ");

						 scanf("%c", &pole[i].hodnota.c);

						 break;

			default :	printf("Neznamy typ \n");

						 break;

		}

		cisti();

	}



	/* tlac nacitanych hodnot */

	for (i = 0; i < POCET; i++) {

		if (pole[i].typ == CISLO)

			printf("%d. položka = %d \n", i + 1, pole[i].hodnota.i);

		else

			printf("%d. položka = %c \n", i + 1, pole[i].hodnota.c);

	}

}
Poznámka:
* V tomto príklade bol vhodne použitý výčtový typ s inicializovanými položkami, pretože to zjednodušilo väzbu medzi vstupom z klávesnice a prepínačom switch.


Čo je dobré si uvedomiť:

* Štruktúry su uložené v bloku súvislej pamäti a môžu v nich byť "výplne", tzn. že položky nie su nutne uložené bezprostredne za sebou. Veľkosť štruktúry je vhodné získavať jedine pomocou operátoru sizeof.
* So štruktúrou ako parametrom funkcie sa pracuje vo funkcii väčšinou pomocou operátora -> aj keď skutočný parameter bola štruktúra definovaná staticky.
* Uniony sú štruktúry, ktorých každá položka ma offset 0 a teda jednotlivé položky sa pri nevhodnom použití navzájom prepisujú.
* Výčtový typ je možné s výhodou použiť pre definovanie suvisiacich symbolických konštánt.
* Výčtový typ výrazne podporuje čitateľnosť a bezpečnosť programu a doporučuje sa ho používať.

Časté chyby:
struct text {

	int a, b;				 /* tento typ definície nepoužívať!				 */

};

text x;						 /* ma byť:	 struct text x;					 */



typedef struct link {

	int hodnota;

	LINK *ďalší;				/* ma byť:	 struct link *ďalší;				 */

} LINK;



typedef struct {

	int a, b;

} AAA;

AAA x, *p_x = &x;

*p_x.a = 1;					 /* ma byť:	 p_x->a = 1;						 */



typedef enum {

	blue, red;				 /* tu nema byť bodkociarka						 */

} FARBY;						/* mena položiek je vhodné pisat veľkými písmenami */
Úlohy:

1. Definuj štruktúru s tromi prvkami (float, char a int v tomto poradí) a union s tými istými prvkami. Zisti adresy štruktúry, unionu a všetkých ich položiek. Ďalej zisti veľkosť štruktúry a unionu.
Spoiler

2. Definuj štruktúru, ktorá bude mať položky meno a vek. Napíš funkciu napln(), ktorá túto štruktúru naplní tvojimi dátami. Pointer na štruktúru bude odovzdávaný ako prvý parameter funkcie. Tú istú štruktúru alokuj dynamicky a naplň ju dátami priateľa opäť pomocou funkcie napln(). Obsah obidvoch štruktúr vytlač.
Spoiler

3. Uprav predchádzajúci program tak, že sa meno a vek budú čítať zo súboru (obidva údaje budú na jednom riadku a súbor nebude mať viac ako 1000 riadkov). Načítané hodnoty sa budú ukladať do statického poľa štruktúr. Vypočítaj priemerný vek a vytlač mená všetkých ľudí, ktorí majú tento vek.
Spoiler

4. Predchádzajúci program uprav tak, že namiesto do poľa štruktúr sa budú načítané údaje ukladať do jednosmerne zreťazeného dynamického zoznamu týchto štruktúr. Ten sa bude vytvárať dynamicky podľa aktuálnej dĺžky čítaného súboru.
Spoiler

5. Vytvor program, ktorý pomocou funkcie fgets() prečíta súbor a uloží ho do pamäti po riadkoch pomocou jednosmerne zoradeného zoznamu štruktúr. Položkami štruktúry budú okrem iného reťazec max. dĺžky 80 a aktuálna dĺžka riadku. Vytlač najdlhší riadok súboru.
Spoiler

6. Uprav predchádzajúci program tak, aby položkami štruktúr bol pointer na reťazec a dĺžka aktuálneho riadku. Vypočítaj priemernú dĺžku riadku a vytlač všetky riadky s touto dĺžkou.
Spoiler

7. Napíš program, ktorý prečíta súbor dĺžky max. 1000 riadkov a do poľa štruktúr uloží dĺžku riadku. Do prkov vhniezdenej štruktúry pocet uloží jednak počat písmen v tomto riadku, a potom aj počet ostatných znakov. Vypíš počet písmen v súbore.
Spoiler

8. Napíš program, ktorý bude zisťovať, či sa súbor, ktorého meno bude zadané z klávesnice, nachádza na disku alebo nie. K tomuto účelu vytvor funkciu BOOLEAN je_tu(char *meno). Typ BOOLEAN vytvor pomocou výčtového typu s položkami ANO a NIE.
Spoiler

9. Definuj výčtový typ AUTOMOBILY a vytlač názvy a hodnoty jednotlivých položiek. Názvy položiek tlač:
* po znakoch pomocou dvoch cyklov
* pomcou printf()
* pomocou puts()
Spoiler

10. Predchádzajúci výčtový typ skús inicializovať, najprv čiastočne, potom úplne a opäť vytlač názvy jeho položiek.
Spoiler
  • 0

Popis: Štruktúry, uniony a výčtové typy
Štruktúry
Definície a základne schopnosti
Štruktúry a pointery
Štruktúry odkazujúce sami na seba
Štruktúra v inej štruktúre
Alokácia pamäti pre jednotlivé položky štruktúry
Štruktúry a funkcie
Zhrnutie poznatkov o práci so štruktúrami
Inicializácia štruktúr
Výčtový typ
Uniony
Rozdiel medzi variantným záznamom v Pascale a unionom
Poznámky:
Odkazy:


0 Komentárov


Najlepšie lekcie


Najnovšie pridané lekcie


Najnovšie komentáre


Najviac komentované lekcie


Najviac zobrazené lekcie


Náhodné lekcie


Na tejto stránke bolo užívateľ(ov) za posledných 30 minút

členov, návštevníkov