Einführung in die Programmiersprache C

Werbung
Einführung in die Programmiersprache C
Steffen Börm
Christian-Albrechts-Universität zu Kiel
Sommersemester 2014
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
1 / 68
Übersicht
1
Einleitung
2
Daten
3
Ausdrücke und Funktionen
4
Fallunterscheidungen und Schleifen
5
Zeiger und Arrays
6
Programmbibliotheken
7
Praxis
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
2 / 68
Wieso C?
Flexibel: Volles Potential des Computers steht zur Verfügung.
Effizient: Maschinennah, viele Operationen können durch den
Compiler unmittelbar in Maschinenbefehle verwandelt werden.
Beherrschbar: Es passiert nur, was wir explizit programmieren.
Verbreitet: Eine der am häufigsten genutzten
Programmiersprachen, verwandt mit C++, Objective C und Java.
Vorsicht: C verzeiht Fehler nicht so leicht wie andere Sprachen.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
3 / 68
Termine
Für die C-Einführung werden die Termine der Vorlesungen
Algorithmen und Datenstrukturen“ und Organisation und Architektur
”
”
von Rechnersystemen“ der ersten Semesterwoche verwendet:
Montag, 14. April 2014, CAP3 Hörsaal 2, 10 c.t. (Börm)
Montag, 14. April 2014, CAP3 Hörsaal 2, 16 c.t. (von Hanxleden)
Dienstag, 15. April 2014, CAP3 Hörsaal 2, 9 s.t. (von Hanxleden)
Freitag, 25. April 2014, CAP3 Hörsaal 2, 8 c.t. (Börm)
Hinzu kommen praktische Aufgaben und Ergänzungen in den
jeweiligen Übungen.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
4 / 68
Literatur
Wir können im Rahmen der Vorlesung nur einen kurzen Einblick in die
wichtigsten Aspekte der Sprache C geben, deshalb empfehlen wir für
eine eingehendere Beschäftigung die folgenden Quellen:
D. Ritchie und B. W. Kernighan:
Programmieren in C
P. Bäumle-Courth, T. Schmidt:
Praktische Einführung in C
RRZN Hannover:
Die Programmiersprache C. Ein Nachschlagewerk.
Wikibook C-Programmierung
C-Howto.de
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
5 / 68
Entwicklungsumgebung
Ein C-Programm durchläuft mehrere Stufen, bevor es ausgeführt
werden kann:
Editor: Wir schreiben das Programm als gewöhnliche Textdatei.
Präprozessor: Einzelne Zeichenketten können ersetzt werden,
beispielsweise um Abkürzungen zu verwenden.
Compiler: Der resultierende Text wird in die Maschinensprache
eines Computers übersetzt.
Linker: Es entsteht eine für das Betriebssystem ausführbare Datei.
Loader: Die ausführbare Datei wird in den Speicher geladen.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
6 / 68
Software
Für die Bearbeitung der Übungsaufgaben ist ein Computer mit
C-Entwicklungsumgebung erforderlich.
Windows: Visual Studio Express
Windows: MinGW / MSys (Unix-ähnlich)
MacOS: Xcode
Linux: GNU Compiler Collection
Alternative: Virtuelles Linux-System unter VirtualBox
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
7 / 68
Beispiel: GNU Compiler Collection
Präprozessor und Compiler: Überführen den Quelltext example.c in
eine Objektdatei example.o, die Maschinenbefehle und
Linker-Informationen, beispielsweise über Funktionsnamen, enthält.
gcc -c example.c
Linker: Fügt Objektdateien und Bibliotheken zu einer ausführbaren
Datei example zusammen.
gcc example.o -o example
Programmstart: Unmittelbar per Befehlszeile.
./example
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
8 / 68
Übersicht
1
Einleitung
2
Daten
3
Ausdrücke und Funktionen
4
Fallunterscheidungen und Schleifen
5
Zeiger und Arrays
6
Programmbibliotheken
7
Praxis
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
9 / 68
Variablen
Eine Variable ist in C ein Speicherbereich, der eine gewisse Größe hat
und an einer gewissen Adresse beginnt.
Variablen werden im Rahmen einer Variablendefinition mit einem
Namen versehen, um dem Programmierer die Arbeit zu erleichtern.
Variablennamen dürfen aus
Buchstaben (a, . . . , z, A, . . . ,Z),
Ziffern (1, . . . ,9, 0) und
Unterstrichen ( ) bestehen,
sie dürfen allerdings nicht mit einer Ziffer beginnen.
Um die Zuordnung eines geeigneten Speicherbereichs zu einem
Variablennamen kümmern sich Compiler, Linker und Loader.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
10 / 68
Typen
Damit der Compiler weiß, wie eine Variable zu interpretieren ist, wird
jeder Variablen ein Typ zugeordnet.
Typen können mit Namen versehen sein, für die dieselben Regeln wie
für Variablennamen gelten.
Einige Typen sind vordefiniert, beispielsweise
int für ganze Zahlen,
float und double für Gleitkommazahlen oder
char für Buchstaben.
Manche Typen können mit den Schlüsselworten short, long und
unsigned modifiziert werden.
Mathematik: Ein Typ kann als eine Menge von Werten interpretiert
werden, eine Variable dieses Typs entspricht dann einem Element
dieser Menge.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
11 / 68
Variablendefinitionen
Eine Variable wird definiert, indem ihr Typ und ihr Name durch
Leerraum getrennt angegeben werden, den Abschluss bildet ein
Semikolon:
int x;
int 2y;
long int y4;
short int w_3;
float x+y;
float x_plus_y;
char _Next;
unsigned char a;
S. Börm (CAU Kiel)
4
8
4
4
8
4
4
4
ganze Zahl, Variablenname x
Variablenname beginnt mit Ziffer
lange ganze Zahl namens y4
kurze ganze Zahl namens w_3
Variablenname enthält Zeichen +“
”
Gleitkommazahl namens x_plus_y
Buchstabe namens _Next
Buchstabe ohne Vorzeichen namens a
Einführung C
Sommersemester 2014
12 / 68
Verbünde
Mit dem Schlüsselwort struct können wir neue Typen aus bereits
definierten Typen zusammensetzen.
struct {
int a;
float x;
} z;
Die beiden Komponenten können wir dann mit z.a und z.x erreichen,
sie sind Variablen des Typs int beziehungsweise float.
Mathematik: Ein Typ entspricht einer Menge T , ein Verbundtyp
entspricht dem kartesischen Produkt mehrere Mengen T = X × Y .
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
13 / 68
Typdefinitionen
Spätestens bei Verbünden empfiehlt es sich, neu definierten Typen
einen eigenen Namen zu geben. Diesem Zweck dient das
Schlüsselwort typedef:
typedef unsigned int uint;
typedef struct { float re; float im; } complex;
typedef struct { int r; int g; int b; } color;
Die neuen Typen können in Variablendefinitionen verwendet werden:
uint i;
complex z;
color background;
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
14 / 68
Übersicht
1
Einleitung
2
Daten
3
Ausdrücke und Funktionen
4
Fallunterscheidungen und Schleifen
5
Zeiger und Arrays
6
Programmbibliotheken
7
Praxis
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
15 / 68
Operatoren für arithmetische Berechnungen
Die Inhalte von Variablen werden durch Operatoren verwendet und
verändert.
Arithmetische Operatoren führen Berechnungen durch.
x + y
3 * a
y - z
b / 17
c % 5
Zuweisungsoperatoren verändern Werte von Variablen.
a = b
x += y
a *= 3
i ++
++ i
S. Börm (CAU Kiel)
y -= z
b /= 17
j --- j
Einführung C
c %= 5
Sommersemester 2014
16 / 68
Operatoren für die Bitmanipulation
int- und char-Variablen können auch als Folge von Bits interpretiert
und entsprechend manipuliert werden.
Bitweise Verknüpfungen führen Oder-, Exklusiv-Oder-, Und- sowie
Komplement-Operationen für alle Bits des Ergebnisses durch.
x | y
x |= y
˜f
p ˆ q
p ˆ= q
a & b
a &= b
Bitweises Schieben nach links“ und rechts“, wobei das niedrigste Bit
”
”
rechts“ steht.
”
x << 5
y >> 3
a <<= 2
b >>= 4
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
17 / 68
Ausdrücke
Mehrere Operatoren können zu komplexeren Termen
zusammengesetzt werden.
Dabei gelten die üblichen Regeln für arithmetische Ausdrücke,
beispielsweise Punkt- vor Strichrechnung“. Mit Klammern lässt sich
”
die Reihenfolge der Anwendung der Operatoren steuern.
Für konstante Größen können Literale verwendet werden,
beispielsweise 3 für die Zahl drei oder 3.141 als Näherung der Zahl π.
x = (a + 7) * 3
a += 3 * b + 17
p = q = r
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
18 / 68
Typkonvertierung
Mit dem Cast-Operator können wir Ausdrücke eines Typs in andere
Typen umwandeln:
int
a =
b =
c =
d =
a; int b; float c; int d;
17;
a / 3;
((float) a) / 3;
23 / ((int) c);
Bei der Berechnung von b wird die ganzzahlige Division verwendet,
bei der von c die konventionelle, bei der von d wiederum die
ganzzahlige, da in diesem Fall c abgerundet wird.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
19 / 68
Funktionen
Eine Funktion beschreibt eine Folge von Anweisungen, die der Reihe
nach ausgeführt werden.
Sie werden nach demselben Schema wie Variablen und Typen mit
Namen bezeichnet.
Die einfachste Anweisung ist ein mit einem Semikolon
abgeschlossener Ausdruck, der ausgeführt wird.
void
compute()
{
x = 4 * y + 3;
}
Das Schlüsselwort void gibt in diesem Beispiel an, dass die Funktion
keinen Wert zurückgibt.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
20 / 68
Parameter und Rückgabewert
Eine Funktion kann eine Anzahl von Parametern erhalten. Parameter
sind Variablen, denen Werte zugewiesen werden, wenn wir die
Funktion aufrufen.
Eine Funktion kann mit der Anweisung return ein Ergebnis
zurückgeben.
double
area_triangle(double height, double base)
{
return height * base / 2.0;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
21 / 68
Funktionen ohne Rückgabewert
Falls eine Funktion keinen Wert zurückgeben soll, beispielsweise weil
ihre Ergebnis anders übermittelt werden können, können wir den
vordefinierten Typ void verwenden:
void
stop_program()
{
exit();
}
Der Typ void weist die Besonderheit auf, dass wir keine Variablen
oder Parameter dieses Typs definieren dürfen.
Allerdings dürfen wir (dazu später mehr) Zeiger auf diesen Typ
verwenden.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
22 / 68
Funktionsaufrufe
Der Aufruf einer Funktion ist ein weiterer Operator, der die Parameter
übergibt und das Ergebnis der Funktion als Wert zurückgibt.
a = area_triangle(3.0, 1.5)
b = area_triangle(4.0, 2.0)
- 3.0 * area_triangle(1.0, 0.5)
Die Ausführung unseres Programms beginnt mit dem Aufruf der
Funktion main durch das System. Einfachstes Beispiel:
int
main()
{
return 0;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
23 / 68
Lokale Variablen
Zu Beginn einer Funktion können eine Reihe von Variablen definiert
werden, die nur innerhalb der Funktion existieren und sichtbar sind:
int
main()
{
int i;
int j;
i = 3 + 5 * 7;
j = i * i - 2;
return j;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
24 / 68
Beispiel: Fläche eines Dreiecks
Aufgabe: Berechne die Fläche des Dreiecks ABC.
Mathematik: Fläche ist halbe Determinante der Kantenvektoren:
1
Bx − Ax Cx − Ax
det
By − Ay Cy − Ay
2
float
area_triangle3(float ax, float ay,
float bx, float by,
float cx, float cy)
{
float bax; float bay; float cax; float cay;
bax = bx - ax; bay = by - ay;
cax = cx - ax; cay = cy - ay;
return 0.5 * (bax * cay - bay * cax);
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
25 / 68
Übersicht
1
Einleitung
2
Daten
3
Ausdrücke und Funktionen
4
Fallunterscheidungen und Schleifen
5
Zeiger und Arrays
6
Programmbibliotheken
7
Praxis
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
26 / 68
Fallunterscheidungen
Häufig müssen wir in Abhängigkeit von Variablen unterschiedliche
Rechenoperationen ausführen.
if(x)
y = 2.0 * a + b;
else
z = 1.5 * b - a;
Falls x ungleich null ist, werden die Befehle in der zweiten Zeile
ausgeführt, sonst die in der vierten.
Die dritte und vierte Zeile können wir wegfallen lassen, falls wir sie
nicht benötigen.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
27 / 68
Operatoren für Wahrheitswerte
In C steht der Wert 0 für falsch“ und jeder andere Wert für wahr“.
”
”
Vergleichsoperatoren ergeben 1, falls eine Relation gilt, und 0 sonst.
x < y
x <= y
a > b
a >= b
p != q
p == q
Vorsicht: x = y ist eine Zuweisung, x == y ist ein Vergleich.
Logische Operatoren führen Oder-, Und- und Nicht-Operationen durch.
x || y
a && b
!f
Vorsicht: In x || y wird y nur ausgewertet, falls x gleich null ist, und
in x && y wird es nur auswertet, falls x ungleich null ist.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
28 / 68
Beispiel: Fakultät per Rekursion
Induktive Definition: Die Fakultät der Zahl 0 ist 1.
Die Fakultät der Zahl n ist dasselbe wie das Produkt aus n und der
Fakultät der Zahl n-1.
unsigned int
factorial(unsigned int n)
{
if(n == 0)
return 1;
else
return n * factorial(n-1);
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
29 / 68
Beispiel: Fallunterscheidung in Ausdrücken
Wir können in C eine Fallunterscheidung auch direkt in einen Ausdruck
hineinschreiben, beispielsweise lässt sich das Maximum der Zahlen a
und b wir folgt berechnen:
maximum = (a < b ? b : a)
Falls das erste Argument ungleich null ist, wird das zweite Argument
ausgewertet, sonst das dritte.
Die Berechnung der Fakultät lässt sich so kürzer schreiben:
unsigned int
factorial(unsigned int n)
{
return (n == 0 ? 1 : n * factorial(n-1));
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
30 / 68
Blockanweisungen
Formal unterscheidet die if-Anweisung nur zwischen zwei
Anweisungen, die ausgeführt werden sollen.
Wir können allerdings mehrere Anweisungen und sogar lokale
Variablen mit geschweiften Klammern {, } zu einer Blockanweisung
zusammenfassen:
int i; int j;
if(i == 3) {
int j;
j = i * 7 + 5;
i = j / 2;
}
else
i = 2 * i + 3;
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
31 / 68
Mehrfache Fallunterscheidung
Wir können mit einer einzigen Fallunterscheidung auch mehrere
mögliche Werte eines Ausdrucks behandeln:
switch(x) {
case 0:
a = b;
break;
case 1:
a = c;
break;
default:
a = b + c;
}
Vorsicht: Ohne break werden auch die folgenden Befehle ausgeführt.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
32 / 68
while-Schleife
Wir können dafür sorgen, dass eine Folge von Anweisungen
wiederholt wird, solange eine Bedingung erfüllt ist:
i = 1;
j = 0;
while(i < 1000) {
i *= 2;
j ++;
}
Der Schleifenrumpf, der Anweisungsblock in geschweiften Klammern,
wird ausgeführt, solange die Auswertung der Schleifenbedingung, des
Ausdrucks in den runden Klammern, einen von null verschiedenen
Wert ergibt.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
33 / 68
Beispiel: Euklidischer Algorithmus
Aufgabe: Berechnung des größten gemeinsamen Teilers.
if(a == 0)
return b;
while(b != 0) {
if(a > b)
a -= b;
else
b -= a;
}
return a;
Idee: Der ggT beider Zahlen bleibt in jedem Schritt unverändert.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
34 / 68
Beispiel: Ägyptisches Potenzieren
Aufgabe: Berechne y = x p für eine natürliche Zahl p.
y = 1; z = x;
while(p > 0) {
if(p % 2 == 1)
y *= z;
p /= 2;
z *= z;
}
return y;
Idee: Binärdarstellung p = pk 2k + pk−1 2k−1 + . . . + p1 21 + p0 führt zu
k
k−1
x p = (x 2 )pk (x 2 )pk−1 . . . (x 2 )p1 x p0 .
Vorsicht: Division ganzer Zahlen ergibt eine ganze Zahl.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
35 / 68
for-Schleife
Häufig sind vor dem Eintritt in eine Schleife Variablen zu setzen und in
jedem Durchlauf zu aktualisieren.
j = 0;
for(i=1; i<=100; i++)
j += i;
Der erste Ausdruck der for-Anweisung wird vor Eintritt in die
eigentliche Schleife ausgeführt.
Die Schleife wird wiederholt, solange der zweite Ausdruck
ungleich null ist.
Am Ende jedes Schleifendurchlaufs wird der dritte Ausdruck
ausgewertet.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
36 / 68
for-Schleife als while-Schleife
Jede for-Schleife kann auch als while-Schleife geschrieben werden:
for(i=7; i>0; i/=2)
j++;
ist äquivalent zu
i = 7;
while(i > 0) {
j++;
i /= 2;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
37 / 68
Beispiel: Fibonacci-Folge
Aufgabe: Berechne die durch f0 = 0, f1 = 1, fk = fk−1 + fk−2 gegebene
Fibonacci-Folge.
if(k == 0)
return 0;
g = 0;
f = 1;
for(i=1; i<k; i++) {
h = g;
g = f;
f = g + h;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
38 / 68
Übersicht
1
Einleitung
2
Daten
3
Ausdrücke und Funktionen
4
Fallunterscheidungen und Schleifen
5
Zeiger und Arrays
6
Programmbibliotheken
7
Praxis
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
39 / 68
Zeiger
Eine Besonderheit der Sprache C ist die Möglichkeit, unmittelbar auf
die Adressen von Variablen zuzugreifen.
Wenn wir den Adressoperator & auf eine Variablen anwenden,
erhalten wir einen Zeiger auf den zu ihr gehörenden Speicherbereich.
void
pointer()
{
int k;
int *k_ptr;
k_ptr = &k;
}
Zeiger können genauso in Variablen gespeichert werden wie Zahlen,
der Typ T * beschreibt dabei Zeiger auf Variablen des Typs T.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
40 / 68
Dereferenzieren
Indem wir den Inhaltsoperator * auf einen Zeiger anwenden, können
wir den Speicherbereich, auf den er zeigt, wie eine Variable
verwenden:
int
dereference()
{
int k;
int *k_ptr;
k_ptr = &k;
*k_ptr = 7;
return k;
}
Die Zuweisung an *k_ptr hat hier denselben Effekt wie eine
Zuweisung an k, die Funktion gibt immer 7 zurück.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
41 / 68
Zeiger als Funktionsparameter
Mit Zeigern kann eine Funktion mehrere Ergebnisse zurückgeben:
void
sum_and_product(float x, float y,
float *sum, float *product)
{
*sum = x + y;
*product = x * y;
}
int main()
{
float a; float b;
sum_and_product(7, 5, &a, &b);
return 0;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
42 / 68
Arrays
Wir können Variablen definieren, die mehrere Elemente eines
bestimmten Typs aufnehmen, indem wir Arrays verwenden:
void
array()
{
int x[4];
x[0] = 3; x[2] = 8;
x[1] = 5; x[3] = x[1] + x[2];
}
Vorsicht: Die Elemente eines Arrays der Länge n sind mit 0 bis n-1
durchnumeriert, im Beispiel darf etwa x[4] nicht verwendet werden.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
43 / 68
Arrays und Zeiger
In fast allen Fällen unterscheidet C nicht zwischen einem Array und
einem Zeiger auf das erste Element des Arrays:
void
array_pointer()
{
int x[4];
int *x_ptr;
x_ptr = x;
x_ptr[2] = 7;
x[3] = x_ptr[2];
}
Vorsicht: Dadurch wird es dem Compiler unmöglich, die Korrektheit
von Arrayzugriffen zu prüfen.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
44 / 68
Zeigerarithmetik
Wenn wir zu einem Zeiger eine ganze Zahl hinzuaddieren, erhalten wir
einen Zeiger auf einen anderen Eintrag des Arrays:
void
pointer_add()
{
float x[5];
float *x0_ptr, *x3_ptr, *x2_ptr;
x0_ptr = x;
x3_ptr = x0_ptr + 3;
x2_ptr = x3_ptr - 1;
}
Vorsicht: Wir können in dieser Weise Werte anderer Variablen und
womöglich sogar das Programm selbst verändern.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
45 / 68
Strings
Zeichenketten werden in C als Arrays des Typs char dargestellt.
Um Zeichenketten unterschiedlicher Länge handhaben zu können,
wird das Ende der Zeichenkette durch eine Null markiert.
Wie Zahlen können auch konstante Strings durch Literale definiert
werden, nämlich durch in doppelte Anführungszeichen
eingeschlossene Buchstabenfolgen.
char *a;
a = "Algorithmen und Datenstrukturen\n";
Mit einem Backslash \ können Sonderzeichen eingefügt werden, hier
etwa durch \n der Wechsel in eine neue Zeile.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
46 / 68
Beispiel: Länge eines Strings
int
length_string(char *a)
{
int len;
len = 0;
while(*a != 0) {
len++; a++;
}
return len;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
47 / 68
Beispiel: Suchen eines Teilstrings
char *
findsub_string(char *a, char *b)
{
char *asub, *bsub;
while(*a != 0) {
asub = a; bsub = b;
while(*bsub != 0 && *asub == *bsub) {
asub++; bsub++;
}
if(*bsub == 0)
return a;
a++;
}
return 0;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
48 / 68
Beispiel: Befehlszeilenparameter
Der Funktion main werden in einer Unix-Umgebung auch die in der
Befehlszeile angegebenen Parameter als Funktionsparameter
übergeben.
Das erfolgt über ein Array aus Strings:
int
main(int argc, char **argv)
{
int i;
for(i=1; i<argc; i++)
if(strcmp(argv[i], "--help") == 0)
print_help_message();
return 0;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
49 / 68
Verbünde und Zeiger
Ein Verbundtyp kann Zeiger auf sich selbst enthalten, wenn wir bei der
Definition dem Verbundtyp einen Namen geben:
typedef struct list_element_s {
int entry;
struct list_element_s *next;
} list_element;
Für den Zugriff auf die Komponenten eines Verbundtyps, auf die ein
Zeiger verweist, gibt es als Abkürzung den Operator ->:
list_element *this;
this->entry = 42;
this->next = 0;
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
50 / 68
Übersicht
1
Einleitung
2
Daten
3
Ausdrücke und Funktionen
4
Fallunterscheidungen und Schleifen
5
Zeiger und Arrays
6
Programmbibliotheken
7
Praxis
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
51 / 68
Funktionsdeklaration
Wir können eine Funktion dem Compiler bekannt machen, ohne sie
vollständig zu definieren. Statt einer Funktionsdefinition ist es dann
eine Funktionsdeklaration:
extern float area_circle(float radius);
Eine deklarierte Funktion kann wie jede andere aufgerufen werden,
allerdings muss spätestens zur Laufzeit des Programms auch eine
vollständige Definition vorliegen.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
52 / 68
Header-Dateien
Über Funktionsdeklarationen lässt sich einfach der Zugriff auf externe
Programmbibliotheken und das Betriebssystem umsetzen.
Die Deklarationen werden in einer separaten Datei zusammengefasst,
die wir mit einer Präprozessor-Anweisung einbinden können:
#include <math.h>
int
main()
{
double x;
double y;
x = sin(3.0) / cos(3.0) - tan(3.0);
y = log(3.5) + exp(-2.5);
return 0;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
53 / 68
Standardbibliothek
Die Kommunikation mit dem Betriebssystem, also insbesondere auch
mit dem Anwender, erfolgt über eine Standardbibliothek, die eine
Reihe von Funktionen enthält, unter anderem für
die Ein- und Ausgabe von Zeichen,
die Anforderung und Freigabe von Speicher,
die Manipulation von Zeichenketten oder
mathematische Operationen.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
54 / 68
Ausgabe von Daten
#include <stdio.h>
int
main()
{
int i;
printf("Hallo\n");
i = 3 * 4 + 7;
printf("3 * 4 + 7 = %d\n", i);
return 0;
}
Der erste Parameter definiert das Format der Ausgabe, mit %
markierte Platzhalter werden durch die weiteren Parameter ersetzt.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
55 / 68
Eingabe von Daten
#include <stdio.h>
int
main()
{
int i;
int j;
scanf("%d", &i);
scanf("%d", &j);
printf("%d mod %d = %d\n", i, j, i % j);
return 0;
}
Auch hier definiert der erste Parameter, welche Daten die Funktion
erwarten soll. Vorsicht: Die weiteren Parameter müssen Zeiger sein.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
56 / 68
Speicherverwaltung
#include <stdlib.h>
int
main()
{
int *a;
a = (int *) malloc(sizeof(int));
*a = 17;
free(a);
return 0;
}
Der Größenoperator sizeof ermittelt die Speichergröße eines Typs
oder einer Variablen,
Der Cast-Operator (T) interpretiert sein Argument als Typ T.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
57 / 68
Beispiel: Einfach verkettete Liste, Teil 1
typedef struct list_s {
int entry;
struct list_s *next;
} list;
list *
addto_list(int entry, list *s)
{
list *new;
new = malloc(sizeof(list));
new->entry = entry; new->next = s;
return new;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
58 / 68
Beispiel: Einfach verkettete Liste, Teil 2
list *s, *x;
s = addto_list(17, 0);
s = addto_list(36, s);
s = addto_list(5, s);
for(x=s; x; x=x->next)
printf("%d\n", x->entry);
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
59 / 68
Arrays variabler Größe
#include <stdlib.h>
int
main()
{
int *fib; int n; int i;
n = 17;
fib = (int *) malloc(sizeof(int) * n);
fib[0] = 0; fib[1] = 1;
for(i=2; i<n; i++) {
fib[i] = fib[i-1] + fib[i-2];
}
free(fib);
return 0;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
60 / 68
Beispiel: Stringoperationen
Da Strings nur Arrays sind, würde der Zuweisungsoperator = lediglich
den Zeiger auf ihr erstes Element kopieren. Deshalb brauchen wir
Hilfsfunktionen, die Speicher anfordern und die Arrays kopieren.
#include <string.h>
int
main()
{
char *a; char *b; char *c
a = "Algorithmen"; b = " und Datenstrukturen";
c = (char *) malloc(sizeof(char)
* (strlen(a) + strlen(b) + 1));
strcpy(c, a);
strcat(c, b);
return 0;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
61 / 68
Übersicht
1
Einleitung
2
Daten
3
Ausdrücke und Funktionen
4
Fallunterscheidungen und Schleifen
5
Zeiger und Arrays
6
Programmbibliotheken
7
Praxis
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
62 / 68
Compiler-Warnungen
Gute Compiler können eine Reihe typischer Programmierfehler
erkennen, die in formal korrekten C-Programmen auftreten.
Das folgende Programmfragment ist korrektes C, bewirkt aber
vermutlich nicht das vom Programmierer Erwartete:
if(x=y)
x += 3;
Wenn wir den GNU-Compiler mit zusätzlichen Parametern aufrufen,
erhalten wir eine Warnung:
gcc -c -Wall -Wextra ifdemo.c
warning: suggest parentheses around assignment
used as truth value
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
63 / 68
Defensives Programmieren
Zusicherungen: C bietet eine einfache Möglichkeit, die Gültigkeit
logischer Bedingungen zu überprüfen:
#include <assert.h>
assert(p != 0);
p->entry = 5;
Falls die in assert angegebene Bedingung nicht wahr ist, wird das
Programm mit einer Fehlermeldung beendet.
Initialisierung: Es ist häufig sinnvoll, Variablen rechtzeitig in einen
definierten Zustand zu bringen. Das gilt insbesondere bei der Freigabe
dynamischen Speichers:
free(p); p = 0;
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
64 / 68
Verständlichkeit des Programmtexts
Um ein Programm verständlich zu halten, empfiehlt es sich,
Kommentare einzufügen, die zwischen /* und */ eingeschlossen
werden:
int i;
/* Schleifenvariable */
/* Zahlen von 1 bis 10 aufsummieren */
j = 0;
for(i=1; i<=10; i++)
j += i;
Kommentare werden durch den Präprozessor durch Leerraum ersetzt.
Die Lesbarkeit eines Programms lässt sich weiter verbessern, indem
konsequent Leerzeilen zwischen zusammengehörenden Anweisungen
eingefügt und Rümpfe von Schleifen und Fallunterscheidungen durch
Einrückungen kenntlich gemacht werden.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
65 / 68
Konstante Parameter
Insbesondere bei Funktionen, die mit Zeigern arbeiten, ist es sinnvoll,
das Schlüsselwort const einzusetzen, um sicher zu stellen, dass über
bestimmte Zeiger nur lesend auf Variablen zugegriffen werden kann.
int
string_compare(const char *a, const char *b)
{
while(*a != 0 && *a == *b) {
a++; b++;
}
if(*a == *b)
return 0;
else if(*a < *b) return -1;
else
return 1;
}
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
66 / 68
Debugger
Mit einem Debugger können übersetzte Programme Schritt für Schritt
ausgeführt und Variablen untersucht werden.
Zu der GNU Compiler Collection gehört beispielsweise der GNU
Debugger gdb.
gdb debugtest
break debugtest.c:10
run
print i
step
cont
Für die Analyse von Speicherzugriffen ist valgrind ein hilfreiches
Werkzeug, das das Programm auf einem simulierten Rechner ausführt
und sein Verhalten protokolliert.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
67 / 68
Make
Für umfangreichere Projekte bietet es sich an, den Aufruf der Compiler
und Linker zu automatisieren. Das Programm make berücksichtigt
dabei die Abhängigkeiten zwischen den einzelnen Dateien, die wir ihm
in Form der Datei Makefile zur Verfügung stellen müssen:
modul1.o: modul1.c modul1.h
modul2.o: modul2.c modul2.h
prog.o: prog.c modul1.h modul2.h
prog: prog.o modul1.o modul2.o
Für jede Abhängigkeit können wir (mit −
→
−
− eingerückt) Befehle
−
→
angeben, mit denen das Ziel aus den Quellen erzeugt werden kann.
S. Börm (CAU Kiel)
Einführung C
Sommersemester 2014
68 / 68
Herunterladen