[Cvičení 3] | [Obsah] | [Cvičení 5] |
int
.
Velikost pole (počet položek) musí být známa při překladu a není možné ji měnit (proto statické pole). Pole může být jedno
či vícerozměrné. Při deklaraci jakéhokoliv statického pole zadáváme do hranatých závorek počet prvků pole.
int
, které se jmenuje A
. Pole
má dvacet prvků.
int A[20];Konstanta může být buď zapsaná přímo (viz. číslo 20) nebo symbolická, definovaná pomocí direktivy
#define
, není dovoleno
použít typovanou konstantu s přidělenou pamětí definovanou pomocí const
:
#define MAXPOCET 20 . . . int A[MAXPOCET];Po této deklaraci překladač vyhradí souvislou paměť pro dvacet čísel typu
int
. Přístup k prvkům pole se provádí pomocí indexů.
Index se zapisuje do hranatých závorek, např.:
A[3] = 0; y = A[i]*3;V jazyce C má index prvního prvku hodnotu nula, index posledního prvku je n-1, kde n je počet prvků pole. Důvodem je požadavek na rychlý výpočet mapovací funkce pole, tj. adresu indexovaného prvku. Tento způsob indexace není možno měnit! Jazyk C neprovádí žádné kontroly správnosti mezí indexů (ani při překladu, ani ve výsledném kódu), důvodem je opět snaha o co nejrychlejší výpočet adresy příslušného prvku pole. Všechny kontroly jsou ponechány v plné míře na programátorovi. Pokud se stane, že index má hodnotu mimo deklarovaný rozsah, pracuje se s daty uložené mimo pole a může se stát, že si programátor nevědomky přepíše hodnoty jiných proměnných.
Hodnoty prvků pole je možné inicializovat již při deklaraci, pomocí tzv. konstruktoru pole:
int B[3] = {1,3,5};
Pomocí klíčového slova typedef
lze deklarovat uživatelské typy. Uživatelský typ pole čísel
typu float
o 20 prvcích definujeme následovně:
typedef float TPole20[20]; /* toto je deklarace nového typu pole TPole20, nikoliv samotného pole */Konkrétní pole (proměnnou typu pole) tohoto typu pak deklarujeme:
TPole20 p; /* deklarujeme pole p */ p[0] = 3.2; p[19] = -3.45;Výhodou přístupu je možnost snadné úpravy kódu - použijeme-li ve všech deklaracích proměnných, parametrech funkcí atd., identifikátor uživatelského typu
TPole20
, stačí změnit definici typu pole např. na int
v jediném místě kódu.
Napište program, který uloží do pole násobky čísla 5 (malou násobilku) a vytiskne je.Řešení:
Dev C++: nasob.dev, nasob.c CodeBlocks: nasob.cbp, nasob.c
float
, které se jmenuje
mat
je na následujícím řádku:
float mat[20][20];Přístup k prvkům pole je opět pomocí indexů, index každé dimenze je v samostatných závorkách. O mezích indexů platí stejná pravidla jako v případě jednorozměrného pole, tedy výše deklarovanou matici mohu indexovat
mat[0][0]
až mat[19][19]
.
Obdobně, dvourozměrné pole je možné také inicializovat pomocí konstruktoru:
int M[2][2] = {{1,2},{3,4}};Poznámka: dvourozměrné pole je v jazyce C uloženo po řádcích.
Napište program, který vypočítá a vytiskne součin dvou matic. Nejprve načte z klávesnice rozměry matic a vlastní matice. Program ověří, zda je možné matice vynásobit.Polotovar:
Řešení:
Dev C++: soucinmat.dev, soucinmat.c CodeBlocks: soucinmat.cbp, soucinmat.c
Dev C++: soucinmat.dev, soucinmat.c CodeBlocks: soucinmat.cbp, soucinmat.c
*
“. Na následujícím řádku je příklad deklarace proměnné p typu ukazatel
na int
:
int *p;Tedy, proměnná p obsahuje adresu paměťového místa, které obsahuje hodnotu typu
int
(obr. 1).
int x; int *p; p = &x;Z výkladu o funkci
scanf
víme, že operátor „&“ vrací
adresu objektu, tedy hodnotou výrazu &x
je adresa, na které je
umístěna proměnná x. Tuto adresu přiřadíme do proměnné p.
Proměnná p nyní ukazuje na proměnnou x.
Přístup k hodnotě (k paměťové buňce), na kterou proměnná typu ukazatel ukazuje, se provádí pomocí operátoru dereference, což je hvězdička
„*“:
*p = 3;Do paměťového místa, kam ukazuje proměnná, jsme nyní uložili hodnotu 3. Pokud uvažujeme předcházejí přiřazení
p = &x;
, změnili
jsme hodnotu proměnné x.
p = 3;
, změnili bychom hodnotu
samotného ukazatele; proměnná p by ukazovala do paměti na buňku s adresou 3.)
Shrneme si tedy ještě jednou situaci na obrázku 1. Máme dvě proměnné x a p:
proměnná x je typu int
a v paměti je uložena na adrese 3426, druhá proměnná p
je typu ukazatel na int
a v paměti je uložena na adrese 2100.
Proměnná p obsahuje adresu proměnné x, tedy hodnotu (číslo) 3426
(v paměťové buňce s adresou 2100 je hodnota 3426). Proměnná x obsahuje
celé číslo 3 (v paměťové buňce s adresou 3426 je hodnota 3).
Poznámka: Pomocítypedef
je možné definovat i uživatelský typ ukazatele, např. typ ukazatel nafloat
definujeme:typedef float* Pfloat; /* Pfloat jako Pointer na float, tato konvence v označování typů je zažitá */Proměnnou typu ukazatel uk deklarujeme za pomocí výše definovaného typu standardně:Pfloat uk;
malloc
(memory allocation) z knihovny stdlib.h
nebo alloc.h
.
Hlavička funkce má podobu:
(void *)malloc(size_t n)
size_t
je celočíselný typ, zpravidla definován
jako unsigned int
) . Funkce vrací ukazatel na počátek přiděleného bloku paměti, pokud má operační systém požadovanou velikost
paměti k dispozici. Ukazatel typu (void *)
představuje obecný ukazatel, který není vázán na konkrétní datový typ. Protože
překladač kontroluje kompatibilitu typů ukazatelů při přiřazování, je nutné při volání funkce výsledek přetypovat.
(viz příklad).
V souvislosti s ukazateli je nutná zmínka o konstantě NULL
, která je definována jako symbolická (většinou
má hodnotu 0). Znamená hodnotu „ukazatele nikam“ – je obdobou hodnoty nill v Pascalu. V případě, že operační systém nemá
k dispozici dostatek volné paměti, vrací funkce malloc
hodnotu NULL
. Správně napsaný program by
měl otestovat výsledek volání funkce malloc
, např. takto:
int *p; p = (int *)malloc(512); // alokuji 512 bytu pameti if (p == NULL) { printf("Nedostatek pameti"); return; }S využítím přiřazovacího výrazu v podmínce můžeme napsat kód efektivněji:
int *p; if ((p = (int *)malloc(512))== NULL) { printf("Nedostatek pameti"); return; }V praxi je běžné, že potřebujeme alokovat paměť pro dynamické pole o n prvcích určitého typu. K výpočtu potřebné velikosti paměti v bytech využijeme operátor
sizeof
s parametrem daného typu. Konkrétně, dynamické pole o n prvcích typu int
alokujeme tímto způsobem:
int *p; p = (int *)malloc(sizeof(int)*n);Čtenář se může ještě setkat s jimými funkcemi pro alokaci paměti -
calloc
a realloc
.void *calloc(size_t n, size_t size)
alokuje paměť pro n položek, každou o velikosti size bytů. Odpovídá tedy volání
funkce malloc(size*n)
, navíc celý přidělený paměťový blok nuluje.void *realloc(void *block, size_t size)
provádí realokaci paměti. Parametrem je ukazatel block na již dříve alokovanou
paměť funkcemi malloc, calloc, realloc
, size je nová požadovaná velikost paměti (logicky zpravidla větší než dříve
alokovaná). Funkce vrátí ukazatel na nově alokovaný blok paměti o velikosti size, obsah původního bloku zkopíruje na počátek nově
alokovaného bloku. Pokud má parametr block hodnotu NULL
, funkce se chová jako malloc
. Není-li k dispozici
dostatek pamětí, vrací NULL
.
Před ukončením činnosti (nebo v okamžiku, kdy ji již nepotřebuje) by měl program alokovanou paměti uvolnit (vrátit k dispozici operačnímu systému).
K uvolnění paměti slouží funkce free
z knihovny stdlib.h
:
Parametrem je ukazatel na blok paměti, který byl dříve alokován pomocí funkcevoid free(void *block);
malloc
(resp. realloc
či
calloc
).
Přístup k prvkům dynamicky alokovaného pole je stejný jako u pole statického, tedy pomocí indexů. K prvkům lze přistupovat i pomocí ukazatelové aritmetiky, kterou uvedeme později.
Nyní uvedeme jednoduchý příklad dynamické alokace pole pro uložení čísel a výpisu tohoto pole v opačném pořadí.
Polotovar:
Řešení:
Příklad:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int *p;
int n; // velikost pole
int i;
printf("Zadejte pocet zpracovavanych cisel: ");
scanf("%d",&n);
if ((p=(int*)malloc(sizeof(int)*n))==NULL)
{
printf("Neni dostatek dynamicke pameti.");
return 1;
}
printf("Zadejte %d celych cisel odelenych mezerou:\n",n);
// nacteni prvku pole
for(i=0;i<n;i++) scanf("%d",&p[i]);
putchar('\n');
// vypis v opacnem poradi
for(i=n-1;i>=0;i--) printf("%d ",p[i]);
putchar('\n');
free(p);
return 0;
}
Kód je k dispozici i k přímému stažení: Dev C++:
Dev C++: dyn_pole1.dev, dyn_pole1.c CodeBlocks: dyn_pole1.cbp, dyn_pole1.c Úloha 4.2
Napište program, který vypočítá a vytiskne součet dvou vektorů o stejné dimenzi. Nejprve načte z klávesnice počet prvků vektoru (dimenzi n),
alokuje dynamicky tři pole. Pak načte prvky prvního vektoru a následně prvky druhého vektoru, každý vektor do samostatného pole.
Řešení:
Dev C++: soucetv.dev, soucetv.c CodeBlocks: soucetv.cbp, soucetv.c
Dev C++: soucetv.dev, soucetv.c CodeBlocks: soucetv.cbp, soucetv.c Úloha 4.3
Napište program, který vypíše na obrazovku všechna prvočísla od 1 do n, n je přirozené číslo zadané z klávesnice.
Využijte algoritmus Eratostenova síta. Pole alokujte dynamicky, dle zadaného n.
Dev C++: eratos.dev, eratos.c CodeBlocks: eratos.cbp, eratos.c
[Cvičení 3] | [Obsah] | [Cvičení 5] |