4. Maskinnära programmering i C. Förberedelser till hemlaboration 1.

Relevanta dokument
IS1200 Datorteknik. Övning CE_O4 Maskinnära programmering med C Förberedelser till hemlaboration 1

CE_O3. Nios II. Inför lab nios2time

*Pekarvärden *Pekarvariabler & *

CE_O1. Nios II. Enkla assembler-instruktioner.

TDDC76 - Programmering och Datastrukturer

F5: Högnivåprogrammering

Att använda pekare i. C-kod

F5: Högnivåprogrammering

CE_O5. Cacheminne. Hemlaboration 2.

Programmering av inbyggda system. Kodningskonventioner. Viktor Kämpe

Dynamiskt minne. Vad är dynamiskt minne Motivering Hur gör man i C Övningar

Assemblerprogrammering, ARM-Cortex M4 del 3

Programmera i C Varför programmera i C när det finns språk som Simula och Pascal??

TDIU01 - Programmering i C++, grundkurs

Objektorienterad Programmering (TDDC77)

Lösningar till tentamen i EIT070 Datorteknik

I Skapa Hej.java och skriv programmet. I Kompilera med javac Hej.java. I Rätta fel och repetera tills du lyckas kompilera ditt program

Assemblerprogrammering för ARM del 3

Innehåll. Pekare Exempel

Innehåll. Pekare Exempel

Föreläsning 10. Pekare (Pointers)

Översikt Introduktion DST 1. Nicholas Wickström. IDE, Högskolan i Halmstad. N. Wickström

Övning från förra gången: readword

Parameteröverföring. Exempel. Exempel. Metodkropp

Per Holm Lågnivåprogrammering 2014/15 24 / 177. int och double = = 2, 147, 483, 647

Minnestilldelning (allokering) och frigörande (avallokering) av minne

Innehåll. Pekare Syntax

2 Pekare och dynamiska variabler.

CE_O2. Nios II. Subrutiner med mera.

Fortsä'ning Pekare. Ulf Assarsson. Originalslides av Viktor Kämpe

Enkla datatyper minne

Poster ( structar ) Postdeklarationer

Programmering, grundkurs, 8.0 hp HI1024, HI1900 etc., Tentamen TEN1. Måndagen den 10 januari 2011,

Variabler, värden och typer

Föreläsning 5-6 Innehåll. Exempel på program med objekt. Exempel: kvadratobjekt. Objekt. Skapa och använda objekt Skriva egna klasser

TDIU01 - Programmering i C++, grundkurs

Programmering A. Johan Eliasson

Dataminne I/O Stack 0x005D 0x3D SP low byte 0x005E 0x3E SP high byte

Föreläsning 5: Introduktion av pekare

Föreläsning 5-6 Innehåll

Stack och subrutiner Programmeringskonventionen

Mål. Datorteknik. Innehåll. Innehåll (forts) Hur ser ett program ut? Hur skapas maskinkoden?

Digital- och datorteknik

Variabler, värden och typer

Programmeringsteknik med C och Matlab

Lågnivåprogrammering. Föreläsning 2 Lågnivåprogrammering. Binära tal. En enkel modell av datorns inre

Objektorienterad Programmering (TDDC77)

Grundläggande C-programmering del 2 Pekare och Arrayer. Ulf Assarsson

Agenda. Arrayer deklaration, åtkomst Makron Flerdimensionella arrayer Initiering Strängar Funktioner och arrayer. Övningar nu och då

Funktionspekare, inledning: funktionsanropsmekanismen. Anrop via pekare

Det finns många flaggor till g++,

Grundläggande C-programmering del 2 Pekare och Arrayer. Ulf Assarsson

TDDC76 - Programmering och Datastrukturer

Institutionen för elektro- och informationsteknologi, LTH

Datorteknik. Föreläsning 3. Assembler, stack och subrutiner, programmeringskonventionen. Institutionen för elektro- och informationsteknologi, LTH

