Teil 6: Strukturen und Unionen - fritzsch/Programmieren/Folien/Prog06.pdf · Kapitel 6: Strukturen...

Post on 15-Aug-2019

214 views 0 download

Transcript of Teil 6: Strukturen und Unionen - fritzsch/Programmieren/Folien/Prog06.pdf · Kapitel 6: Strukturen...

Gliederung

Strukturen

Typdefinitionen

Unionen

Dynamische Speicherverwaltung

Teil 6: Strukturen und Unionen

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.2

Strukturen

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.3

Strukturen

� Ursprung in Pascal als Datentyp record, Verbunddatentyp

� Strukturtyp in C

� kann Komponenten (Variablen) verschiedener Typen enthalten:

� Anwendung: Gruppierung logisch zusammenhängender Daten z. B. Datum, Adresse, Personendaten, geometrische Objekte, .

� Behandlung beim Lesen und Schreiben immer als als Einheit

Personal- Nachname Vorname Straße Haus- Postleit- Wohnort Gehalt nummer nummer zahl

int char[20] char[20] char[20] int int char[20] float

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.4

Strukturtyp-Definition

� frei definierter, zusammengesetzter Datentyp

� feste Anzahl von Komponenten

struct Name

{

typ1 komponentenVariable_1;

typ2 komponentenVariable_2;

. . .

typN komponentenVariable_n;

};

� der Typname ist struct Name

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.5

Strukturvariablen-Definition

� Variable eines Strukturtyps = aus Komponentenvariablen zusammengesetzte Variable

� Erstellung einer Variablen des Typs struct Name

struct Name variable;

Komponenten- variable 1

Komponenten- variable 2

Komponenten- variable n ...

Strukturvariable

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.6

Beispiel-Definition

struct Adresse

{

char strasse[20];

int hausnummer;

int postleitzahl;

char stadt[20];

};

struct Student

{

int matrikelnummer;

char name[20];

char vorname[20];

struct Adresse wohnort;

};

struct Student meyer, mueller; // 2 Studenten

struct Student semester[50]; // Feld aus 50 Studenten

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.7

Übergabe an Funktionen

� call-by-value (wie bei elementaren Datentypen int, float, etc.)

Initialisierungslisten

struct Student student1 =

{

66202,

"Meyer",

"Herbert",

{

"Schillerplatz",

20,

73730,

"Esslingen"

}

};

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.8

Zugriff auf Komponentenvariablen

student1.matrikelnummer = 716347;

struct Wort

{

char s[20];

}

struct Wort w1, w2;

char c1[20], c2[20];

strcpy(c1, "Hallo");

strcpy(w1.s, "Hallo");

c2 = c1;

w2 = w1;

strcpy(c2, c1); /* RICHTIG */

/* RICHTIG, eine Struktur ist ein L-Value */

/* FALSCH, ein Feld ist kein L-Value */

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.9

Zugriff auf Komponentenvariablen

student1.matrikelnummer = 716347;

strcpy (student1.name, "Meyer");

student1.wohnort.postleitzahl = 73733;

strcpy (student1.wohnort.stadt, "Esslingen");

printf ("%6d %5d %s\n", student1.matrikelnummer,

student1.wohnort.postleitzahl,

student1.name);

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.10

Kombination von Typ- und Variablendefinition

� ohne Strukturname/Etikett (unüblich)

struct

{

float x;

float y;

} punkt1, punkt2, punkt3;

� mit Strukturname/Etikett (üblich)

struct Koordinaten

{

float x;

float y;

} punkt1, punkt2, punkt3;

struct Koordinaten punkt4, punkt5, punkt6;

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.11

Struktur-Zuweisungen, Vergleich

� direkte Zuweisung möglich, alle Komponentenwerte der Variablen punktAwerden den jeweiligen Komponenten der Variablen punkt3 zugewiesen

struct Koordinaten punktA = {1.5, 3.0}, punktB;

punktB = punktA;

� ABER: Prüfung auf Gleichheit if (punktA == punktB) ist nicht möglich!

� Bestimmung der Größe in Bytes einer Strukturvariablen:

sizeof (struct Koordinaten)

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.12

Selektion über Zeiger

� Punktoperator . und Pfeiloperator ->

struct Koordinaten

{

float x;

float y;};

