Sie sind auf Seite 1von 18

7.

8 Zeiger auf Funktionen

Eine Funktion ist keine Variable, aber man kann Zeiger auf Funktionen

• definieren
• zuweisen
• in Vektoren eintragen
• an Funktionen übergeben
• als Resultat von Funktionen zurückgeben

Dereferenzierung des Zeigers ruft die entsprechende Funktion auf.

 Möglichkeit: Entscheidung, welche Funktion aufgerufen wird, erst zur Laufzeit


 Möglichkeit: Übergabe von Funktionen an andere Funktionen (über Zeiger)

111

Vereinbarung: int (*ptr) (char);

ptr ist ein Zeiger auf eine Funktion mit dem


• Übergabeparameter vom Typ char und dem
• Rückgabewert vom Typ int

Zuweisung einer Adresse einer bekannten Funktion desselben Typs:

ptr = funktionsname;

oder

ptr = &funktionsname;

Aufruf einer Funktion (klassisch) Aufruf einer Funktion (Zeiger)

int main () int main ()


{ {
...... ....
int a; ptr = funktionsname;
a = funktionsname ('A'); ....
...... int a;
} a = (*ptr)('A');
....
}

112
Anwendungsbeispiel:

Aufruf einer Funktion, die die Nullstelle einer anderen Funktion berechnet

// x1, x2 = Intervallgrenzen

113

Anwendungsbeispiel:
Windows-Funktionsweise mit „Callback“-Funktionen

114
7.9 (Weitere) komplexe Deklarationen

double *x[100];

x ist kein Zeiger auf einen Vektor mit 100 Elementen vom Typ double, sondern
ein Vektor mit 100 Elementen vom Typ Zeiger auf double !

Der Operator [ ] hat eine höhere Priorität als der Operator *

double (*y)[100];

y ist ein Zeiger auf einen Vektor mit 100 Elementen vom Typ double.

int (*z)();

z ist ein Zeiger auf eine Funktion

115

char* (*f[10])(int, int (*f1)(long, long));

?????????? 

int (*f1)(long, long);

f1 ist ein Zeiger auf eine Funktion mit zwei Parametern vom Typ long und
dem Rückgabewert vom Typ int.

char* (*f[10]) (...);

f ist ein Feld mit 10 Elementen vom Typ Zeiger auf Funktion
mit den Parametern … und dem Rückgabetyp Zeiger auf char.


char* (*f[10])(int, int (*f1)(long, long));

f ist ein Feld mit 10 Elementen vom Typ Zeiger auf Funktion mit den Parametern
vom Typ int und vom Typ Zeiger auf Funktion mit zwei Parametern vom Typ long
und dem Rückgabewert int. Der Rückgabewert der Funktionen im Feld f ist vom Typ
Zeiger auf char.
116
7.10 Zeiger und typedef

typedef alterName neuerName;

typedef bei Variablen

typedef double Gleitkommazahl;


Gleitkommazahl Zahl;
Zahl = 10.7;

typedef bei Zeigern: …

typedef int* TP_int; // Zeiger auf int-Variablen


TP_int p_int; // entspricht int* p_int
TP_int x, y; // jetzt eindeutig !

typedef bei Arrays: …

typedef char Name[20];


Name meiner; // entspricht char meiner[20];

117

8. Benutzerdefinierte Datenstrukturen
8.1 Struktur (struct)

Eine Struktur ist ein „Container“, der verschiedene Datenelemente


unterschiedlichen Typs zusammenfassen kann.

struct Name {typ Element1; typ Element2; ...};

struct Punkt {int x; int y;};


struct Komplex {double re; double im;};

Definition von entsprechenden Variablen

struct Punkt {int x; int y;} p1, p2;


struct Punkt p3, p4; // weitere...

Definition von Strukturvariablen ohne Etikett:

struct {int x; int y;} p5, p6;

nur sinnvoll, wenn keine weiteren Variablen gleichen Typs folgen sollen

118
Zugriff auf Komponenten einer Struktur: Der Punktoperator

struct Punkt {int x; int y;} p1;


p1.x = 25;
p1.y = 300;

Zeiger auf Strukturen

struct Komplex {double re; double im;}; // Def.d. Struktur


struct Komplex x; // Variable x vom Typ Komplex

struct Komplex* px = &x; // Pointer px auf x vom Typ Komplex

(*px).re = 1.1; // == x.re=1.1;


(*px).im = 2.2; // == x.im=2.2;

Der Pfeiloperator
px->re = 1.1; // == x.re=1.1;
px->im = 2.2; // == y.im=2.2;

119

Mögliche Syntax bei gleichen / verschiedenen Datentypen


struct Punkt {int x; int y;}; // Def. neuer Datentyp
// oder...
struct Punkt {int x, y;};

struct Punkt p1; // Variable vom Typ struct Punkt

struct Pixel {long x, y;


short R, G, B;}; // Def. neuer Datentyp