Föreläsning 6 pekare och pekare tillsammans med arrayer

TDDC77 Objektorienterad Programmering

Programmering av inbyggda system. Pekare och Arrayer. Viktor Kämpe

Datorsystem Laboration 2: Minnesmappade bussar

c a OP b Digitalteknik och Datorarkitektur 5hp ALU Design Principle 1 - Simplicity favors regularity add $15, $8, $11

Datorsystem. Tentamen

Institutionen för datavetenskap 2014/15

Lösningar till tentamen i EIT070 Datorteknik

Programmering B med Visual C

Assemblerprogrammering - fördjupning

Klassdeklaration. Metoddeklaration. Parameteröverföring

Innehåll. Resurshantering. Resource handles. Minnesallokering. Minnesallokering Exempel: allokering på stacken. 6. Resurshantering

Programmeringsteknik med C och Matlab

Maskinorienterad programmering

Miniprojekt: MEX och molekyldynamik

Programmering av inbyggda system. Pekare och Arrayer. Ulf Assarsson. Originalslides av Viktor Kämpe

Värmedistribution i plåt

Programmering i C++ EDA623 Typer. EDA623 (Föreläsning 4) HT / 33

Ulf Assarsson. Grundläggande C-programmering del 2 Pekare och Arrayer. Läromoment:

I denna laboration undersöker vi hur aritmetiska beräkningar utförs. Vi tittar på olika variabeltyper: 8-bitars, 16-bitars, 32-bitars och flyttal.

Tentamen. Datorteknik Y, TSEA28

Övningar Dag 2 En första klass

LEU240 Mikrodatorsystem

Inledande programmering med C# (1DV402) 27+15=42 1 (22)

Övning 6. Parallellport, timer

Labora&on 2 Funk&oner, if och loop övningar/uppgi:er

Föreläsning 2. Operativsystem och programmering

TDP004. Minne och pekare. Eric Elfving Institutionen för datavetenskap

Kompilering och exekvering. Föreläsning 1 Objektorienterad programmering DD1332. En kompilerbar och körbar java-kod. Kompilering och exekvering

Pekare och arrayer. Indexering och avreferering

Lite om felhantering och Exceptions Mer om variabler och parametrar Fält (eng array) och klassen ArrayList.

Programmering i C++ En manual för kursen Datavetenskaplig introduktionskurs 5p

Lösningar till tentamen i EIT070 Datorteknik

Elektroteknik MF1016 föreläsning 9 MF1017 föreläsning 7 Mikrodatorteknik

Arv: Fordonsexempel. Arv. Arv: fordonsexempel (forts) Arv: Ett exempel. En klassdefinition class A extends B {... }

Om pekare och minneshantering i C, relaterat till operativsystem och särskilt konstruktionen fork() execvp().

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Felsökning. Datatyper. Referenstyper. Metoder / funktioner

EDAA20 Programmering och databaser. Mål komprimerat se kursplanen för detaljer. Checklista. Föreläsning 1-2 Innehåll. Programmering.

Datorsystem. Tentamen

Digital- och datorteknik

Operativsystem ID2200 Tentamen TEN1 3.8 hp :00-18:00

Repetition C-programmering

Digital- och datorteknik

En kort text om programmering i C.

TDIU01 - Programmering i C++, grundkurs

Transkript:

