Ukazatele
Doplňující informace
Ukazatel (anglicky pointer) je proměnná, která slouží pro uložení adresy v paměti (např. jiné proměnné) a pro práci s adresami. V jazyku C používáme ukazatele na konkrétní datový typ, při definici ukazatele je tedy nutné specifikovat datový typ proměnných, ke kterým budeme přes tento ukazatel přistupovat.
Deklarace ukazatelů
Syntaxe:
typ *identifikátor = inic_výraz;
kde typ
je datový typ, se kterým bude ukazatel pracovat, identifikátor
je identifikátor ukazatele a inic_výraz
je inicializační hodnota (měla by to být adresa, na které jsou uložena data daného typu).
Příklady deklarací:
int *pI; /* deklarace ukazatele na číslo typu int */ char *ret = "bla bla"; /* ukazatel inicializovaný adresou prvního znaku v řetězci */ int pole[10]; int *p = pole; /* ukazatel inicializovaný adresou pole, resp. prvního čísla v poli */ long cislo, *pL1, *pL2 ; /* deklarace více ukazatelů na jednom řádku */
Operátor adresy &
Tento operátor slouží pro zjištění adresy dané proměnné.
Příklady:
int i=2, *pi = &i, j; /* inicializace ukazatele adresou proměnné */ pi = &j; /* přiřazení adresy proměnné ukazateli */ scanf("%i", &i); /*uložení přečtené hodnoty na danou adresu */
Operátor dereference *
Operátor slouží pro přístup k hodnotě na dané adrese.
Příklady:
*pi = 3; /* změna hodnoty na adrese ukazatele */ (*pi)++; /* inkrementace hodnoty na adrese ukazatele */ printf("%i\n", *pi); /* výpis hodnoty na adrese ukazatele */
Pointerová aritmetika
Protože ukazatele reprezentují adresy, lze s nimi provádět pouze některé aritmetické operace:
- přičtení (resp. odečtení) celočíselného výrazu k (resp. od) ukazatele
- rozdíl dvou ukazatelů stejného typu
Příklad využití pointerové aritmetiky:
char str[] = "Ahoj!"; char *pom = str; while(*pom != '\0') { printf("%c\n", *pom); pom++; } printf("Délka řetězce je %i.\n", pom - str);
Vztah ukazatelů a polí
Stručně lze říci, že identifikátor pole se chová jako konstantní ukazatel na první prvek v poli. Přístup k prvkům pole pomocí operátoru indexu lze tedy nahradit přístupem pomocí ukazatele, pointerové aritmetiky a operátoru dereference.
Příklad:
char str[] = "Ahoj Svete!"; char *pom; int i; for (i = 0; i < (int)strlen(str); i++) printf("%c", str[i]); pom = str; while (*pom != '\0') { printf("%c", *pom); pom++; }
Ukazatel na strukturu
Tento typ ukazatele definujeme stejně jako ukazatel na jakýkoli jiný typ. Pouze při přístupu ke členům struktury na adrese dané ukazatelem je možné místo operátoru dereference a operátoru tečky použít operátor ->
, což vede ke zjednodušení zdrojového kódu.
Ekvivalentní možnosti přístupu ke členu struktury přes ukazatel:
(*id_struktury).id_clenu id_struktury->id_clenu
Příklad:
typedef struct {char Den, Mesic;} Datum; Datum den = {12, 2}; Datum *narozen = &den; narozen->Den = 25;
Struktura "uvnitř sebe samé"
V některých situacích (např. vytváření fronty, zásobníku, seznamu) je potřeba vytvořit strukturu, která bude mít informace o jiné struktuře stejného typu. Jak již víme, není možné mít ve strukturovaném datovém typu člen stejného strukturovaného typu. Toto omezení se dá obejít použítím ukazatelů, když členem struktury bude ukazatel na strukturu stejného typu.
Příklady definice struktury:
struct s1 {int data; struct s1 *dalsi;}; typedef struct s1{ int data; struct s1 *dalsi; } seznam;
Příklady použití struktury:
struct s1 a = {1, NULL}; seznam b = {2, &a}; b.dalsi->data = 0;