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;

Creative Commons License Sbírka úloh z jazyka C. © Katedra informatiky Univerzity Palackého v Olomouci, 2009.
Projekt byl vytvořen za podpory grantu FRVŠ 2061/2009/G1.