IS1200 ösningar till exempel, övning 4, 2015 4. Maskinnära programmering i C. Förberedelser till hemlaboration 1. 4.1. Big-endian och little-endian När heltal, flyttal och adresser ska lagras i datorns minne så behövs flera bytes för varje värde. Då finns två alternativ för byte-ordningen. En möjlighet är att börja med den byte som innehåller värdets mest signifikanta bitar, och placera denna byte närmast adress 0. Övriga bytes som ingår i värdet kommer i ordning, med mindre signifikanta bitar ju längre från adress 0 man kommer. Denna byte-ordning kallas big-endian. Den andra möjligheten är att börja med den byte som innehåller värdets minst signifikanta bitar, och den ordningen kallas little-endian. Instruktionerna ldw och stw kopierar data mellan ett byte-adresserat minne och ett processorregister som har plats för 4 bytes. Här är en figur som illustrerar skillnaden mellan big-endian och little-endian för instruktionerna ldw och stw. ittle-endian medför alltså att den "första" byten, den byte som ligger närmast adress 0 i minnet, finns längst till höger i registret, i den "lilla" änden. Big-endian medför att den byte som ligger närmast adress 0 i minnet placeras längst till vänster i registret, i den "stora" änden. I vår labutrustning används little-endian byte-ordning. ösningar till övning 4, sida 1 (av 10) 2015-01-13

4.2. Alignment Det är vanligt att hårdvaran kräver att datatyper som är större än bara en enstaka byte lagras på en (start-) adress som är delbar med en lämplig 2-potens. Detta underlättar för hårdvarukonstruktören, eftersom minnet vanligtvis är uppbyggt med platser som är bredare än enstaka bytes. Ofta är minnets verkliga ordlängd 4 byte eller 8 byte. När minnet är bredare än 1 byte finns extra hårdvara för att utföra instruktionen ldb, oad Byte. Hårdvaran måste läsa ett helt minnesord, och sedan välja ut rätt byte. Påminnelse om effektivadress: anta att en processor utför oad-instruktionen ldw r8,4(r9) Innehållet i register r9 och konstanten 4 adderas. Resultatet av additionen blir den minnesadress som oad-instruktionen läser i minnet. Denna minnesadress kallas för effektivadress. Om instruktionen ldw (oad Word) används med en effektivadress som inte är jämnt delbar med 4, så ligger de 4 bytes som instruktionen ska läsa utspridda på två olika minnesord med intilliggande adresser. För att göra instruktionen ldw i detta fall skulle ännu mera extra hårdvara behövas. Den hårdvaran skulle behöva läsa båda minnesorden, välja ut rätt bytes, och sätta ihop dem till ett ord. Här är ett exempel på hur hårdvaran skulle behöva hämta två ord och sätta ihop dem för att utföra en ldw-instruktion när effektivadressen = 43. adress 40 40 41 42 43 adress 44 44 45 46 47 Nios II har inte denna extra hårdvara för att läsa två ord och sätta ihop. Därför måste effektivadressen till instruktionen ldw alltid vara jämnt delbar med 4. På samma sätt måste effektivadressen till instruktionen ldh (oad Halfword, läser 2 byte) alltid vara jämnt delbar med 2. Vissa processorer, bland annat i Sparc-serien, har instruktioner som läser/skriver 8 byte i taget, det vill säga 64 bitar. En oad-instruktion för 8 byte kan heta ldd (oad Double). 8-bytes oad och Store används för 64-bits adresser, 64-bits heltal (long long int) och 64-bits flyttal (double). I Sparc-fallet kräver processorn att effektivadressen är jämnt delbar med 8 om en oad- eller Store-instruktion ska läsa/skriva 8 byte. Detta passar förstås för minnessystem där varje plats i minnet är 8 byte stor. Mer om Nios II: hårdvaran kollar inte om adressen är jämnt delbar med 4, utan utför instruktionen och läser/skriver på fel plats i minnet. Simulatorn kollar adresserna och avbryter programmet om exempelvis ldw används med en effektivadress som inte är jämnt delbar med 4. ösningar till övning 4, sida 2 (av 10) 2015-01-13

