Dynamisch geheugen beheer + Normaal wordt laats in het werkgeheugen gereserveerd tijdens de comilatie aan de hand van de declaraties van de variabelen. + Deze geheugenreservering is statisch: in het bronbestand van het rogramma wordt reeds vastgelegd hoe groot bijvoorbeeld een array zal zijn. + Hieraan is tijdens de uitvoering van het rogramma niets meer te veranderen. + In laats daarvan kan geheugen meer dynamisch gereserveerd worden. Hiervoor zijn functies ter beschikking om geheugen tijdens run-time aan te vragen en eventueel later weer vrij te geven. void malloc ( s i z e t grootte ) ; void free ( void ) ; Afhankelijk van de toeassing zal de gealloceerde ruimte data bevatten van een beaald tye. Omdat tijdens de uitvoering van malloc geen informatie ter beschikking is omtrent het tye van de anonieme variabele, wordt door malloc een ointer teruggegeven die naar data van een willekeurig tye wijst. Dit wordt aangegeven door het tye void *. Dit tye moet omgezet worden naar het juiste tye, door middel van de casting oerator. + Om deze functies te gebruiken moet een include van het malloc.h headerbestand gebeuren. malloc: memory allocatie; argument grootte van de ruimte die men wenst te alloceren, uitgedrukt in aantal bytes. Indien de uitvoering van de functie succesvol verloot, wordt het adres teruggegeven van het begin van de toegekende ruimte. Deze ruimte bestaat uit een oeenvolging van een aantal bytes gelijk aan grootte. Indien er iets misgaat, wordt een NULL waarde teruggeven. Returnwaarde van malloc is een adres van een geheugenruimte dat zelf geen naam heeft. Deze returnwaarde wordt toegewezen aan een ointer variabele, zodat de anonieme variabele via die ointer gebruikt kan worden. free: met argument zo n ointer variabele die via malloc een waarde toegewezen gekregen heeft. Het effect van de functie is dat de ruimte waarnaar de ointer wijst, vrij gegeven wordt. Deze ruimte kan dan achteraf door een oroe van malloc terug gealloceerd worden (om voor iets anders gebruikt te worden). Functie heeft geen return-waarde, dus als een rocedure te bestemelen. * dynvar.c : dynamische geheugen allocatie int ; double q ; = ( int ) malloc ( sizeof ( int ) ) ; = 5; rintf ( De toegekende waarde i s %d\n, ) ; free ( ) ;
q = (double ) malloc ( sizeof (double ) ) ; q = 5.25; rintf ( De toegekende waarde i s %f \n, q ) ; free (q ) ; Het gebruik van ointers in rogramma s leidt vrij dikwijls tot fouten. Twee bekende fenomenen: dangling ointer : een variabele die een adres bevat naar een reeds gedeallocceerd object: = malloc (20); free ( ) ; int: 4 bytes double: 8 bytes lost object : een gealloceerd dynamische object dat niet langer toegankelijk is vanuit het rogramma, maar toch nog bruikbare data bevat: q = malloc (40); = malloc (4); In laats van string ointers te initialiseren met adressen van vooraf gedefinieerde karakters en arrays van karakters, kan ook de functie malloc gebruikt worden om de geheugenlaatsen voor de string as tijdens run-time te voorzien. char c ; c = (char ) malloc (32); strcy (c, dit i s een nieuwe string ) ; Dynamische arrays * dynar.c : array met dynamische lengte #define VIJF 5 w c 32 bytes dit is een nieuwe string double ; Merk o dat er een verschil is met een gewone array van karakters: char w[32];. = (double ) malloc ( VIJF sizeof (double ) ) ; memset (, 0, VIJF sizeof (double ) ) ;
= 1.11; (+1) = 2.22; (+2) = 3.33; (+3) = 4.44; (+4) = 5.55; rintf ( De toegekende waarden zijn : ) ; for ( i =0; i<vijf; i++) rintf ( %5.2 f, [ i ] ) ; rintf ( \n ) ; Om een element in de dynamisch gealloceerde array aan te sreken, kan men zowel de ointer notatie (*(+i)) als de array notatie ([i]) gebruiken. 1.11 2.22 3.33 4.44 5.55 q [ i ] = ( float ) malloc ( m sizeof ( float ) ) ; rintf ( Geef de elementen in r i j er r i j \n ) ; for ( j =0; j<m; j++) scanf ( %f, &q [ i ] [ j ] ) ; scanf ( % c ) ; berekeningen... rintf ( %8 :, q [ i ] ) ; for ( j =0; j<m; j++) rintf ( %8.3 f, ( (q+i )+j ) ) ; rintf ( \n ) ; * dynmat.c : matrix met dynamisch aantal rijen en kolommen #include <s td lib. h> float q ; int n, m; int i, j ; vrijgeven geheugen free (q ) ; free (q [ i ] ) ; Bij deze dynamische 2-dimensionale array is q een ointer naar een ointer; vandaar de twee * in de declaratie. m q 10 rintf ( Geef aantal r i je n en aantal kolommen : ) ; scanf ( %d%d% c, &n, &m) ; reservering geheugen q = ( float ) malloc ( n sizeof ( float ) ) ; n 5
Dynamische structures Na definitie (lijn 20) bevat de variabele geen zinnige informatie. Er is alleen laats voorzien om het resultaat van een malloc o te slaan. Wanneer deze toekenning gebeurd is, wijst naar een ruimte van 32 bytes (sizeof(koel)). Door middel van de casting oerator wordt deze ruimte geïnterreteerd als iets van tye Koel. Bij de tweede allocatie wordt ineens ruimte voorzien voor N = 6 structures en q wijst naar het eerste element hiervan. Men kan q ook interreteren als een array van N elementen waarbij elk element van tye Koel is (for-lus vanaf lijn 32). Dit kan natuurlijk ook o een ointer-achtige manier geschreven worden, zie for-lus vanaf lijn 41. Met behul van de r++ exressie wordt telkens naar het volgende element in de array gewezen. Koel ; Koel, q, r ; Mens m; = ( Koel ) malloc ( sizeof ( Koel ) ) ; >links. l e e f t i j d = 21; >rechts. l e e f t i j d = 19; rintf ( links %d rechts %d\n, >links. l e e f t i j d, >rechts. l e e f t i j d ) ; q = ( Koel ) malloc ( N sizeof ( Koel ) ) ; memset (q, 0, N sizeof ( Koel ) ) ; for ( i =0; i<n; i++) * dynstru.c : dynamische structuren #include <s td lib. h> #include <string. h> #define N 6 tyedef struct char naam [ 1 4 ] ; short l e e f t i j d ; Mens ; tyedef struct Mens links ; Mens rechts ; q [ i ]. links. l e e f t i j d = 30+ i ; q [ i ]. rechts. l e e f t i j d = 30 i ; rintf ( links %d rechts %d\n, r >links. l e e f t i j d, r >rechts. l e e f t i j d ) ; ( r ). links. l e e f t i j d = 40+ i ; ( r ). rechts. l e e f t i j d = 40 i ; rintf ( links %d rechts %d\n, r >links. l e e f t i j d, r >rechts. l e e f t i j d ) ; m = (Mens )q ;
Een voorbeeld. for ( i =0; i <2 N; i++, m++) m >l e e f t i j d = 50 + ( i%2? i /2 : i /2); rintf ( links %d rechts %d\n, r >links. l e e f t i j d, r >rechts. l e e f t i j d ) ; In het laatste gedeelte (vanaf lijn 50) wordt de array van N Koel structures geïnterreteerd als een array van 2N Mens structures. Hiervoor wordt de q ointer van tye Koel * via de casting oerator omgezet naar de m ointer van tye Mens *. In het rogramma-deel wordt een vector object beschreven: wat de elementen van het object zijn en welke oeraties o dit object mogelijk zijn. * vector.h : definities tyedef struct vector Vector ; int lengte ; double arr ; Vector creatie ( int lengte, double waarde ) ; void teniet ( Vector v ) ; void drukaf ( Vector v ) ; Vector lus ( Vector v1, Vector v2 ) ; double inwro ( Vector v1, Vector v2 ) ; q r m 21 19 30 40 50 30 40 50 31 41 51 29 39 49 32 42 52 28 38 48 33 43 53 27 37 47 34 44 54 26 36 46 35 45 55 25 35 45 * vector.c : imlementatie #include vector. h Vector creatie ( int lengte, double waarde ) Vector vec = 0, NULL ; if ( lengte > 0 ) vec. lengte = lengte ; vec. arr = (double ) malloc ( lengte sizeof (double ) ) ;
for ( i =0; i<lengte ; i++) vec. arr [ i ] = waarde ; return vec ; void teniet ( Vector v) if ( v >lengte == 0 && v >arr == NULL ) return ; else free (v >arr ) ; v >lengte = 0; v >arr = NULL; return ; vec. arr [ i ] = v1. arr [ i ] + v2. arr [ i ] ; return vec ; double inwro ( Vector v1, Vector v2) double res = 0. 0; if ( v1. lengte!= v2. lengte ) return res ; for ( i =0; i<v1. lengte ; i++) res += v1. arr [ i ] v2. arr [ i ] ; return res ; Om deze routines te testen kan een testrogramma gemaakt worden: void drukaf ( Vector v) for ( i =0; i<v. lengte ; i++) rintf ( %10.3 f, v. arr [ i ] ) ; rintf ( \n ) ; Vector lus ( Vector v1, Vector v2) Vector vec ; if ( v1. lengte!= v2. lengte ) return creatie (0, 0. 0 ) ; vec = creat ie (v1. lengte, 0. 0 ) ; for ( i =0; i<vec. lengte ; i++) * testvec.c : testrogramma #include vector. h Vector a, b, c ; a = creat ie (5, 2. 5 ) ; b = creati e (5, 6. 9 ) ; c = lus (a, b ) ; drukaf ( c ) ; rintf ( Inwendig roduct = %f \n, inwro (a, c ) ) ; teniet (&a ) ; teniet (&b ) ; teniet (&c ) ;
Denktaak #include <s td lib. h> #define LEN 16 char c ; char car [LEN] ; Besreek aan de hand van bovenstaand rogramma het verschil tussen een array van characters en een ointer naar een character. Leg uit wat er gebeurt bij starten van a.out joske flu. Merk o dat lijn 18 een syntax fout bevat; wat is er verkeerd? i f ( argc!= 3 ) exit (1); c = (char ) malloc ( LEN sizeof (char) ) ; strcy (c, argv [ 1 ] ) ; strcy ( car, argv [ 2 ] ) ; c++; rintf ( via ointer %s \n, c ) ; car++; rintf ( via array %s \n, car ) ; foin ( c ) ; rintf ( \t\t ointer %s \n, c ) ; farray ( car ) ; rintf ( \t\t array %s \n, car ) ; foin (char t ) t++; rintf ( \ tfun ointer %s \n, t ) ; farray (char tar [ ] ) tar++; rintf ( \ tfun array %s \n, tar ) ;