Ukazatele, dynamická alokace paměti, pole

Download Report

Transcript Ukazatele, dynamická alokace paměti, pole

Verze 2009.01
10 Ukazatele a pole
A1PRG - Programování – Seminář
Ing. Michal Heczko [email protected]
Agenda

Ukazatele
 Nulový
ukazatel
 Obecný ukazatel
 Aritmetika ukazatelů

Dynamické přidělování paměti
Ukazatel


Při dosavadní práci s proměnnými použity tzv.
statické proměnné.
Ukazatel (Pointer) je proměnná, která představuje
adresu v paměti, na které je uložena skutečná
hodnota.
Ukazatel

Ukazatel je proměnná

Neobsahuje hodnotu, ale pouze paměťovou adresu


Zajímá nás hodnota ležící na adrese, kterou
definuje
Každý ukazatel ukazuje na určitý datový typ
(ukazatel na celé číslo, …)
Ukazatel

Pojmy:
 Adresa
 Obsah
ukazatele
ukazatele / Hodnota ukazatele
 Hodnota
na níž ukazatel ukazuje
Operátory

Operátor reference
 Operátor:
&
 Význam: Vrací adresu proměnné

Operátor dereference
 Operátor:
*
 Význam: Vrací obsah zadané adresy
Příklad 1
int i;
int *p_i1;
int *p_i2;
Příkaz
Obsah na adrese
10 (&i)
20 (&p_i1)
30 (&p_i2)
i = 1;
1
?
?
p_i1 = &i;
1
10
?
*p_i1 = 2;
2
10
?
i = *p_i1 + 1;
3
10
?
p_i2 = &p_i1;
3
10
20
Příklad 2

#include "stdafx.h"

#include <conio.h>

int _tmain(int argc, _TCHAR* argv[])

{

int i, j, *p_i;

scanf("%d %d",&i,&j);

p_i = (i > j) ? &i : &j;

printf("Vetsi je %d na adrese %p",*p_i,p_i);

getch();

return 0;

}
Nulový ukazatel



Symbolická konstanta NULL
Lze přiřadit libovolnému ukazateli bez ohledu na
datový typ
Označení, že ukazatel „neukazuje nikam“
Nulový ukazatel

Příklad:
 Otevření
neexistujícího souboru (v případě, že soubor
neexistuje, vrací funkce hodnotu NULL):
FILE *f;
f = fopen(″soubor.txt″,″r″);
if (f == NULL)
printf(″Soubor neexistuje″);
Obecný ukazatel


Generický ukazatel na typ void
Po správném přetypování může ukazovat na data
libovolného typu
Obecný ukazatel
void *p;
int a = 5;
double b = 2.8e36;
p = &a;
* (int *) p = 7;
p = &b;
* (double *) p = 12.83;
Příklad

Funkce pro záměnu dvou proměnných
void zamen(int *p_i, int *p_j)
{
int pom;
pom = *p_i;
*p_i = *p_j;
*p_j = pom;
}
Aritmetika ukazatelů

Součet (a rozdíl) ukazatele a celého čísla

Rozdíl ukazatelů

Porovnání ukazatelů
Aritmetika ukazatelů

Součet (a rozdíl) ukazatele a celého čísla:
 Přičtením
celého čísla k ukazateli vzniká ukazatel nový.
 Nový ukazatel bude ukazovat o N adres dále.
 Pokud ukazatel bude ukazovat na prvek struktury,
která v paměti zabírá 10 B, přičtením 1 bude nový
ukazatel ukazovat o 10 B dále.

Př.
int *p_i;
p_i = p_i + 1;
Aritmetika ukazatelů

Rozdíl ukazatelů:
 Vrací
počet údajů, které leží mezi prvním a druhým
ukazatelem.
 Rozdíl ukazatelů má smysl například u polí

Porovnání ukazatelů (==):
 Vrací
hodnotu 1, pokud ukazatele ukazují na stejné
místo v paměti.
 U polí možno použít i další relační operátory.
Dynamické přidělování paměti





Umožňuje uživateli řídit přidělování paměti
Paměť je přidělována z tzv. hromady (heap)
Problém: přidělování paměti tak, aby nedošlo ke
kolizi s ostatními daty.
Přidělení paměti pomocí funkce malloc().
Uvolnění paměti pomocí funkce free().
Dynamické přidělování paměti