struct Koordinaten punktA = {1.5, 3.0}, *ppunkt;

ppunkt = &punktA;

� Wie greife ich auf Komponenten von punktA über den Zeiger ppunkt zu?

� Komponenten-Selektion über Zeiger auf 2 Arten möglich:

(*ppunkt).x bzw. ppunkt->x

(*ppunkt).x = 3; ppunkt->x = 3;

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.13

Zeiger und geschachtelte Strukturen

� Strukturvariablen als Komponenten

struct Vektor

{

struct Koordinaten *anfang;

struct Koordinaten *ende;};

� Zeiger vom Typ Vektor

struct Vektor vec, *pvec;

vec.anfang = &punkt2;

vec.ende = &punkt3;

pvec = &vec;

...

pvec->anfang->x bzw.

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.14

Strings in Strukturen

� String als Komponentenvariable

struct Name

{

char nachname[20];

char *vorname;

};

struct Name person1 = {"Maier", "Herbert"};

� char nachname[20]; strukturintern, String gehört zur Strukturvariablen

� char *vorname; strukturextern, (in diesem Falle konstanter String)

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.15

Typdefinition mit typedef

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.16

Was ist typedef?

� Vergabe eines neuen Namens (Alias) neuername für einen

• schon bekannten oder

• soeben definierten Datentyp

typedef bekanntertyp neuername;

� Beispiele: typedef unsigned long int UINT;

UINT a;

typedef float REAL;

REAL b;

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.17

Anwendung

� spart Schreibarbeit

� Portierbarkeit von Programmen mit maschinenabhängigen Datentypen(maschinenabhängige Datentypen treten NUR in der typedef Zeile auf)

� Beispiel: Windows-API

https://msdn.microsoft.com/en-

us/library/windows/desktop/aa383751%28v=vs.85%29.aspx

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.18

Anwendung

� Beispiel: einheitlicher Long-Integer LINT

typedef long long int LINT; // Anpassung auf LLP64-System

typedef long int LINT; // Anpassung auf LP64-System

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.19

typedef und Strukturen

struct Datum

{

short int tag;

char monat[10];

short int jahr;

};

struct Datum heute;

Empfohlene Variante

typedef struct

{

short int tag;

char monat[10];

short int jahr;

} DATUM;

DATUM heute;

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.20

Unionen

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.21

Union-Definition

� Benutzung wie Struktur

� ABER: alle Komponenten (Alternativen) beginnen bei der selben Adresse

� speichert jeweils nur eine einzige Komponente (aus Reihe von Alternativen)

� Programmierer ggf. muss verfolgen, welcher Typ momentan in der Union gespeichert ist

union Variant

{

int intAlternative;

float floatAlternative;

};

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.22

Zugriff auf Alternativen

union Variant

{

int intAlternative;

float floatAlternative;

};

int x;

union Variant vario;

� Alternative schreiben / auslesen

vario.floatAlternative = 123.0;

x = vario.intAlternative;

� Zeiger auf Union

union Variant *pVario = &vario;

x = pVario->intAlternative;

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.23

Beispiel: Prozessorregister

struct WORDREGS

{

unsigned int ax;

unsigned int bx;

unsigned int cx;

unsigned int dx;

};

struct BYTEREGS

{

unsigned char al,ah;

unsigned char bl,bh;

unsigned char cl,ch;

unsigned char dl,dh;

};

union REGS

{

struct WORDREGS w;

struct BYTEREGS b;

};

inregs.w.ax = 0x0815; /* BX Register auf Hex 0815 setzen */

inregs.b.ch = 0x1A; /* AH Register auf Hex 1A setzen */

union REGS inregs;

Dynamische Speicherverwaltung

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.26

Dynamische Speicherverwaltung

Problem: Speicherbedarf ist während verschiedenerProgrammausführungen unterschiedlich

Lösung: Variablen (insb. Arrays) maximal dimensionieren:

char eingabetext[1000];

Variable Feldgröße in lokalen Arrays nutzen (ab C99)

� Nachteile?

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.27

Statische vs. dynamische Variablen

� statische Variable (inkl. lokal, global)

int x;

Verfügbarkeit und Ablage/Speichersegment je nach Speicherklasse (auto, register, static, extern)

� Speichersegmente

Code

Daten

Heap

Stack

lokale

Variable

globale

Variable

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.28