4.3. Adressrymd (address space) och vad som finns i rymden a) Se föreläsning 5 och lab-pm för hemlab om Maskinnära programmering med C. b) Exempel på tänkbar minnesallokering: Antag att ditt program har tillgång till en adressrymd med adresser från 0 upp till 2 32-1 (om programräknaren är 32 bitar stor) vilket är 4 Gigabyte. (Operativsystemets virtuellminnessystem erbjuder varje program en känsla av att ha tillgång till ett så stort minne. Mer om virtuellt minne får Du lära dig i kurser av typen Datorteknik fortsättningskurs och Operativsystem) På adress 0 och uppåt placeras binärkoden för den översatta programkoden. Programmmets binärkod kommer att ta olika stor plats beroende på programmets storlek. På närmast högre adresser placeras de variabler som ska vara statiska dvs finnas plats för i minnet under hela exekveringen. Dessa variabler delas upp i initialized och uninitialized data. I den exekverbara filen, a.out, eller *.exe, måste finnas information om varje variabels storlek och eventuellt innehåll. För de initialiserade variablerna ska ju även finnas information om deras värde, vilket alltså tar mer plats i a.out/*.exe-filen. För de oinitierade variablerna behöver plats reserveras men det räcker med information (i a.out/*.exe-filen) om hur mycket plats (hur många bytes) som ska reserveras för dessa variabler. Programkod och initerade variabler kan buntas ihop till en enda stor binärkodsklump. Det är tänkbart/rimligt att variabler som deklareras som const (i själva verket konstanter) placeras tillsammans med programkoden och görs Read-Only. Till exempel textsträngar i formateringssatser typ printf etc. c) Programkod, initialiserade variabler samt reserverad plats för oinitierade variabler placeras alltså från adress 0 i minnet och uppåt så stor plats som behövs. Dessa statiska minnesutrymmen reserveras at compile-time. Resten av den tillgängliga minnesarean används för dynamisk minnesallokering, at execution-time, dvs för heap och stack. Heapen kan placeras direkt efter data/bss-arean och växer mot högre adresser. Stacken kan placeras i minnets högsta adresser och växa mot lägre adresser. Det är tänkbart och rimligt att förvänta sig att ett operativsystem tillsammans med hårdvara i MMU, Memory Management Unit, kan upptäcka när stack och/eller heap växer in i varandras minnesutrymme. Det är tänkbart och rimligt att förvänta sig att ett operativsystem tillsammans med hårdvara i MMU, Memory Management Unit, kan upptäcka om programräknaren pekar utanför programarea och upptäcka om programmet vid exekvering gör minnesreferenser (med OAD/STORE) till variabler inne i programarean. Kanske löses detta genom att man i den virtuella adressrymden skiljer mellan pages som hör till olika minnesområden. ösningar till övning 4, sida 3 (av 10) 2015-01-13

4.4. Värden, pekare, referenser, heltalsvariabler Skriv programrader i C som visar hur * och & används för att a) deklarera två heltalsvariabler: a och b. int a, b; # placera i.bss eller # på adress delbar med 4 a:.word 0 # ett ord = 4 bytes = 32 bitar med värdet 0 b:.word 0 # ett ord = 4 bytes = 32 bitar med värdet 0 b) initialisera heltalsvariabeln b till värdet 27 i samband med deklarationen. int a; int b=27; a:.word 0 b:.word 27 # ett ord = 4 bytes = 32 bitar med värdet 27 (dec) c) deklarera två pekarvariabler som kan peka på a och b: ptr1 och ptr2. int* ptr1; int* ptr2; /* int* ptr1, ptr2; är fel fel fel */ /* int *ptr1, *ptr2; är också OK */ ptr1:.word 0 # ett ord = 4 bytes = 32 bitar med värdet 0 ptr2:.word 0 # ett ord = 4 bytes = 32 bitar med värdet 0 d) tilldela a värdet 4711 och b värdet 47. a=4711; b= 47;.text # placera i.text arean # på adress delbar med 4 moviar8, a # r8 pekar nu på a moviar9, 4711 # r9 innehåller värdet 4711 stw r9, 0(r8) # värdet 4711 skrivs till a moviar8, b # r8 pekar nu på b moviar9, 47 # r9 innehåller nu värdet 47 stw r9, 0(r8) # värdet 47 skrivs till b e) tilldela pekarvariabeln ptr1 ett värde så att den pekar på heltalsvariabeln a. ptr1 = &a; /* utläses som ptr1 tilldelas värdet av adressen till a */.text # placera i.text arean # på adress delbar med 4 moviar8, a # adressen till a skrivs till r8 moviar9, ptr1 # r9 pekar nu på ptr1 stw r8, 0(r9) # adressen till a skrivs nu till ptr1 ösningar till övning 4, sida 4 (av 10) 2015-01-13

