Einführung in die Programmierung - Hochschule Niederrhein
Einführung in die Programmierung - Hochschule Niederrhein
Einführung in die Programmierung - Hochschule Niederrhein
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
ma<strong>in</strong><br />
ma<strong>in</strong><br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong><br />
Def<strong>in</strong>ition nach ANSI C:<br />
Bachelor of Science<br />
Prof. Dr. Rethmann<br />
Fachbereich Elektrotechnik und Informatik<br />
<strong>Hochschule</strong> Niederrhe<strong>in</strong><br />
WS 2009/10<br />
<strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char *argv[]) {<br />
....<br />
return 0;<br />
}<br />
Zeichenfolgen als Parameter übergeben:<br />
argc (argument count): Anzahl der beim Aufruf angegebenen<br />
Zeichenfolgen <strong>in</strong>kl. Programmname<br />
argv (argument vector): Vektor von Zeigern auf <strong>die</strong><br />
angegebenen Zeichenfolgen<br />
argv[0] = Programmname<br />
Rückgabewert 0: erfolgreich ausgeführtes Programm<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> <strong>die</strong> ma<strong>in</strong>-Funktion 3 / 41<br />
üblich: Str<strong>in</strong>g-Array zur Abfrage von Umgebungsvariablen.<br />
#<strong>in</strong>clude <br />
void ma<strong>in</strong>(<strong>in</strong>t argc, char *argv[], char *env[]) {<br />
<strong>in</strong>t i;<br />
}<br />
for (i = 0; env[i] != NULL; i++)<br />
pr<strong>in</strong>tf("Variable %d = %s\n", i, env[i]);<br />
Erzeugt beim Aufruf unter L<strong>in</strong>ux bspw. <strong>die</strong> Ausgabe:<br />
Variable 0 = TERM=xterm<br />
Variable 1 = SHELL=/b<strong>in</strong>/bash<br />
Variable 2 = PAGER=/usr/b<strong>in</strong>/less<br />
Variable 3 = LANG=de_DE.UTF-8<br />
...<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> <strong>die</strong> ma<strong>in</strong>-Funktion 5 / 41<br />
Übersicht<br />
<strong>die</strong> ma<strong>in</strong>-Funktion<br />
Speicherverwaltung<br />
Rekursive Funktionen<br />
Gültigkeitsbereiche<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Speicherverwaltung 7 / 41<br />
Übersicht<br />
ma<strong>in</strong><br />
<strong>die</strong> ma<strong>in</strong>-Funktion<br />
Speicherverwaltung<br />
Rekursive Funktionen<br />
Gültigkeitsbereiche<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> <strong>die</strong> ma<strong>in</strong>-Funktion 2 / 41<br />
#<strong>in</strong>clude <br />
void ma<strong>in</strong>(<strong>in</strong>t argc, char *argv[]) {<br />
<strong>in</strong>t i;<br />
}<br />
ma<strong>in</strong><br />
for (i = 0; i < argc; i++)<br />
pr<strong>in</strong>tf("Parameter %d = %s\n", i, argv[i]);<br />
Wird das Programm als arg.c gespeichert und mit arg e<strong>in</strong>s 2<br />
drei ausgeführt, so wird folgende Ausgabe erzeugt:<br />
Parameter 0 = arg<br />
Parameter 1 = e<strong>in</strong>s<br />
Parameter 2 = 2<br />
Parameter 3 = drei<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> <strong>die</strong> ma<strong>in</strong>-Funktion 4 / 41<br />
Umwandeln der Programmparameter: sscanf(char *s, ...)<br />
äquivalent zu scanf, aber E<strong>in</strong>gabezeichen stammen aus der<br />
Zeichenkette s.<br />
Beispiel:<br />
Rückgabewert: Anzahl der umgewandelten E<strong>in</strong>gaben.<br />
<strong>in</strong>t i, n, p;<br />
for (i = 0; i < argc; errno = 0, i++) {<br />
p = sscanf(argv[i], "%d", &n);<br />
if (p == 0)<br />
pr<strong>in</strong>tf("failed to convert %s\n", argv[i]);<br />
else if (errno == ERANGE)<br />
pr<strong>in</strong>tf("%s is out of range\n", argv[i]);<br />
else pr<strong>in</strong>tf("%d: value %d\n", i, n);<br />
}<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> <strong>die</strong> ma<strong>in</strong>-Funktion 6 / 41<br />
Speicherverwaltung<br />
Der von e<strong>in</strong>em C-Programm während se<strong>in</strong>er Ausführung belegte<br />
Speicher ist <strong>in</strong> vier Bereiche aufgeteilt:<br />
Code-Segment: enthält das übersetzte Programm, also <strong>die</strong><br />
auszuführenden Masch<strong>in</strong>enbefehle.<br />
Statische Daten: während des gesamten Lebenszyklus<br />
verfügbare Daten wie globale Variablen oder statische, lokale<br />
Variablen.<br />
Heap: dynamisch allozierter Speicher (malloc)<br />
Stack: Informationen über Funktionsaufrufe<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Speicherverwaltung 8 / 41
Speicherverwaltung<br />
Für <strong>die</strong> lokalen Variablen und Argumente e<strong>in</strong>er Funktion wird erst<br />
beim Aufruf der Funktion Speicherplatz reserviert.<br />
Nach Beenden der Funktion wird der Speicherplatz wieder<br />
freigegeben.<br />
ma<strong>in</strong><br />
SP<br />
fkt1<br />
ma<strong>in</strong><br />
SP<br />
fkt2<br />
fkt1<br />
ma<strong>in</strong><br />
SP<br />
fkt1<br />
ma<strong>in</strong><br />
E<strong>in</strong> CPU-Register (SP: Stack Po<strong>in</strong>ter) enthält <strong>die</strong> Adresse des<br />
nächsten freien Speicherplatzes.<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Speicherverwaltung 9 / 41<br />
Speicherverwaltung<br />
Vorsicht: Zeiger auf lokale Variablen als Rückgabewert e<strong>in</strong>er<br />
Funktion liefern ke<strong>in</strong>en def<strong>in</strong>ierten Wert!<br />
char* <strong>in</strong>tToStr<strong>in</strong>g(<strong>in</strong>t a) {<br />
char s[10];<br />
<strong>in</strong>t i, t;<br />
}<br />
for (t = 1; t < a; t *= 10)<br />
;<br />
for (t /= 10, i = 0; t > 0; t/= 10, i++)<br />
s[i] = (a / t) % 10 + ’0’;<br />
s[i] = ’\0’;<br />
return s;<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Speicherverwaltung 11 / 41<br />
Übersicht<br />
<strong>die</strong> ma<strong>in</strong>-Funktion<br />
Speicherverwaltung<br />
Rekursive Funktionen<br />
Gültigkeitsbereiche<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Rekursive Funktionen 13 / 41<br />
Fakultät – C-Code<br />
#<strong>in</strong>clude <br />
<strong>in</strong>t fact(<strong>in</strong>t n) {<br />
if (n max)<br />
max = a[i];<br />
}<br />
res[0] = max;<br />
res[1] = m<strong>in</strong>;<br />
return res;<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Speicherverwaltung 12 / 41<br />
Rekursive Funktionen<br />
Rekursion <strong>in</strong> der Mathematik:<br />
B<strong>in</strong>omialkoeffizienten:<br />
<br />
n n − 1 n − 1<br />
= + mit<br />
k k − 1 k<br />
Fibonacci-Zahlen:<br />
<br />
n<br />
= 1 und<br />
n<br />
Fn = Fn−1 + Fn−2 mit F0 = 0 und F1 = 1<br />
<br />
n<br />
= 1<br />
0<br />
Determ<strong>in</strong>ante: Die Adjunkte Aik ist <strong>die</strong> Determ<strong>in</strong>ante<br />
(n − 1)ter Ordnung, <strong>die</strong> durch Streichen der i-ten Zeile und<br />
k-ten Spalte, multipliziert mit (−1) i+k entsteht.<br />
Entwickeln nach der i-ten Zeile:<br />
n<br />
D(aij) =<br />
k=1<br />
aikAik<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Rekursive Funktionen 14 / 41<br />
Fakultät – Programmablauf<br />
Aufrufe Rückgabe<br />
fact(4)<br />
= 4 * fact(3)<br />
fact(3)<br />
= 3 * fact(2)<br />
= 3 * 2 = 6<br />
fact(2)<br />
= 2 * fact(1) = 2 * 1 = 2<br />
fact(1) = 1<br />
= 4 * 6 = 24<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Rekursive Funktionen 16 / 41
B<strong>in</strong>omialkoeffizienten – C-Code<br />
#<strong>in</strong>clude <br />
<strong>in</strong>t b<strong>in</strong>(<strong>in</strong>t n, <strong>in</strong>t k) {<br />
if (n < k || k < 0)<br />
return -1;<br />
}<br />
if (k == 0 || k == n)<br />
return 1;<br />
return b<strong>in</strong>(n-1, k-1) + b<strong>in</strong>(n-1, k);<br />
void ma<strong>in</strong>() {<br />
pr<strong>in</strong>tf("b<strong>in</strong>(%d,%d) = %d\n", 7, 3, b<strong>in</strong>(7, 3));<br />
}<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Rekursive Funktionen 17 / 41<br />
B<strong>in</strong>omialkoeffizienten – Speicherverwaltung<br />
n = 4<br />
k = 1<br />
b<strong>in</strong> = ?<br />
n = 4<br />
k = 1<br />
b<strong>in</strong> = ?<br />
n = 3<br />
k = 0<br />
b<strong>in</strong> = 1<br />
n = 4 n = 4<br />
k = 1 k = 1<br />
b<strong>in</strong> = 1<br />
b<strong>in</strong> = 1<br />
n = 3<br />
k = 1<br />
b<strong>in</strong> = ?<br />
n = 4<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 3<br />
k = 1<br />
b<strong>in</strong> = ?<br />
n = 2<br />
k = 0<br />
b<strong>in</strong> = 1<br />
n = 4<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 3<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 4 n = 4<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 3<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 2<br />
k = 1<br />
b<strong>in</strong> = ?<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 3<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 2<br />
k = 1<br />
b<strong>in</strong> = ?<br />
n = 1<br />
k = 0<br />
b<strong>in</strong> = 1<br />
n = 4 n = 4<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 3<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 2<br />
k = 1<br />
b<strong>in</strong> = 1<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 3<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 2<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 1<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 4 n = 4<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 3<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 2<br />
k = 1<br />
b<strong>in</strong> = 2<br />
k = 1<br />
b<strong>in</strong> = 1<br />
n = 3<br />
k = 1<br />
b<strong>in</strong> = 3<br />
b<strong>in</strong> = 4<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Rekursive Funktionen 19 / 41<br />
Umwandeln <strong>in</strong> B<strong>in</strong>ärdarstellung<br />
C-Code:<br />
#<strong>in</strong>clude <br />
void <strong>in</strong>tToB<strong>in</strong>(<strong>in</strong>t n) {<br />
if (n < 2) {<br />
pr<strong>in</strong>tf("%1d", n);<br />
return;<br />
}<br />
}<br />
<strong>in</strong>tToB<strong>in</strong>(n / 2);<br />
pr<strong>in</strong>tf("%1d", n % 2);<br />
void ma<strong>in</strong>(void) {<br />
<strong>in</strong>tToB<strong>in</strong>(11);<br />
}<br />
Ablauf:<br />
<strong>in</strong>tToB<strong>in</strong>(n)<br />
11<br />
11<br />
5<br />
5<br />
2<br />
2<br />
1<br />
n = 4<br />
k = 1<br />
Ausgabe<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Rekursive Funktionen 21 / 41<br />
Rekursion und Mathematik<br />
Beispiel:<br />
n<br />
i =<br />
i=1<br />
n · (n + 1)<br />
2<br />
Induktionsanfang für n = 1: −→ Rekursionsende<br />
1<br />
i = 1 ! =<br />
i=1<br />
1 · 2<br />
2<br />
= 1<br />
Induktionsschluss n ❀ n + 1: −→ rekursiver Aufruf<br />
n+1<br />
i =<br />
i=1<br />
n<br />
i + (n + 1)<br />
i=1<br />
I.A. n · (n + 1)<br />
= + (n + 1)<br />
2<br />
= (n + 1) · (n + 2)<br />
2<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Rekursive Funktionen 23 / 41<br />
1<br />
0<br />
1<br />
1<br />
B<strong>in</strong>omialkoeffizienten – Programmablauf<br />
(4, 1)<br />
+<br />
(3, 0)<br />
(2, 0)<br />
(1, 0)<br />
(3, 1)<br />
+<br />
(2, 1)<br />
+<br />
(1, 1)<br />
(5, 2)<br />
+<br />
(1, 0)<br />
(3, 1)<br />
+<br />
(2, 0) (2, 1)<br />
+<br />
(1, 1)<br />
(4, 2)<br />
+<br />
(3, 2)<br />
+<br />
(2, 1)<br />
+<br />
(1, 0)<br />
(2, 2)<br />
(1, 1)<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Rekursive Funktionen 18 / 41<br />
Quersumme<br />
#<strong>in</strong>clude <br />
<strong>in</strong>t qsum(unsigned <strong>in</strong>t zahl) {<br />
<strong>in</strong>t ziffer;<br />
}<br />
if (zahl < 10)<br />
return zahl;<br />
ziffer = zahl % 10;<br />
return ziffer + qsum(zahl / 10);<br />
void ma<strong>in</strong>(void) {<br />
unsigned <strong>in</strong>t i;<br />
}<br />
for (i = 731; i < 750; i++)<br />
pr<strong>in</strong>tf("Quersumme(%d)= %d\n", i, qsum(i));<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Rekursive Funktionen 20 / 41<br />
Rekursion und Mathematik<br />
Rekursion kennen wir auch an anderer Stelle <strong>in</strong> der Mathematik:<br />
Beweis durch vollständige Induktion<br />
Beispiel:<br />
#<strong>in</strong>clude <br />
<strong>in</strong>t sum(unsigned <strong>in</strong>t n) {<br />
if (n == 1)<br />
return n;<br />
return n + sum(n-1);<br />
}<br />
void ma<strong>in</strong>(void) {<br />
pr<strong>in</strong>tf("Summe 1+...+10 = %d\n", sum(10));<br />
}<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Rekursive Funktionen 22 / 41<br />
Übersicht<br />
<strong>die</strong> ma<strong>in</strong>-Funktion<br />
Speicherverwaltung<br />
Rekursive Funktionen<br />
Gültigkeitsbereiche<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 24 / 41
Gültigkeitsbereich von Bezeichnern<br />
Gültigkeitsbereich (scope): Der Teil des Programms, wo e<strong>in</strong><br />
Bezeichner benutzt werden kann.<br />
Die Bedeutung e<strong>in</strong>er Deklaration ist abhängig von deren Stelle im<br />
C-Code. Mögliche Stellen für Deklarationen:<br />
außerhalb von Funktionen: globale Variablen<br />
im Funktionskopf: formale Parameter e<strong>in</strong>er Funktion<br />
<strong>in</strong>nerhalb e<strong>in</strong>es Blocks: lokale Variablen<br />
Funktionen können nur außerhalb von Funktionen deklariert<br />
werden.<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 25 / 41<br />
Gültigkeitsbereich von Bezeichnern<br />
typedef struct node {<br />
struct node *pred, *succ;<br />
<strong>in</strong>t value;<br />
} node_t;<br />
typedef struct list {<br />
node_t *first, *last;<br />
<strong>in</strong>t size;<br />
} list_t;<br />
list_t * create(void);<br />
void enqueue(list_t *l, <strong>in</strong>t val);<br />
<strong>in</strong>t dequeue(list_t *l);<br />
char isEmpty(list_t *l);<br />
liste.h<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 27 / 41<br />
Gültigkeitsbereich von Bezeichnern<br />
void enqueue(list_t *l, <strong>in</strong>t val) {<br />
node_t *neu;<br />
node_t *p = l->last->pred;<br />
}<br />
neu = (node_t *) malloc(sizeof(node_t));<br />
neu->value = val;<br />
neu->succ = l->last;<br />
neu->pred = p;<br />
p->succ = neu;<br />
l->last->pred = neu;<br />
l->size += 1;<br />
char isEmpty(list_t *l) {<br />
return l->size == 0;<br />
}<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 29 / 41<br />
Gültigkeitsbereich von Bezeichnern<br />
#<strong>in</strong>clude <br />
#<strong>in</strong>clude "liste.h"<br />
<strong>in</strong>t ma<strong>in</strong>(void) {<br />
<strong>in</strong>t i;<br />
list_t *list;<br />
}<br />
list = create();<br />
for (i = 3; i < 20; i++)<br />
enqueue(list, i);<br />
while (!isEmpty(list))<br />
pr<strong>in</strong>tf("%d\n", dequeue(list));<br />
return 0;<br />
haupt.c<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 31 / 41<br />
Gültigkeitsbereich von Bezeichnern<br />
Module: C-Quellcode auf mehrere Dateien aufteilen:<br />
e<strong>in</strong>e Datei enthält Vere<strong>in</strong>barungen und/oder Funktionen<br />
nur e<strong>in</strong>e Datei darf <strong>die</strong> Funktion ma<strong>in</strong> enthalten<br />
Beispiel: Liste<br />
liste.h: enthält <strong>die</strong> Datenstruktur und <strong>die</strong> Deklaration aller<br />
Zugriffsmethoden<br />
liste.c: Implementierung aller Zugriffsmethoden<br />
haupt.c: Programm verwendet <strong>die</strong> Liste, enthält ma<strong>in</strong><br />
⇒ gleichzeitiges Arbeiten am Source-Code möglich<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 26 / 41<br />
Gültigkeitsbereich von Bezeichnern<br />
#<strong>in</strong>clude <br />
#<strong>in</strong>clude "liste.h"<br />
list_t * create(void) {<br />
list_t *l;<br />
}<br />
liste.c<br />
l = (list_t *) malloc(sizeof(list_t));<br />
l->first = (node_t *) malloc(sizeof(node_t));<br />
l->last = (node_t *) malloc(sizeof(node_t));<br />
l->first->succ = l->last;<br />
l->first->pred = NULL;<br />
l->last->succ = NULL;<br />
l->last->pred = l->first;<br />
l->size = 0;<br />
return l;<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 28 / 41<br />
Gültigkeitsbereich von Bezeichnern<br />
<strong>in</strong>t dequeue(list_t *l) {<br />
<strong>in</strong>t res = -1;<br />
node_t *f;<br />
}<br />
if (isEmpty(l))<br />
return res;<br />
f = l->first->succ;<br />
l->first->succ = f->succ;<br />
f->succ->pred = l->first;<br />
res = f->value;<br />
l->size -= 1;<br />
free(f);<br />
return res;<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 30 / 41<br />
Gültigkeitsbereich von Bezeichnern<br />
liste.c<br />
liste.obj<br />
liste.h<br />
#<strong>in</strong>clude #<strong>in</strong>clude<br />
Prä−Compiler<br />
Compiler<br />
L<strong>in</strong>ker<br />
haupt.exe<br />
haupt.c<br />
haupt.obj<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 32 / 41
Gültigkeitsbereich von Bezeichnern<br />
Es gibt vier mögliche Gültigkeitsbereiche:<br />
der Compiler kennt nur, was er bereits gelesen hat, aber ke<strong>in</strong>e<br />
anderen Dateien → globale Variablen und alle Funktionen<br />
gelten vom Deklarationspunkt bis zum Ende der Datei<br />
formale Funktionsparameter gelten vom Deklarationspunkt bis<br />
zum Ende der Funktion bzw. des Prototypen<br />
lokale Variablen am Beg<strong>in</strong>n e<strong>in</strong>es Blocks gelten bis zum Ende<br />
des Blocks<br />
Anweisungsmarken gelten <strong>in</strong>nerhalb der Funktion, <strong>in</strong> der <strong>die</strong><br />
Deklaration erfolgt<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 33 / 41<br />
Lebensdauer von Objekten<br />
Wie lange bleibt e<strong>in</strong> Objekt im Speicher und kann über se<strong>in</strong>en<br />
Bezeichner angesprochen werden?<br />
statische Lebensdauer: Objekte s<strong>in</strong>d stets verfügbar<br />
Funktionen<br />
globale Variablen<br />
statische Variablen<br />
automatische Lebensdauer: Objekte, <strong>die</strong> zu Beg<strong>in</strong>n e<strong>in</strong>es<br />
Blocks angelegt werden, s<strong>in</strong>d nach dem Verlassen des Blocks<br />
nicht mehr verfügbar, sofern nicht anders def<strong>in</strong>iert.<br />
e<strong>in</strong>e Funktion ist auch e<strong>in</strong> Block<br />
dynamische Lebensdauer: Der Speicherbereich wird mittels<br />
Bibliotheksfunktionen angelegt und freigegeben (malloc und<br />
free).<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 35 / 41<br />
Speicherklasse<br />
Die Speicherklasse e<strong>in</strong>es Objekts hat E<strong>in</strong>fluss auf<br />
<strong>die</strong> Lebensdauer und<br />
den Gültigkeitsbereich des Objekts und<br />
erlaubt E<strong>in</strong>schränkungen für den Zugriff auf Daten.<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 37 / 41<br />
Speicherklasse: extern<br />
In der Regel ist Datenaustausch über e<strong>in</strong>e Parameterliste<br />
gegenüber globalen Variablen vorzuziehen:<br />
Global gültige Daten führen oft zu Programmen mit vielen,<br />
schwer durchschaubaren Datenpfaden zwischen Funktionen<br />
(mit unerwünschten Nebenwirkungen).<br />
Der Aufbau von Bibliotheken mit allgeme<strong>in</strong> gültigen<br />
Funktionen ist nicht möglich.<br />
Weniger Fehleranfällig: Pr<strong>in</strong>zip der Datenkapselung<br />
Daten s<strong>in</strong>d nur <strong>in</strong>nerhalb e<strong>in</strong>es Moduls sichtbar<br />
Zugriff auf Daten nur über def<strong>in</strong>ierte Zugriffsmethoden<br />
mehr dazu später<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 39 / 41<br />
Gültigkeitsbereich von Bezeichnern<br />
<strong>in</strong>t global; // gilt bis zum Ende der Datei<br />
// x: gilt nur <strong>in</strong>nerhalb der Klammern<br />
double s<strong>in</strong>(double x);<br />
<strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char *argv[]) {<br />
<strong>in</strong>t lokal; // gilt nur <strong>in</strong>nerhalb von ma<strong>in</strong><br />
...<br />
for (i = 0; i < 10; i++) {<br />
<strong>in</strong>t j; // gilt nur <strong>in</strong>nerhalb des Blocks<br />
for (j = 0; j < i; j++) {<br />
...<br />
}<br />
}<br />
}<br />
// Label ende gilt nur <strong>in</strong>nerhalb von ma<strong>in</strong><br />
ende: ...<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 34 / 41<br />
Lebensdauer von Objekten<br />
void fkt(<strong>in</strong>t x) {<br />
static <strong>in</strong>t s = 1; // statische Lebensdauer<br />
<strong>in</strong>t a = 1; // automatische Lebensdauer<br />
}<br />
pr<strong>in</strong>tf("x= %d, s= %d, a= %d\n", x, s++, a++);<br />
<strong>in</strong>t ma<strong>in</strong>(void) {<br />
<strong>in</strong>t i, *p;<br />
}<br />
p = (<strong>in</strong>t *) malloc(10 * sizeof(<strong>in</strong>t));<br />
for (i = 0; i < 10; i++) {<br />
p[i] = i + 1; // dynamische Lebensdauer<br />
fkt(p[i]);<br />
}<br />
free(p);<br />
return 0;<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 36 / 41<br />
Speicherklasse: extern<br />
Variablen, <strong>die</strong> außerhalb von Funktionen deklariert werden, s<strong>in</strong>d<br />
implizit vom Typ extern.<br />
Lebensdauer: Für <strong>die</strong> gesamte Laufzeit des Programms wird<br />
Speicherplatz reserviert.<br />
Gültigkeit: Globale Variablen gelten von dem Punkt, an dem sie<br />
vere<strong>in</strong>bart werden, bis zum Ende der Datei.<br />
E<strong>in</strong> Objekt e<strong>in</strong>er externen Deklaration ist beim B<strong>in</strong>den auch<br />
Programmteilen aus anderen Dateien bekannt.<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 38 / 41<br />
Speicherklasse: static<br />
Anwendung bei<br />
Funktionen: Die Funktion ist nur <strong>in</strong>nerhalb der Quelldatei und<br />
nicht dem L<strong>in</strong>ker bekannt (siehe Modulare <strong>Programmierung</strong>,<br />
Datenkapselung).<br />
lokale Variablen: Objekte behalten ihren Wert auch nach<br />
Verlassen des Blocks, <strong>in</strong> dem sie def<strong>in</strong>iert s<strong>in</strong>d.<br />
globale Variablen: E<strong>in</strong>schränkung des Gültigkeitsbereichs auf<br />
<strong>die</strong> Datei.<br />
Gültigkeit: <strong>in</strong>nerhalb des umschließenden Blocks bzw. bei<br />
Funktionen und globalen Variablen <strong>in</strong>nerhalb der Datei.<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 40 / 41
Speicherklasse: static<br />
dat1.c:<br />
void f(void) {<br />
extern <strong>in</strong>t i;<br />
...<br />
}<br />
static <strong>in</strong>t i;<br />
<strong>in</strong>t j;<br />
void g(void) {<br />
i = 42;<br />
j = 4711;<br />
...<br />
}<br />
sehr schlechter Programmierstil!<br />
dat2.c:<br />
void h(void) {<br />
extern <strong>in</strong>t j; // ok<br />
extern <strong>in</strong>t i; // Fehler!<br />
}<br />
i += 42;<br />
j += 4711<br />
<strong>E<strong>in</strong>führung</strong> <strong>in</strong> <strong>die</strong> <strong>Programmierung</strong> Gültigkeitsbereiche 41 / 41