typedef bei Strukturen


typedef struct {int x; int y;} Punkt; // Def. neuer Datentyp

Punkt p1; // Variable vom Typ Punkt

120
typedef struct tagBITMAP {
LONG bmType;
LONG bmWidth;
LONG bmHeight;
LONG bmWidthBytes;
typedef unsigned short WORD; WORD bmPlanes;
WORD bmBitsPixel;
typedef void* LPVOID; LPVOID bmBits;
} BITMAP, *PBITMAP;
Windef.h

121

Typengleichheit und Zuweisung von Strukturen als Ganzes

typedef struct {double x; double y;} Punkt;

Punkt p1 = {1.234, 5.678}; // Variable, Initialisierung


Punkt p2 = p1; // Initialisierung als Ganzes
Punkt p3;

p3 = p1; // Zuweisung als Ganzes

Vorsicht bei Zuweisung als Ganzes, wenn Struktur Zeiger beinhaltet !!

typedef struct {
int Breite, Hoehe;
short BytesProPixel;
...
char *Daten;
} Bild;

Bild Bild1, Bild2;


... // Bild1 laden o.ä.
Bild2 = Bild1; // Bild1.Daten und Bild2.Daten zeigen nun
// auf selben Speicherbereich !!
122
Typen sind verschieden („nicht konform“), wenn Sie nicht die gleiche Wurzel haben.

typedef struct {double x; double y;} Punkt1;


typedef struct {double x; double y;} Punkt2;

Punkt1 a = {1.23, 4.56};


Punkt2 b;

b = a; //Fehler, da a und b von verschiedenen Typen sind.

Typen sind konform, wenn Sie die gleiche Wurzel haben.

typedef struct {double x; double y;} Punkt1;


typedef Punkt1 Punkt2;

Punkt1 a = {1.23, 4.56};


Punkt2 b;

b = a; //OK, da die Typen konform sind.

123

Geschachtelte Strukturen

typedef struct {double x, y;} Punkt;


typedef struct {int t, m, y;} date;

struct messwert { char Name[20];


date Datum;
Punkt Wert;}; // Definition einer neuen Struktur

struct messwert X = { {"1. Messung"},


{13, 11, 2006},
{0.0, 1.1} }; // Initialisierung

124
Vektor, dessen Elemente Strukturen sind

typedef struct {double x, y;} Punkt;


Punkt vektor[3] = { {0.0, 1.1},
{2.2, 3.3},
{4.4, 5.5} };

double ErgX, ErgY;

ErgX = vektor[1].x; // Zugriff mit Punktoperator


ErgY = vektor[1].y;

punkt* ptr = vektor; // Zugriff mit Pointer auf Punkt


// oder
punkt* ptr = &vektor[0];

ErgX = (*ptr).x;
ErgY = (*ptr).y;

ptr->x = 2.2;
ptr->y = 3.3;

125

Rekursive Strukturen

struct knoten { // der Knoten eines Baumes:


char *word; // zeigt z.B. auf den Text
struct knoten *links; // linker Nachkomme
struct knoten *rechts; // rechter Nachkomme
};

Eine Struktur darf nicht sich selbst enthalten.


Elemente gleichen Typs schon.

126
8.2 Union

= Struktur mit alternativen Datentypen (zu unterschiedlichen Zeiten!)

Alle Alternativen beginnen bei derselben Adresse.

Es wird Speicherplatz für die größte Alternative reserviert.

union vario { int intnum;


long longnum;
double doublenum;} varioname;

Zugriff und Zuweisung wie bei struct

union vario a;
int x = 123;
double y = 1.234;

a.intnum = x; // Speicherung einer int-Variablen


a.doublenum = y; // Speicherung einer double-Variablen
// alternativ !!

127

Ein Beispiel aus der Windows-Programmierung:

128
129

8.3 Bitfelder

Anwendung: Sammlung mehrerer Ja / Nein-Angaben in einer Variablen.


„Flags“

Definition über „Bitmasken“  Werte = Zweierpotenzen

// Beispiel
#define KEYWORD 01
#define EXTERNAL 02
#define STATIC 04

int flags = KEYWORD;


...
flags |= EXTERNAL | STATIC; // setzt die zwei Flags
flags &= ~(EXTERNAL | STATIC); // löscht sie
...
if ((flags &(EXTERNAL | STATIC)) == 0) ... // testet, ob gelöscht

130
Beispiel aus der (Windows-)Praxis

131

132
133

DWORD = 32bit unsigned integer

134
135

136
9. Speicherverwaltung
9.1 Speicher reservieren

#include "stdlib.h"

void *malloc (size_t size);

size Größe des angeforderten Speicherbereichs in Bytes

*malloc (memory allocation) gibt einen Zeiger auf den Speicherplatz zurück.
Typ des Zeigers: Pointer auf void

Nicht genügend Speicherplatz vorhanden  Rückgabe NULL

#include "stdlib.h"

