PB071: Úvod do jazyka C - 6

Více o deklaracích; uživatelské datové typy; dynamická alokace paměti

Další informace o deklaracích

Oblast platnosti jmen

Druh: Deklarováno: Platí:
Lokální na začátku funkce nebo bloku (v C99 kdekoli ve funkci nebo bloku) od místa deklarace do konce bloku
Globální mimo funkce od místa deklarace do konce souboru

Paměťové třídy

Vždy právě jedna třída:

auto Implicitní! Vzniká při volání funkce nebo vstupu do bloku, zaniká při jejím opuštění.
register Jako auto s umístěním pokud možno do registru.
extern Dostupné v celém programu (i v jiných souborech). V jednom ze souborů musí být skutečná deklarace.
Příklad:
V 1 souboru: int *prvocisla={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
Ve všech souborech: extern int *prvocisla;
static
  • Globální proměnné: dostupné jen v daném souboru. V jiných souborech může být jméno použito pro jiný objekt (nedoporučuje se však)
  • Lokální proměnné: uchovají si hodnotu do příštího volání funkce

Viditelnost jmen

V oblasti platnosti kromě vložených míst, kde je definován jiný stejnojmenný objekt, jehož název "zastíní" objekt původní.

Kvalifikátory - pouze v ANSI C a C99

Uživatelem definované datové typy

Výčtový typ enum

enum r_obdobi { jaro, leto, podzim, zima } obdobi,*p_obd;

Lze oddělit deklaraci typu od deklarace proměnných tohoto typu:

enum r_obdobi { jaro, leto, podzim, zima };
enum r_obdobi obdobi,*p_obd;

Klíčové slovo enum není možné ani při opakovaném použití jako o řádek výš vynechat (na rozdíl od jazyka C++). (r_obdobi není datový typ)

Implicitně jaro==0 leto==1 atd. Lze změnit:

enum r_obdobi { jaro=0, leto=1, podzim=0, zima=-1 };

Použití: možno int i=podzim; nelze obdobi=1;

Strukturovaný typ struct

struct osoba
{ char jmeno[21];
  char prijmeni[31];
  unsigned int osob_cislo;
  unsigned long int tel_cis;
  char oddeleni[11];
  struct osoba *nadrizeny;
} sef, sekret, ucetni;

Opět lze oddělit deklaraci typu od deklarace proměnných:

struct telefon
{ unsigned int predvolba;
  unsigned long int cislo;
  unsigned int klapka; };
struct telefon stara, otec={420,543210987L,124};

Podobně jako u výčtu název struktury není datový typ!

Použití komponent struktury - pomocí operátorů . a ->

sekret.nadrizeny=&sef;
int smerovka=otec.predvolba;
struct osoba *nekdo=&ucetni;
printf("%s ma telefon %lu\n",nekdo->prijmeni,nekdo->tel_cis);

x->y znamená totéž jako (*x).y

Bitová pole

Rozdělení struktury nebo unionu na položky int, unsigned int (doporučeno) nebo signed int (v C99 rovněž _Bool) o délce měřené pouze na bity. Délka   komponent se zadává (jakožto počet bitů) za jejich názvy po dvojtečce:

struct barva { unsigned int red:5; unsigned int green:6; unsigned int blue:5; };

Často tak však paměť neušetříme - zkrátí se data, ale prodlouží přeložený program.

Typ union

Jako struct, ale položky se v paměti překrývají.

union atom { int i; double d; char var[7]; };

Inicalizovat lze pouze složku unionu uvedenou jako první (v C99 to lze obejít použitím pojmenovaného inicializátoru - viz dále).

Deklarace typedef

typedef typ synonymum

Např.

typedef unsigned long int uli;
typedef char line [81]; /* POZOR - ne char[81] line */
        /* line je ted typ ekvivalentni char[81] */
typedef float* pfl;
typedef struct {int den; int mesic; int rok;} datum;

Potom lze psát deklarace jako:

uli velke_cislo;
line nadpis="Rekapitulace:";
pfl function vyber(datum d);

V C99 však nelze použít typedef pro parametr nebo návratovou hodnotu funkce! Lze obejít použitím makra:
#define pfl float *
#define datum
struct {int den; int mesic; int rok;}

Makro má však jiné úskalí:
pfl p1,p2
se rozvine jako
float * p1,p2;
takže p2 není ukazatel!

Pojmenované inicializátory (C99)

V C99 lze rovněž inicializovat pouze vybrané prvky pole nebo komponenty struktury či unionu:

int A[100] =  {1, [99]=-1};

Prvek A[0] bude mít počáteční hodnotu 1, A[99] hodnotu -1, ostatní budou nulové.

struct souradnice {double x; double y;};
struct souradnice vrchol = {.y=1.5};

Explicitně je inicializována jen souřadnice y, vrchol.x bude proto mít hodnotu 0.

Složené literály (C99)

Přiřazení hodnoty struktuře

Ačkoli v deklaraci lze použít inicializaci struktury, nelze struktuře přiřadit konstantu přiřazovacím příkazem
otec={420,543210987,124}; /* CHYBA! */
protože neexistují konstanty typu struktura.

V C99 však takový složený literál použít lze, pokud jej explicitně přetypujeme:

otec=(struct telefon){420,543210987,124};

Explicitně řízená dynamická alokace paměti

#include <stdlib.h>

void *malloc (size_t size);
void free (void *ptr);
void *realloc (void *ptr, size_t size);

size_t je typ, který se pomocí typedef v závislosti na platformě mapuje na některý celočíselný typ (obvykle unsigned int nebo unsigned long int

Funkce malloc alokuje potřebnou paměť a vrátí ukazatel na její začátek, ten je třeba přetypovat na ukazatel na příslušný typ. Příklad použití:

double *dynpole=(double *)malloc(N*sizeof(double));

S dynamicky alokovaným polem se pracuje jako s obyčejným polem, je možné ho obvyklým způsobem indexovat. Pouze sizeof dynpole nevrátí délku pole, ale délku ukazatele.

Až pole přestaneme potřebovat, uvolníme alokovanou paměť:

free(dynpole);

V případě potřeby lze pole realokovat na jinou velikost (větší i menší) pomocí funkce realloc. Dosavadní obsah se zkopíruje do nově alokovaného pole a potom se původní pole zruší.

Příklad (navazuje na předchozí příklad): Pokud alokované pole nestačí, zdvojnásobíme je:

N*=2;
dynpole=realloc(dynpole,N*sizeof(double));

Dynamická alokace v C99

Zdálo by se, že v C99 jsou uvedené funkce zbytečné, protože pole lze deklarovat s dynamickými mezemi i normální deklarací. Přesto však přinejmenším ve dvou případech to nestačí:

Přehled možností alokace paměti (ilustrováno na poli) 

Druh: Příklad: Alokováno po dobu:
Statická double x[10]; (mimo funkci)
static double x[10];
(ve funkci)
Po celou dobu práce programu (alokováno při překladu/linkování)
Automatická
s pevnou délkou
double x[10]; (ve funkci) Během práce funkce nebo bloku (ANSI C)
Od deklarace do konce funkce nebo bloku (C99)
Automatická
s proměnnou délkou
int n;
double x[n]; (ve funkci; jen C99)
Od deklarace do konce funkce nebo bloku
Řízená double *x=
(double*)malloc(n*sizeof(double));
Od provedení malloc do provedení free nebo do konce programu (free může být i v jiné funkci)

Předchozí Předchozí přednáška Další Další přednáška Hlavní stránka Hlavní stránka