ZARZA

¸ DZANIE

PAMIE

ÇIA

¸

void *realloc(void *p, size_t size);

Standardowe funkcje malloc i calloc dynamicznie pobieraj¸

a

Funkcja realloc zmienia rozmiar obiektu wskazywanego przez p od systemu ż¸

adane bloki pami¸

eci.

na wartość określon¸

a przez size. Zawartość obiektu nie ulegnie zmianie w jego cz¸

eści pocz¸

atkowej o rozmiarze równym mniej-

szemu z rozmiarów: starego i nowego. Jeśli nowy rozmiar jest void *malloc(size_t n);

wi¸

ekszy, to dodatkowy obszar pami¸

eci nie jest inicjowany.

Funkcja zwraca wskaźnik do nowego obszaru lub NULL, jeśli polecenie nie może być wykonane. Wówczas wskaźnik p nie ulega Zwraca:

zmianie.

• wskaźnik do n bajtow nie zainicjowanej pami¸eci w przypadku powodzenia

#include <stdio.h>

•

#include <stdlib.h>

NULL, gdy ż¸

adanie nie może być spełnione.

#include <string.h>

Przykład:

int main(void)

{

#include <stdio.h>

char *str;

#include <string.h>

/* allocate memory for string */

#include <stdlib.h>

str = (char *) malloc(10);

#include <process.h>

/* copy "Hello" into string */

strcpy(str, "Hello");

int main(void)

printf("String is %s\n

Address is %p\n", str, str);

{

str = (char *) realloc(str, 20);

char *str;

printf("String is %s\n

New address is %p\n",

/* allocate memory for string */

str, str);

if ((str = (char *) malloc(10)) == NULL)

/* free memory */

{

free(str);

printf("Not enough memory to allocate buffer\n"); return 0;

exit(1);

/* terminate program if out of memory */

}

}

/* copy "Hello" into string */

strcpy(str, "Hello");

Zwolnienie przydzielonej pami¸

eci

/* display string */

printf("String is %s\n", str);

/* free memory */

free(str);

void free(void *p);

return 0;

}

Funkcja free zwalnia obszar pami¸

eci wskazywany przez p; nie

robi nic, jeśli p równa si¸

e NULL.

void *calloc(size_t obj, size_t size);

Argument p musi być wskaźnikiem do obszaru uprzednio przydzielonego przez jedn¸

a z funkcji: malloc, calloc, realloc.

Różnica mi¸

edzy standardow¸

a deklaracj¸

a tablicy, a jej

Funkcja calloc

zwraca wskaźnik do obszaru pami¸

eci przezna-

dynamiczn¸

a alokacj¸

a

czonego dla tablicy złożonej z nobj elementów, każdy o rozmiarze size.

Funkcja zwraca NULL, jeśli to polecenie nie może być wy-1)

char hello[5];

konane. Obszar jest inicjowany zerami.

2)

char *hello=(char *) malloc((size_t) 5);

#include <stdio.h>

#include <stdlib.h>

1. pami¸

eć przydzielana do pami¸

eci stosu (stack memory),

#include <string.h>

która jest ponownie wykorzystywana po zakończeniu dzia-

łania funkcji

int main(void)