Funkce malloc()
 Rezervace
paměti
 Jediný parametr typu unsigned int – počet bytů
 Návratová hodnota: ukazatel na typ void – obsahuje
adresu prvního prvku v paměti
 Je
vhodné přetypovat na potřebný datový typ
 Není-li v paměti dostatek místa pro přidělení žádaného
úseku, vrací hodnotu NULL
Dynamické přidělování paměti

Funkce free()
 Uvolnění
paměti
 Parametrem je ukazatel na typ void
Dynamické přidělování paměti

Příklad:
int *p_i;
if ((p_i = (int *)malloc(sizeof(int))) == NULL)
{
printf("Nedostatek pameti!");
}
else
{
printf("Zadejte celociselnou hodnotu: ");
scanf("%d", p_i);
printf("Zadana hodnota: %d",*p_i);
free(p_i);
}
Dynamické přidělování paměti

Funkce calloc()
 Alokace
paměti pro určitý počet prvků dané velikosti
 Parametry:
 Počet
prvků
 Velikost jednoho prvku - počet bytů
 Návratová
hodnota: ukazatel na typ void – obsahuje
adresu prvního prvku v paměti
Dynamické přidělování paměti

Funkce calloc()
 Srovnání
s funkcí malloc()
malloc ( n * size );
calloc ( n , size );
Pole


„Struktura“ složená se stejných prvků
Jednotlivé prvky indexujeme od 0
Př.:
int x[10];
x[0] = 10;
for (int i = 0; i < 10; i++)
{
x[i] = i;
}
Statické pole

Nevýhoda: nutno zadat konstantní rozměr pole
Př.:
int x[10];
x[0] = 10;
for (int i = 0; i < 10; i++)
{
x[i] = i;
}
Dynamické pole


Možnost zadat rozměr pole na základě proměnné.
Definice pomocí malloc() (popř. calloc())
Př.:
int *x;
x = (int *) malloc(10*sizeof(int));
for (int i = 0; i < 10; i++)
{
*(x+i) = i;
}
Statické / dynamické pole
Akce
Statické pole
Dynamické pole
Definice
int x[5];
int *x;
x = malloc(5*sizeof(int))
Naplnění n-tého
prvku pole
hodnotou
x[n] = 5;
*(x + n) = 5;
Adresa n-tého
prvku (např. u
příkazu scanf)
scanf("%d",&x[n]);
scanf("%d",(x+n));
Uvolnění paměti
free(x)
Vícerozměrná pole


Jazyk C umožňuje definici pole s vyšší dimenzí než
1.
Dvourozměrné pole:
int x[10][10];
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++)
x[i][j] = 0;
}
}
{
Vícerozměrná pole

Trojrozměrné pole:
int x[10][10][10];
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
for (int k = 0; k < 10; k++)
x[i][j][k] = 0;
}
}
}
{
Vícerozměrná pole

Statické pole
int pole[2][2];
 Po

celou dobu má rozměr 2x2
Polostatické pole
int *pole[2];
pole[0] = (int *)malloc(4*sizeof(int));
pole[1] = (int *)malloc(8*sizeof(int));
 Počet
prvků
řádků neměnná, každý řádek má různý počet
Vícerozměrná pole

Dynamické pole
int **pole;
pole = (int **) malloc(2*sizeof(int *));
pole[0] = (int *)malloc(4*sizeof(int));
pole[1] = (int *)malloc(8*sizeof(int));
 Zcela
flexibilní
Vícerozměrná pole

Transformace dvourozměrného pole na
jednorozměrné
int *pole;
int r = 3;
int s = 2;
pole = (int *)malloc(r*s*sizeof(int));
//přístup k pole[2][1]
*(pole + (2*s + 1)) = 5;
Inicializace pole

Hodnoty uvádíme ve složených závorkách
int x[3] = {2, 3, 5};
int y[] = {1, 2};

Pokud v inicializaci uvedeme méně prvků, zbylé jsou
inicializovány na 0
int x[3] = {2, 3};

Na druhou stranu není možné uvést prvků více:
int y[2] = {1, 2, 4};
Inicializace pole

Vícerozměrné pole
int x[][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
A1PRG-s
10. Ukazatele a pole
Děkuji za pozornost
Ing. Michal Heczko
[email protected]
218/U3
Prezentace k dispozici na http://vyuka.fai.utb.cz