Statische vs. dynamische Variablen

� dynamische Variable hat keinen Bezeichner, keine Vereinbarung

� Anlegen erfolgt bei Bedarf auf dem Heap

� Zugriff durch Zeiger auf Bereich im Heap

Daten

Stack

Heap

stat. Pointer-Variable

stat. Pointer-Variable

dyn. Variable

dyn. Variable

Code

Daten

Heap

Stack

lokale

Variable

globale

Variable

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.29

Dynamische Speicherverwaltung

Problem: Speicherbedarf ist während verschiedenerProgrammausführungen unterschiedlich

Lösung bisher: Variablen (insb. Arrays) maximal dimensionieren � Nachteil: "verschenkter" Speicher

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.30

Dynamische Speicherverwaltung

Problem: Speicherbedarf ist während verschiedenerProgrammausführungen unterschiedlich

Lösung bisher: Variablen (insb. Arrays) maximal dimensionieren � Nachteil: "verschenkter" Speicher

stdlib.h bietet Funktionen zum Speicheranforderung und -freigabe:

void* malloc(int Groesse);

void* calloc(int AnzahlElemente, int ElementGroesse);

void* realloc(void *memBlock, int Groesse);

void free(void *memBlock);

Lösung neu: Speicherbedarf dynamisch, d.h. zur Programmlaufzeitfestlegen

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.31

Speicherreservierung mit malloc()

#include <stdio.h>

#include <stdlib.h>

int main()

{

int *pMem;

pMem = malloc(sizeof (int));

if (p != NULL)

{

*pMem = 3;

printf("pointer auf int-Zahl mit Wert: %d\n", *pMem);

free(pMem);

}

else

printf("Speicheranforderung fehlgeschlagen.\n");

return 0;

}

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.32

Speicherreservierung mit realloc() I

#include <stdio.h>

#include <stdlib.h>

int main()

{

int *pMem;

pMem = malloc(sizeof (int));

if (pMem == NULL)

{

printf("Speicheranforderung fehlgeschlagen.\n");

return -1;

}

*pMem = 3;

printf("Nach malloc():\n");

printf("pointer auf int-Zahl mit Wert: %d\n", *pMem);

...

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.33

Speicherreservierung mit realloc() II

...

pMem = realloc ((void *)pMem, 2 * (sizeof(int)));

if (pMem == NULL)

{

printf ("Speicheranforderung fehlgeschlagen.\n");

return -1;

}

pMem[0] = 4;

pMem[1] = 6;

printf("Nach realloc():\n");

printf("1. Element von pMem hat den Wert: %d\n", pMem[0]);

printf("2. Element von pMem hat den Wert: %d\n", pMem[1]);

free(pMem);

return 0;

}

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.34

Speicherreservierung für ein Feld

#include <stdio.h>

#include <stdlib.h>

int main()

{

int *pArray = NULL;

int i, anzahl = 0;

printf "Geben Sie die Anzahl der Feld-Elemente ein: ");

scanf("%d", &anzahl);

pArray = malloc(anzahl * sizeof(int));

if (pArray == NULL)

return -1;

// Nutzung des reservierten Speicherbereichs

for (i = 0; i < anzahl; i++)

pArray[i] = i * i;

...

free(pArray);

return 0;

}

Kapitel 6: Strukturen und Unionen

Strukturen Typdefinitionen Unionen Dynamische Speicherverwaltung

6.35

malloc & free: Typische Fehler

Fehler Folge

1) kein Speicher mehr frei2) Freigabe einer falschen Adresse u.U. Absturz3) Freigabe bereits freigegeben Speichers u.U. Absturz4) Freigabe eines regulären Feldes /

einer regulären Variablen mit free() u.U. Absturz5) Freigabe eines nicht-initialisierten Speichers u.U. Absturz6) Zugriff auf ungültigen Speicher vor der

Speicheranforderung u.U. Absturz7) Zugriff auf bereits freigegebenen Speicher u.U. Absturz8) Zugriff auf Speicher mit ungültigen Indizes u.U. Absturz9) Verlust des Speichers durch Überschreiben

des Zeigers "memory leak"10) Verlust des Zeigers durch Rücksprung aus

einer Funktion "memory leak"11) Verlust des Zeigers bei Rückgabe

(return-value verworfen) "memory leak"