int* ptr;
if (ptr = (int*) malloc (sizeof(int)) != NULL);
{
*ptr = 123;
}
else
printf ("Nicht genügend Speicherplatz!");

137

Reservierung von Speicherplatz für 3 Integervariablen  entspricht Vektor

#include "stdlib.h"

int* ptr;
int y;

if (ptr = (int*) malloc (3*sizeof(int)) != NULL);


{
*ptr = 123; // ptr[0] = 123;
ptr++;
*ptr = 100; // ptr[1] = 100;
ptr++;
*ptr = 200; // ptr[2] = 200;
}
else
printf ("Nicht genügend Speicherplatz!");

138
#include "stdlib.h"

void *calloc (size_t num, size_t size);

num Anzahl der benötigten Variablen

size Größe der Variablen in Bytes

*calloc gibt einen Zeiger auf den Speicherplatz zurück und setzt Inhalte auf 0.
Typ des Zeigers: Pointer auf void

Nicht genügend Speicherplatz vorhanden  Rückgabe NULL

#include "stdlib.h"

int* ptr;
if (ptr = (int*) calloc (3, sizeof(int)) != NULL);
printf ("Pointer zeigt auf 3 int");
else
printf ("Nicht genügend Speicherplatz!");

139

9.2 Speicherplatz freigeben

#include "stdlib.h"

int* ptr;
if (ptr = (int*) calloc (3, sizeof(int)) != NULL);
printf ("Pointer zeigt auf 3 int");
else
printf ("Nicht genügend Speicherplatz!");

free (ptr);

140
9.3 Werte- und Zeigersemantik

int a, b;
Wertesemantik:
a = 100; Statische Variable
b = a; • Variablentyp und Variablenname
... • Zugriff über Variablenname
• Gültigkeit durch statische Struktur des Programms festgelegt

int *a, *b;


a = (int*) malloc (sizeof(int));
b = (int*) malloc (sizeof(int));

*a = 100;
Zeigersemantik: *b = *a;
Dynamische Variable ...
free (a);
• keine Variablenvereinbarung free (b);
• kein Variablenname
• Zugriff NUR über Pointer
• werden zur Laufzeit in einem Speicherbereich (Heap) angelegt und können wieder
gelöscht werden (Speicherplatzfreigabe)
• Pointer auf die dynamische Variable ist i.d.R. eine statische Variable

141

9.4 Doppel-Zeiger

Fall 1:
Wir wollen uns 12 Zahlen merken

int a [12];

4 18 66 2 101 7 9 65 56 47 0 22

a a[0]......a[2]...................................................a[11]

*a......*(a+2)...............................................*a+11

142
9.4 Doppel-Zeiger

Fall 2:
Wir wollen uns n Zahlen merken

int n; // Anzahl der Zahlen


int* a; // Das „Array“

n = .... ;
a = (int*) malloc (n * sizeof (int));

4 18 66 2 101 ...

a a[0]......a[2]...............................a[n-1]

*a......*(a+2)................

143

9.4 Doppel-Zeiger

Fall 3:
Wir wollen uns k Zahlenreihen merken, jede soll ihre eigene Länge n [ i ] haben.

 Wir müssen uns erst einmal auch noch die k Längen merken.

int k; // Anzahl der Reihen


int i; // Zählindex
int* n; // „Array“ für die Längen

k = .... ;
n = (int*) malloc (k * sizeof (int));
for (i = 0; i < k; i++)
n[i] = ...;

5 4 7 5 10 ...

n n[0]......n[2]...............................n[k-1]

*n......*(n+2)................

144
9.4 Doppel-Zeiger

 Dann: Das Array für die Zeiger auf die k Zahlenreihen

int k; // Anzahl der Reihen


int i; // Zählindex
int* n; // „Array“ für die Längen
int** a; // „Array“ für die Zeilen

k = .... ;
n = (int*) malloc (k * sizeof (int));
for (i = 0; i < k; i++)
n[i] = ...;

a = (int**) malloc (k * sizeof (int*));

a[0]

a
a[2]
.
.
.
145

9.4 Doppel-Zeiger

 Schließlich: Die k Arrays für die Zahlenreihen


int k; // Anzahl der Reihen
int i; // Zählindex
int* n; // „Array“ für die Längen
int** a; // „Array“ für die Zeilen

k = .... ;
a[2][4] = 543;
n = (int*) malloc (k * sizeof (int)); *(a[2]+4) = 543;
for (i = 0; i < k; i++) *(*(a+2)+4) = 543;
n[i] = ...;

a = (int**) malloc (k * sizeof (int*));

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


a[i] = (int*) malloc (n[i] * sizeof (int));

a[0] 4 18 66 2 101 (n[0] = 5)


7 9 65 56 (n[1] = 4)
a
47 0 22 7 543 1 12 (n[2] = 7)
a[2]
. . .
. . .
. . .
146

Das könnte Ihnen auch gefallen