f) tilldela heltalsvariabeln b samma värde som a, med hjälp av ptr1. b=*ptr1; /* b tilldelas det värde som ptr1 peka på */.text # placera i.text arean # på adress delbar med 4 moviar8, ptr1 # nu pekar r8 på ptr1 moviar9, b # nu pekar r9 på b ldw r10, 0(r8) # nu innehåller r10 värdet av ptr1 som pekar på a ldw r11, 0(r10) # nu innehåller r11 värdet som ptr1 pekar på dvs a stw r11, 0(r9) # nu innehåller b det som ptr1 pekade på dvs a g) tilldela pekarvariabeln ptr2 ett värde så att den pekar på samma variabel som ptr1. ptr2 = ptr1; /* variabeln ptr2 tilldelas samma värde som variabeln ptr1 */.text # placera i.text arean # på adress delbar med 4 moviar8, ptr1 # nu pekar r8 på ptr1 moviar9, ptr2 # nu pekar r9 på ptr2 ldw r10, 0(r8) # nu finns värdet från ptr1 i r10 stw r10, 0(r9) # nu har ptr2 samma värde som ptr1 4.5. Värden, pekare, referenser, char-variabler Skriv programrader i C som visar hur * och & används i nedanstående exempel. Översätt varje exempel för hand till Nios2-assembler. Skriv alltså först C och sedan Nios-II-assembler för att: a) deklarera två globala variabler av typen char: c och d. char c, d; # placera i.bss eller # på adress delbar med 4, kanske onödigt... c:.byte 0 # 1 byte = 8 bitar med värdet 0 d:.byte 0 # 1 byte = 8 bitar med värdet 0 Blir det någon skillnad i Nios-II-assemblerkoden jämfört med motsvarande operation med heltalsvariabler? Svar JA, bara en byte per variabel och tätt packat b) initialisera variabeln d till värdet 65 i samband med deklarationen. Vad blir det för skillnad i Nios-II-assemblerkoden jämfört med motsvarande operation med heltalsvariabler? char c; char d=65; # placera i.bss eller # på adress delbar med 4 c:.byte 0 # 1 byte = 8 bitar med värdet 0 d:.byte 65 # 1 byte = 8 bitar med värdet 65 (dec) ösningar till övning 4, sida 5 (av 10) 2015-01-13

c) deklarera två globala pekarvariabler som kan peka på c och d: ptr3 och ptr4. char *ptr3, *ptr4; # placera i.bss eller # på adress delbar med 4, nödvändigt, pekare är 4 bytes ptr3:.word 0 # ett ord = 4 bytes = 32 bitar med värdet 0 ptr4:.word 0 # ett ord = 4 bytes = 32 bitar med värdet 0 Blir det någon skillnad i Nios-II-assemblerkoden jämfört med motsvarande operation med heltalsvariabler? Ingen kvalitets-skillnad mot heltal (förutom symboliska namn) d) tilldela c värdet 'M'. och tilldela d värdet 97. c = 'M'; d = 97;.txt moviar8, c # r8 pekar nu på c movi r9, 'M' # nu räcker det med movi (istf movia) stb r9, 0(r8) # ska vara stb istf stw moviar8, d # r8 pekar nu på d movi r9, 97 # misstänkt negativt?! stb r9, 0(r8) # ska vara stb istf stw Vad blir det för skillnad i Nios-II-assemblerkoden jämfört med motsvarande operation med heltalsvariabler? Se den kraftiga texten ovan. e) tilldela pekarvariabeln ptr3 ett värde så att den pekar på variabeln c. ptr3 = &c;.txt moviar8, c # nu pekar r8 på c moviar9, ptr3 # nu pekar r9 på ptr3 stw r8, 0(r9) # nu pekar ptr3 på c Blir det någon skillnad i Nios-II-assemblerkoden jämfört med motsvarande operation med heltalsvariabler? Ingen kvalitets-skillnad mot heltal (förutom symboliska namn) f) tilldela variabeln d samma värde som c, med hjälp av ptr3. d=*ptr3; /* d tilldelas det värde som ptr3 pekar på */.txt moviar8, ptr3 # nu pekar r8 på ptr3 moviar9, d # nu pekar r9 på d ldw r10, 0(r8) # nu innehåller r10 värdet av ptr3 som pekar på c ldb r11, 0(r10) # nu innehåller r11 värdet som ptr3 pekar på dvs c stb r11, 0(r9) # nu innehåller d det som ptr3 pekade på dvs c Vad blir det för skillnad i Nios-II-assemblerkoden jämfört med motsvarande operation med heltalsvariabler? Se den kraftiga texten ovan. ösningar till övning 4, sida 6 (av 10) 2015-01-13