{

2. przydział do pami¸

eci sterty - heap (heap memory - sterta char *str = NULL;

zmiennych dynamicznych w pami¸

eci operacyjnej.

/* allocate memory for string */

str = (char *) calloc(10, sizeof(char));

/* copy "Hello" into string */

Heap memory - cała pami¸

eć za wyj¸

atkiem bufora pami¸

eci stosu

strcpy(str, "Hello");

(oraz bufora bezpieczeństwa wokół stosu.

/* display string */

Uwaga:

printf("String is %s\n", str);

/* free memory */

• bł¸edem jest zwalnianie czegos, co nie zostało przydzielone free(str);

za pomo¸

a funkcji malloc lu/b calloc

return 0;

}

• bł¸edem jest również używanie czegoś, co zostało zwolnione Uwaga: Wartość wskaźnika zwracanego przez obydwie funkcje Typowym

i

niepoprawnym fragmentem programu

jest

trzeba zrzutować na odpowiedni typ.

nast¸

epuj¸

aca p¸

etla, która zwalnia bloki pami¸

eci powi¸

azane w łań-

Zmiana wielkości przydzielonego obszaru cuch:

• opuszczenie w deklaracji tablicy określenia liczby elemen-for (p=head; p != NULL; p=p->next)

/* Zle

*/

tów w pierwszym wymiarze tablicy powoduje domniema-free(p);

nie go na podstawie listy inicjatorów.

Poprawnie nalezy przechowywac wszystko, co jeszcze Przykłady:

bedzie potrzebne przed zwolnieniem pamieci: for (p=head; p != NULL; p=q) {

int Vec[3]={10,20,30};

q=p->next;

long int Arr[3][2]={ {1,2}, {3,4}, {5,6}}; free(p);

char Greet[6]={’H’,’e’,’l’,’l’,’o’};

}

/*

Greet[6] przypisano domy\’ slnie ’\0’ */

char Text[]="Hello World";

Tablice wielowymiarowe

/*

domniemany rozmiar

12 */

short int Matrix[2][3]={{1,2},{3}};

Zasady:

/*

domniemany inicjator {{1,2,0},{3,0,0}} */

• tablica dwuwymiarowa jest jednowymiarow¸a tablic¸a, w której każdy element jest tablic¸

a jednowymiarow¸

a

Wskaźniki a tablice wielowymiarowe

• dopuszczalne jest niedookreślenie pierwszego wymiaru Po nast¸

epuj¸

acych definicjach:

(jego określenie nast¸

epuje wówczas w momencie inicjali-

zacji), natomiast nast¸

epne musz¸

a być sprecyzowane

int a[10][20];

int *b[10];

• elementy s¸a umieszczane w pami¸eci wierszami, tzn. odwo-

łanie

oba zapisy a[3][4] i b[3][4] s¸

a poprawnymi odwołaniami do poje-

dyńczego obiektu typu int.

daytab[i][j] /* [wiersz][kolumna] */

oznacza odniesienie do wiersza i-tego,

a jest

prawdziw¸

a

tablic¸

a

wielowymiarow¸

a,

zarezerwo-

kolumny

j-tej. (Najszybciej zmienia

wano

dla

niej

200

miejsc

o

rozmiarze

int;

ele-

si\c e prawy skrajny indeks.

ment a[wiersz][kolumna] znajduje si¸

e według wzoru:

20*wiersz+kolumna

Przykład:

b przydziela jedynie 10 miejsc na wskaźniki i nie inicjuje ich; nadanie wartości pocz¸

atkowych musi być zrobione jawnie

static char daytab[2][13]={

- statycznie lub programowo.

{0,31,28,31,30,31,30,31,31,30,31,30,31}, Jeśli każdy z elementów tablicy b wskazuje na tablic¸

e 20

{0,31,28,31,30,31,30,31,31,30,31,30,31}}; elementów całkowitych. Wówczas mamy zarezerwowane 200 miejsc rozmiaru int plus 10 komórek na wskaźniki.

/* podaj dzien roku na podstawie miesiaca i dnia

*/

int day_of_year(int year, int month, int day) Ważn¸

a przewag¸

a tablicy wskaźników jest możliwość zróżnico-

{

wania długości wierszy.

int i,leap;

leap=year % 4 == 0 && year % 100 != 0

Przekazywanie tablicy dwuwymiarowej do funkcji

|| year % 400 == 0;

Musimy podać liczb¸

e kolumn. Zatem, jeśli tablica daytab ma for (i=1; i<month; i++)

być przekazana do funkcji f, to deklaracja funckji powinna mieć day += daytab[leap];

jedn¸

a z trzech poniższych postaci:

return day;

}

f(int daytab[2][13]);

/* podaj miesiac i dzien na podstawie dnia roku */

void month_day(int year, int yearday,

f(int daytab[][13]);

int *pmonth, int *pday)

{

f(int (*daytab)[13]);

int i,leap;

leap=year % 4 == 0 && year % 100 != 0

|| year % 400 == 0;

Ostatnia deklaracja mówi, że daytab jest wskaźnikiem do ta-for (i=1; yearday > daytab[leap][i]; i++) blicy 13 liczb całkowitych. Nawiasy okr¸

agłe s¸

a w tym przypadku

yearday -= daytab[leap][i];

konieczne, ponieważ nawiasy kwadratowe [] maj¸

a wyższy prio-

*pmonth=i;

rytet niż operator adresowania pośredniego *.

Bez nawiasów

*pday=yearday;

okr¸

agłych deklaracja

}

int *daytab[13];

Inicjowanie tablic wielowymiarowych

wprowadza tablic¸

e 13 wskaźników do obiektów całkowitych.

Lista inicjatorów jej elementów uj¸

eta w nawiasy klamrowe.

Możliwość korzystania z tablic wielowymiarowych o indeksach

•

ujemnych

Jeśli w pewnym nawiasie klamrowym zabraknie elementów, to uzupełnia si¸

e zerami ( {0} ).

Rozwi¸

azanie przyj¸

ete przez autorów Numerical Recipes:

• Jeśli

w

pewnych

nawiasach

wewn¸

etrznych

zostan¸

a

wymienione

#include <stdlib.h>

wszystkie inicjatory, to nawiasy takie można pomin¸

ać.

#include <stdio.h>

#define TYPFLOAT long double

• nawiasy klamrowe zawieraj¸ace list¸e zmaków można #define MSQRT sqrtl zast¸

apić napisem-łańcuchem składaj¸

acym si¸

e z takich wła-

#define MFABS fabsl

śnie znaków.

void nrerror(char error_text[])

/* Funkcja odczytu i tworzenia listy */

{

void czytanie(t_element **adpocz)

fprintf(stderr,

{

char nazwwe[DL_NAZW+1]; /* nazwisko czytane */

"Numerical Recipes run-time error...\n"); t_element *temp;

/* na zamiane wsk. */

fprintf(stderr,"%s\n",error_text);

*adpocz=NULL;

/* na poczatku lista pusta */

fprintf(stderr,"...now exiting to system...\n"); while (1) {

exit(1);

printf("nazwisko: ");

}

gets(nazwwe);

if (strlen(nazwwe)) {

TYPFLOAT **dmatrix(int nrl,int nrh,int ncl,int nch) temp=(t_element *) malloc(sizeof(t_element));

{

strcpy(temp->nazw,nazwwe);

int i;

printf("wiek: ");

TYPFLOAT **m;

scanf("%d", &temp->wiek); getchar(); /* przeskakuje znak \n */

m=(TYPFLOAT **)

temp->nast=*adpocz;

malloc((unsigned) (nrh-nrl+1)*sizeof(TYPFLOAT*));

*adpocz=temp;

if (!m) nrerror("allocation failure 1 in dmatrix()");

}

m -= nrl;

else break; /* wyjscie, gdy nazwisko puste */

}

for(i=nrl;i<=nrh;i++) {

}

m[i]=(TYPFLOAT *)

/* Funkcja wyprowadzania zawartosci listy */

malloc((unsigned) (nch-ncl+1)*sizeof(TYPFLOAT)); void pisanie(t_element *poc)

if (!m[i])

{

printf("\n\n

NAZWISKO

WIEK\n\n");

nrerror("allocation failure 2 in dmatrix()"); while (poc) {

m[i] -= ncl;

printf("%20s

%3d\n",poc->nazw, poc->wiek);

}

poc=poc->nast;

return m;

}

}

}

void free_dmatrix(TYPFLOAT **m,

int nrl,int nrh,int ncl,int nch)

{

int i;

for(i=nrh;i>=nrl;i--) free((char*) (m[i]+ncl)); free((char*) (m+nrl));

}

Odwołania do funkcji dmatrix mog¸

a wygl¸

adać nast¸

epuj¸

aco:

TYPFLOAT **Q;

/* .......

*/

Q=dmatrix(-10,N,-5,N);

Struktury odwołuj¸

ace si¸

e do samych siebie - tworzenie

listy

Lista - uporz¸

adkowany ci¸

ag elementów, z których każdy zawiera

wskaźnik do nast¸

epnego elementu.

Drzewo - uporz¸

adkowany ci¸

ag elementów, z których każdy za-

wiera wskaźnik do nast¸

epnego i poprzedzaj¸

acego elementu.

Przykład (program tworz¸

acy list¸

e danych wczytywanych z kla-

wiatury i wypisuj¸

acy j¸

a):

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#define DL_NAZW 20

/* maks. dl. nazwiska */

typedef struct element /* def. typu element */

{

char nazw[DL_NAZW+1]; /*nazwisko */

int wiek;

/* wiek */

struct element *nast; /* wsk. do nast. el. */

} t_element;

void main()

{

void czytanie(t_element **); /* f. tworzaca */

void pisanie(t_element *);

/* f. wypisujaca*/

t_element *poczatek; /*wsk. do poczatku listy*/

czytanie(&poczatek);

pisanie(poczatek);

}