Dynamiskt minne Agenda Vad är dynamiskt minne Motivering Hur gör man i C Övningar
Minne Datorns primärminne används till olika ändamål De flesta system partitionerar minnet efter användningen: Programkoden Variablerna: Globala (+statiska) Lokala Dynamiskt allokerade
Programkod Globala+statiska Stacken (lokala variabler) Minne Fix storlek, känt efter kompilering Växer/krymper under körning Heapen (dynamiskt minne)
Stacken Låt oss se vad som händer då ett program körs. Vi intresserar oss för variablerna och speciellt hur stacken används då funktionerna körs.
void baz(void) { int C[100]; void bar(void) { float B[100]; baz(); void foo(void) { double A[100]; bar(); int main(void) { short X[100]; foo(); return 0; Några funktioner
void baz(void) { int C[100]; void bar(void) { float B[100]; baz(); void foo(void) { double A[100]; bar(); int main(void) { short X[100]; foo(); return 0; Några funktioner Stacken
void baz(void) { int C[100]; void bar(void) { float B[100]; baz(); void foo(void) { double A[100]; bar(); int main(void) { short X[100]; foo(); return 0; Några funktioner X: Stacken
void baz(void) { int C[100]; void bar(void) { float B[100]; baz(); void foo(void) { double A[100]; bar(); int main(void) { short X[100]; foo(); return 0; Några funktioner A: X: Stacken
void baz(void) { int C[100]; void bar(void) { float B[100]; baz(); void foo(void) { double A[100]; bar(); int main(void) { short X[100]; foo(); return 0; Några funktioner B: A: X: Stacken
void baz(void) { int C[100]; void bar(void) { float B[100]; baz(); void foo(void) { double A[100]; bar(); int main(void) { short X[100]; foo(); return 0; Några funktioner C: B: A: X: Stacken
void baz(void) { int C[100]; void bar(void) { float B[100]; baz(); void foo(void) { double A[100]; bar(); int main(void) { short X[100]; foo(); return 0; Några funktioner B: A: X: Stacken
void baz(void) { int C[100]; void bar(void) { float B[100]; baz(); void foo(void) { double A[100]; bar(); int main(void) { short X[100]; foo(); return 0; Några funktioner A: X: Stacken
void baz(void) { int C[100]; void bar(void) { float B[100]; baz(); void foo(void) { double A[100]; bar(); int main(void) { short X[100]; foo(); return 0; Några funktioner X: Stacken
void baz(void) { int C[100]; void bar(void) { float B[100]; baz(); void foo(void) { double A[100]; bar(); int main(void) { short X[100]; foo(); return 0; Några funktioner Stacken
Stack vs. Heap Lokalt deklarerade arrayer (dvs på stacken) kan ha dynamisk storlek Enkelt att hantera - automatisk återäming Begränsad livstid Dynamiskt allokerat minne (dvs på heapen) Kan behållas så länge man önskar Räcker att allokera det som behövs för tillfället Ägandet kan relatera till objekt istället för funktioner Måste lämnas tillbaks exakt en gång lätt att missa
Skapa dynamiskt minne i C Det är i huvudsak två funktioner du behöver använda: malloc free malloc tar minne i anspråk Motsvarar att deklarera en variabel Data är dock inte bundet till en viss funktion Kom ihåg: Lokala variabler försvinner då funktionen lämnas dock ej dyn. minne
Återlämna dynamiskt minne free återlämnar ett dynamiskt allokerat minne Då minnet inte försvinner automatiskt så är det ditt ansvar som programmerare att återlämna det
Kodfragment struct CAR *carp; int n=20; // Allokera en array av 20 element: carp = malloc(sizeof(struct CAR)*n); if (carp) {... // Gör något roligt... // Arbetet klart: lämna tillbaks minnet free(carp);
Kodfragment struct CAR *carp; int n=20; // Allokera en array av 20 element: carp = malloc(sizeof(struct CAR)*n); if (carp) {... // Gör något roligt... // Arbetet klart: lämna tillbaks minnet free(carp); Allokering och återlämnande behöver inte ske i samma funktion
Funktionerna void *malloc(int size); Returnerar en pekare till dynamiskt minne eller NULL om det inte finns något ledigt av tillräcklig storlek void free(void *mem); Återlämnar till systemet det minne som pekas ut av 'mem'. Detta är tidigare allokerat med malloc
Access av dynamiskt minne Eftersom vi når det via pekare så tillkommer inget nytt. När vi skickat arrayer som argument till funktioner så skickades egentligen pekare. Pekare vet inte om ifall de pekar på arrayer eller dynamiskt minne. Metoden för access är alltså densamma
Access struct CAR *carp; int n=20; // Allokera en array av 20 element: carp = malloc(sizeof(struct CAR)*n); if (carp) {... for (i=0; i<n; i++) scanf( %d, &carp[i].doors);... // Arbetet klart: lämna tillbaks minnet free(carp);
Returnera arrayer? Ibland vill man returnera en större mängd data från en funktion: struct CAR *load_cars(void) { struct CAR bilar[100]; FILE *fp = fopen( cars, rb ); if (fp) { fread(bilar, sizeof(struct CAR), 100, fp); fclose(fp); return bilar;
Returnera arrayer - nej! Ibland vill man returnera en större mängd data från en funktion: struct CAR *load_cars(void) { struct CAR bilar[100]; FILE *fp = fopen( cars, rb ); if (fp) { FEL!!! fread(bilar, sizeof(struct CAR), 100, fp); fclose(fp); return bilar;
Returnera arrayer - nej! Ibland vill man returnera en större mängd data från en funktion: struct CAR *load_cars(void) { struct CAR bilar[100]; FILE *fp = fopen( cars, rb ); if (fp) { fread(bilar, sizeof(struct CAR), 100, fp); fclose(fp); return bilar; FEL!!! Syntaktiskt korrekt, men: bilar försvinner när load_cars returnerar
Returnera dynamiskt minne! Gör om gör rätt! struct CAR *load_cars(void) { struct CAR *bilar= malloc(sizeof(struct CAR)*100); FILE *fp = fopen( cars, rb ); if (fp && bilar) { fread(bilar, sizeof(struct CAR), 100, fp); fclose(fp); return bilar;
Returnera dynamiskt minne! Gör om gör rätt! struct CAR *load_cars(void) { struct CAR *bilar= malloc(sizeof(struct CAR)*100); FILE *fp = fopen( cars, rb ); if (fp && bilar) { fread(bilar, sizeof(struct CAR), 100, fp); fclose(fp); return bilar; Dynamiskt minne finns kvar tills man gör free
Övning Skriv en funktion som allokerar dynamiskt minne till ett heltal och låter användaren skriva in data till detta. Skriv en annan funktion som skriver ut det inmatade värdet. Båda funktionerna anropas från main. Minnet ska återlämnas så snart det inte längre behövs.
Övning 2 Skriv ett program som: läser in ett antal flyttal från en fil räknar hur många nollor som finns bland talen skriver ut detta En testfil finns på hemsidan (rätt utskrift:305784). Först i filen finns ett heltal som anger antal element Låt koden återge problemets delar, dvs: float *load_numbers(int *n); Funktionen läser in data från filen till dynamiskt allokerat minne. int count_zeros(float *arr, int n); Funktionen returnerar antalet nollor i arrayen som pekas ut av arr. n anger antalet element. Utskriften görs i main Var återlämnar du minnet?