g) tilldela pekarvariabeln ptr4 ett värde så att den pekar på samma variabel som ptr3. ptr4 = ptr3; /* variabeln ptr2 tilldelas samma värde som variabeln ptr1 */.txt moviar8, ptr3 # nu pekar r8 på ptr3 moviar9, ptr4 # nu pekar r9 på ptr4 ldw r10, 0(r8) # nu finns värdet från ptr3 i r10 stw r10, 0(r9) # nu har ptr4 samma värde som ptr3 Blir det någon skillnad i Nios-II-assemblerkoden jämfört med motsvarande operation med heltalsvariabler? Ingen kvalitets-skillnad mot heltal (förutom symboliska namn) 4.6. Funktionen memcpy Bland biblioteksrutinerna finns en som heter memcpy, med följande deklaration. void * memcpy( void * dest, const void * src, size_t len ); Ett anrop kan se ut såhär. int a[4711][4711]; int b[4711][4711]; /* här emellan finns mera kod, som bland annat initialiserar matrisen a */ (void) memcpy( &b[0][0], &a[0][0], sizeof( a ) ); a) Förklara vad en pointer to void är för något. Det är en pekare som pekar på en plats i minnet men det är odefinierat vilken typ som pekas ut. Det innebär att kompilatorn inte vet hur många bytes som eventuellt ska läsas eller skrivas på den platsen i minnet. Därför krävs av programmeraren att det görs type-cast av en void-pekare innan den kan användas för en minnesreferens. Exempel: int * ptr1 = (int *) malloc (sizeof(int)); b) Förklara de tre parametrarna till memcpy. Den första, dest, är en voidpekare som anger första byte i minnet till vilken kopiering ska ske. Den andra, src, är en voidpekare som anger första byte från vilken kopiering ska ske. Den tredje parametern anger antal bytes som ska kopieras. c) Förklara returvärdet från memcpy. Returvärdet är en voidpekare (som ska returnera det ursprungliga värdet av dst) d) Förklara operatorn sizeof(). Opeatorn sizeof() kommer (at compile-time) ta reda på storleken av a uttryckt i antal bytes. e) Förklara texten (void) vid anropet till memcpy. På returvärdet, vilke typ det än är, görs type-cast till en void för att därefter ignoreras. ösningar till övning 4, sida 7 (av 10) 2015-01-13

