¸ 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);
}