f) Visa hur funktionen memcpy kan översättas till assembler för Nios II. memcpy: mov r2, r4, # returnera dst-pekaren beq r6, r0, out # kolla om klart baa: ldb r12, 0(r5) # läs 1 byte addi r5, r5, 1 # öka src-pekare stb r12, 0(r4) # skriv 1 byte addi r4, r4, 1 # öka dst-pekare subi r6, r6, 1 # minska counter bgt r6, r0,baa # loopa om fler bytes kvar out: ret 4.7. Matriser Se föreläsning 5 och lab-pm för hemlab om Maskinnära programmering med C. C-kompilatorn lagrar matriser radvis. Det innebär att matriselementen alltid läggs i ordning [0][0] sedan [0][1] sedan [0][2] sedan [0][3] sedan [0][4] sedan [1][0] sedan [1][1]sedan [1][2] och så vidare. 4.8. C-version av puttime /* Declare hexasc so the compiler can do type-checking. */ int hexasc( int ); void puttime( int *tid ) { int tmp = *tid; /* Send carriage-return and line-feed to console. */ putchar( '\r' ); putchar( '\n' ); /* Send time to console. */ putchar( hexasc( tmp >> 12 ) ); putchar( hexasc( tmp >> 8 ) ); putchar( ':' ); putchar( hexasc( tmp >> 4 ) ); putchar( hexasc( tmp ) ); } ösningar till övning 4, sida 8 (av 10) 2015-01-13

4.9. Struct a) struct tiger { char namn[13]; int vikt; float fart; float lengd; }; b) struct eararea { float left; float right; }; c) struct elephant { char namn[13]; int vikt; struct eararea oronyta; }; d) Vilket resultat erhålls som returvärde från operationerna sizeof (struct elephant); troligen 13(+3) + 4 + 4 + 4 = 28 sizeof (struct tiger); troligen 13(+3) + 4 + 4 + 4 = 28 sizeof (int); troligen 4 Kommentarer: detta förutsätter att en int och en float lagras i 4 byte, samt att int och float och hela structen lagras på adresser jämnt delbara med 4. Det senare är nödvändigt för att hårdvaran i Nios II och många andra datorer ska kunna läsa en int eller float med en ldw-instruktion (och skriva med en stw-instruktion). e) En vektor, cirkus, med plats för 4 elefanter kan man deklarera med struct elephant cirkus[4]; ösningar till övning 4, sida 9 (av 10) 2015-01-13

4.10. Dynamisk minnesallokering med malloc och free Beskriv med ord eller rita en figur som illustrerar hur minne kan allokeras, avallokeras och återanvändas vid följande tänkvärda operationer i ett c-program / * 1 * / / * 2 * / / * 3 * / / * 4 * / / * 5 * / / * 6 * / /* 1 */ struct elephant * dumbo=(struct elephant *) malloc (sizeof (struct elephant)); /* 2 */ struct tiger * tiger1 = (struct tiger *) malloc (sizeof (struct tiger)); /* 3 */ free (dumbo); /* 4 */ struct tiger * tiger2 = (struct tiger *) malloc (sizeof (struct tiger)); /* 5 */ struct tiger * tiger3 = (struct tiger *) malloc (sizeof (struct tiger)); /* 6 */ free (tiger1); Figuren nedan avses illustrera rad för rad vad som sker (För att lagra en elephant reserveras 28 bytes liksom för en tiger.) /* 1 */ för dumbo allokeras 28 bytes i botten på heap /* 2 */ för tiger1 allokeras ytterligare 28 bytes på näraliggande högre adresser och troligen blir det glapp mellan dumbo och tiger1 /* 3 */ av-allokerar 28 bytes (dumbo) i botten på heap /* 4 */ för tiger2 allokera de nyss av-allokerade 28 bytes i botten på heap, reuse /* 5 */ för tiger3 allokeras 28 bytes på adresser ovanför tiger1 och troligen blir det glapp mellan tiger1 och tiger3 /* 6 */ av-allokerar tiger1 och nu blir det en lucka mellan tiger2 och tiger3 - h e a p d u m d u m b o b o t i g e r 2 t i g e r 1 t i g e r 1 t i g e r 1 t i g e r 2 t i g e r 1 t i g e r 2 + T i g e r 3 T i g e r 3 ösningar till övning 4, sida 10 (av 10) 2015-01-13