Sie sind auf Seite 1von 79

Die Programmiersprache C

1 Einleitung
1.1 bersicht
Einleitung
bersicht
Einige grundlegende Begriffe
Geschichtliche Entwicklung, Einordnung
Ein erstes Programm
Grundelemente der Sprache C

Grundlegende Datentypen
Arithmetische Datentypen, Konstanten, Variablen, Zeiger, Felder,
Speicherklassen, Typattribute, Operatoren, Typumwandlung

Kontrollstrukturen
Blockanweisung, Verzweigungs-Anweisungen,
Wiederholungs-Anweisungen, spezielle Anweisungen

Hhere Datentypen
Benutzerdefinierte Datentypen,
Mehrdimensionale Felder, Strukturen und Varianten
Ergnzung: Aufzhlungstyp, Bitfelder

Funktionen
Argumente der main-Funktion, variable Parameteranzahl,
Unterschiede: ANSI-C K&R-C

Standardbibliotheken
Beispiele

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

bersicht (1)

1.2 Einige grundlegende Begriffe


Algorithmus:
Eine endliche, eindeutige Schrittfolge von Operationen, die als allgemeines Verfahren die Lsung einer Klasse von Problemen zum Ziel hat.
Programm:
Die Formulierung eines Algorithmus und der zugehrigen Datendarstellung in einer Programmiersprache.
Machinensprache Assembler
Hochsprache
Interpreter Compiler

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Einige grundlegende Begriffe (1)

(primitiver) Datentyp:
(Wertemenge, Operationenmenge)
Datenobjekt:
kann Wert aufnehmen
Systemzustand:
bestimmt durch aktuelle Werte aller Datenobjekte
Operation:
Aktion, abhngig von Argumenten und Systemzustand
Abstrakter Datentyp (ADT):
(Wertemenge(n), Operationenmenge)
nach auen wie primitiver Datentyp. Beispiel: Intervalle.

Abstraktes Datenobjekt:
(Abstrakter Datentyp, Objekt)
ADT, dessen Operationen abhngen von Argumenten,
Systemzustand und Gedchtnis des ADTs; beeinflut
das Gedchtnis die Operationen nicht, liegt ein Abstrakter Datentyp vor. Beispiel: Warteschlange.

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Einige grundlegende Begriffe (2)

1.3 Geschichtliche Entwicklung,


Einordnung
Anfang der 70er Jahre wurde C von Dennis M.
Ritchie an den Bell Laboratories entworfen zum
Schreiben von Systemprogrammen fr eine DEC
PDP-11.
C ist Nachfolger von BCPL bzw. B, bei denen es
sich jedoch im Gegensatz zu C um typenlose Sprachen handelt. C wurde verallgemeinert und auf eine Vielzahl von Rechnern portiert. Es wird durch
eine umfassende Menge von Werkzeugen im Betriebssystem UNIX untersttzt. UNIX selbst ist zu
ber 90% in C implementiert.
Ende 1989 erfolgte die Standardisierung von C
durch das ANSI X3J11 Komitee.
Seitdem entwickelte sich C zu der am hufigsten
verwendeten Sprache in der professionellen Softwareentwicklung.

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Geschichtliche Entwicklung, Einordnung (1)

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

FORTRAN 57

BASIC

78

APL

68

Geschichtliche Entwicklung, Einordnung (2)

MODULA-2 80

OBERON

88

LISP

ALGOL 60 60

ALGOL 68 77

PL/1

66

COBOL

68

LOGO

68

81

PASCAL

70

BCPL

67

SIMULA 67 69

PROLOG

ADA

83

PEARL

77

72

SMALLTALK 80

C++

84

Einordnung von Programmiersprachen

59

1.4 Ein erstes Programm


/****************************************
* Ein erstes Programm: Hello, World!
*****************************************/
#include <stdio.h>
int main (void)
{
printf ("Hello, World!\n");
return (0);
} /* main */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Ein erstes Programm (1)

1.5 Grundelemente der Sprache C


Folgende Zeichen sind in C-Programmen zulssig:
die alphanumerischen Zeichen:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
0 1 2 3 4 5 6 7 8 9

die folgenden Sonderzeichen:


( ) [ ] { } < > + - * / % ^ ~
& | _ = ! ? # \ , . ; : "

Leerzeichen, (horizontaler) Tabulator, Zeilenendezeichen, vertikaler Tabulator und Zeilenvorschub.


Die nachfolgenden Schlsselwrter sind in C reserviert. Sie knnen nur in ihrer vordefinierten Bedeutung verwendet werden:
auto
break
case
char
const
continue
default
do

TUHH

Rechenzentrum

double
else
enum
extern
float
for
goto
if

Einfhrung in C
Dirk Husung

int
long
register
return
short
signed
sizeof
static

struct
switch
typedef
union
unsigned
void
volatile
while

Grundelemente der Sprache C (1)

2 Grundlegende Datentypen
2.1 Arithmetische Datentypen
Typ

Speicherplatzbedarf

signed
unsigned
signed
unsigned
signed
unsigned
signed
unsigned

long

TUHH

Rechenzentrum

char
char
char
short [int]
short [int]
short [int]
int
int
int
long [int]
long [int]
long [int]
float
double
double

Einfhrung in C
Dirk Husung

1 Byte
1 Byte
1 Byte
2 Bytes
2 Bytes
2 Bytes
maschinenabhngig 2 oder 4 Bytes
maschinenabhngig 2 oder 4 Bytes
maschinenabhngig 2 oder 4 Bytes
4 Bytes
4 Bytes
4 Bytes
4 Bytes
8 Bytes
maschinenabhngig 8, 10 oder
16 Bytes

Arithmetische Datentypen (1)

Bemerkungen:
Der char-Typ kann compilerabhngig vorzeichenbehaftet oder vorzeichenlos sein.
Der jeweilige Speicherplatzbedarf kann mit dem
sizeof-Operator bestimmt werden (durch den
Prprozessor!). Es gilt:
sizeof (short) sizeof (int) sizeof (long).

Die Wertebereiche der Datentypen sind durch


Konstanten in den Header-Dateien limits.h
fr ganzzahlige Typen und float.h fr Gleitpunkttypen beschrieben; z.B.:
#define
#define
#define
#define

SHRT_MIN (-32768)
SHRT_MAX
32767
LONG_MIN
((long)0x80000000)
LONG_MAX
0x7fffffff

#define DBL_MIN

2.2250738585072014e-308

#define DBL_MAX

1.7976931348623151e+308

C besitzt keinen gesonderten booleschen Typ.


Es gilt:
ganzzahliger Wert == 0 FALSE
ganzzahliger Wert != 0 TRUE
C besitzt keinen Mengentyp, jedoch weitreichende Mglichkeiten der Bitmanipulation (s.u.).

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Arithmetische Datentypen (2)

IEEE-double-Format:
sign biased exponent significant
1 bit 11 bits
52 bits
msb
lsb
0/1 11 . . . 10
...
00 . . . 01
denormal 0/1 00 . . . 00
...
00 . . . 00
0
0/1 00 . . . 00
+
0 11 . . . 11

1 11 . . . 11
nan
0/1 11 . . . 11
...
11 . . . 11

normal

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

[1.]11 . . . 11 2exponent1023
...
[1.]00 . . . 00
[0.]11 . . . 11 21022
...
[0.]00 . . . 01
00 . . . 00
00 . . . 00
00 . . . 00
11 . . . 11
...
00 . . . 01

Arithmetische Datentypen (3)

2.2 Konstanten
Ganzzahlige Konstanten
Konstante

Typ

1234
1234U
12345678L
134217728UL
0x8000000UL

int
unsigend int
long
unsigend long
unsigned long, hexadezimal
Hexziffern: 09, AF, af.
char, oktal

007

Gleitkommakonstanten
Konstante

Typ

12.7
1e5
2.0E-3
12.7f
1e5f
2.0E-3l

double
double
double
float
float
long double

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Konstanten (1)

Zeichen
Konstante

Typ

a
\007
\x0A
\n
\

char
char, oktale Notation (hier: \a)
char, hexadezimale Notation (hier: \n)
char, Escape-Sequenz
char, Escape-Sequenz

Zeichenketten
Zeichenketten sind Felder von Zeichen mit einem
zustzlichen abschlieenden 0-Zeichen.
Konstante

Typ

"string"
char *
"\"string\"" char *, Escape-Sequenz

Wichtig:
x belegt 1 Byte
"x" belegt 2 Bytes (0-terminierte Zeichenkette)

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Konstanten (2)

2.3 Variablen
Variablen sind benannte Datenobjekte, die einen
Wert aufnehmen knnen.
Variablennamen bestehen aus einer Folge von
Buchstaben und Ziffern, beginnend mit einem
Buchstaben. Der Unterstrich _ zhlt dabei zu
den Buchstaben.
Zwischen Gro- und Kleinbuchstaben wird unterschieden.
Variablen sind vor Benutzung zu deklarieren;
z.B.:
extern unsigned int uMemoryUsed;
Sie sind an genau einer Stelle im Programm zu
definieren. Erst mit der Variablendefinition wird
Speicherplatz belegt; z.B.:
unsigned int uMemoryUsed;
Variablen knnen bei ihrer Definition initialisiert
werden; z.B.:
unsigned int uMemoryUsed = 0;

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Variablen (1)

2.4 Zeiger, Felder, Adrearithmetik


Beispiel:
int i = 1;
int * pi = & i;
int aiVector [4] = {
1, 2, 3, 4
};
int * piVector = aiVector;
piVector++;
i = piVector - aiVector;

0x10000:
0x10004:
0x10008:
1 i
0x1000C: 0x10008 pi
0x10010:
1 aiVector[0] aiVector
0x10014:
2 aiVector[1]
0x10018:
3 aiVector[2]
0x1001C:
4 aiVector[3]
0x10020: 0x10010 piVector
0x10024:
0x10028:

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Zeiger, Felder, Adrearithmetik (1)

Das Wichtigste in Stichpunkten:


Zeiger-Variablen drfen anderen Zeiger-Variablen gleichen Typs zugewiesen werden.
Der Wert NULL kann jedem Zeiger zugewiesen
werden. NULL verweist auf kein existierendes
Objekt.
Zeiger-Variablen drfen verglichen werden (==,
!=, <, <=, >, >=).
Zeiger-Variablen knnen inkrementiert und dekrementiert werden (skalierte Zeigerarithmetik).
Der Abstand zwischen Zeigern kann ermittelt
werden, sofern die Zeiger auf einen zusammenhngenden Speicherbereich verweisen.
Felder werden reprsentiert durch einen Zeiger auf
das erste Feldelement.
Die Feldelemente tragen die Indizes 0,1,. . .

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Zeiger, Felder, Adrearithmetik (2)

2.5 Speicherklassen
Speicherklasse Beschreibung
auto

static

extern
register

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Standard, optional.
Sichtbarkeit: auerhalb aller Funktionen programmweit, innerhalb einer Funktion beschrnkt auf den aktuellen Block.
Lebensdauer: auerhalb aller Funktionen
ber die gesamte Programmlaufzeit, innerhalb einer Funktion fr die Ausfhrung des
betreffenden Blocks.
Initialisierung: auerhalb aller Funktionen
mit 0, sonst undefiniert, wenn nicht explizit
angegeben.
Sichtbarkeit: auerhalb aller Funktionen modulweit, innerhalb einer Funktion beschrnkt
auf den betreffenden Block.
Lebensdauer: ber die gesamte Programmlaufzeit.
Initialisierung: mit 0, wenn nicht explizit angegeben.
Deklaration, Definition i.a. in einem anderen
Modul auerhalb aller Funktionen als auto.
wie auto, jedoch Empfehlung an den Compiler, die betreffende Variable in einem Prozessorregister zu halten.

Speicherklassen (1)

Beispiel:
#include <stdio.h>
int main (void)
{
int i;
for (i = 0; i < 3; i++) {
int k = 0;
/* beliebiger Ausdruck */
printf ("%4d", k++);
}
for (i = 0; i < 3; i++) {
static int k = 0; /* konstanter Ausdruck */
printf ("%4d", k++);
}
return (0);
} /* main */

Ausgabe:
0

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Speicherklassen (2)

2.6 Typattribute
Attribut

Beschreibung

const

legt fest, da eine Variable nicht gendert werden darf, auch nicht komponentenweise (Felder, Strukturen); z.B.:
const double e = 2.7183;
zeigt an, da eine Variable jederzeit gendert werden kann, auch in nicht offensichtlicher Weise etwa im Verlauf einer
Interrupt-Behandlung ( Einschrnkung
fr Compileroptimierungen).

volatile

Beispiel:
Zeiger auf ein Objekt vom Typ
int
int * const pi;
konstanter Zeiger auf ein Objekt vom Typ int
const int * pi;
Zeiger auf ein konstantes Objekt vom Typ int
const int * const pi; konstanter Zeiger auf ein konstantes Objekt vom Typ int
int * pi;

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Typattribute (1)

2.7 Operatoren
Arithmetische Operatoren
Inkrement-, Dekrementoperator
Vergleichsoperatoren
Operatoren zur Bitmanipulation
Logische Operatoren
sizeof-Operator
Bedingter-Ausdruck-Operator
Zuweisungsoperatoren
Sonstige Operatoren
Anmerkung:
Die Zuweisung zhlt in C zu den Operatoren.
Es gibt in C keine benutzerdefinierten Operatoren.

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Operatoren (1)

Reihenfolge der Ausdrucksauswertung:


1. entsprechend der Klammerung
2. entsprechend der Prioritt der Operatoren
3. entsprechend der Assoziativitt der Operatoren
von rechts nach links bei
monadischen Operatoren
bedingten Ausdrcken
Zuweisungen
4. entsprechend der Assoziativitt der Operatoren
von links nach rechts bei
arithmetischen Operatoren
Vergleichsoperatoren
Operatoren zur Bitmanipulation
Wichtig:
In C ist i.a. nicht festgelegt, in welcher Reihenfolge die Operanden eines Operators (oder auch die
Argumente einer Funktion) ausgewertet werden.
Ausnahmen: &&, ||, ?:
Hier erfolgt die Auswertung der Operanden garantiert von links nach rechts.
TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Operatoren (2)

bitweiser Operator &:


char a = 0xE4; /* 1110 0100 */
char b = 0xCC; /* 1010 1010 */
char r = a & b; /* 1010 0000 */

bitweiser Operator |:
char a = 0xE4; /* 1110 0100 */
char b = 0xCC; /* 1010 1010 */
char r = a | b; /* 1110 1110 */

bitweiser Operator ^:
char a = 0xE4; /* 1110 0100 */
char b = 0xCC; /* 1010 1010 */
char r = a ^ b; /* 0100 1110 */

bitweiser Operator ~:
char a = 0xE4;
char r = ~a;

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

/* 1110 0100 */
/* 0001 1011 */

Operatoren (3)

bitweiser Operator >>:


signed char
signed char
unsigned char
unsigned char

a
r
ua
ur

=
=
=
=

0xE4;
a >> 1;
0xE4;
ua >> 1;

/*
/*
/*
/*

1110
?111
1110
0111

0100
0010
0100
0010

*/
*/
*/
*/

bitweiser Operator <<:


char
char

a
r

= 0xE4;
/* 1110 0100 */
= a << 1; /* 1100 1000 */

logischer Operator &&:


char a = 0xE4;
/* 1110 0100 */
char b = 0xCC;
/* 1010 1010 */
char r = a && b; /* 0000 0001 */

logischer Operator ||:


char a = 0xE4;
/* 1110 0100 */
char b = 0xCC;
/* 1010 1010 */
char r = a || b; /* 0000 0001 */

logischer Operator !:
char a = 0xE4;
char r = !a;

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

/* 1110 0100 */
/* 0000 0000 */

Operatoren (4)

2.8 Typumwandlung
Implizite Typumwandlung
Werden Operanden unterschiedlichen arithmetischen Typs miteinander verknpft, erfolgt eine Typanhebung:
x * ld (long double) x * ld
x * d (double)
x * d
x * f (float)
x * f

, sonst
, sonst
, sonst

nach Erweiterung auf int, wenn mglich, sonst


nach Erweiterung auf unsigend int:
x * ul (unsigned
u * l (long)
u * l (unsigned
(unsigned
x * l (long)
x * u (unsigned

long) x
u
long) u
long) l
x
int) x

* ul
* l
*
* l
* u

, sonst
, sonst
, sonst
, sonst

darin bezeichnen:
ld
d
f
ul
l
u
x

TUHH

Rechenzentrum

einen long double Operanden


einen double Operanden
einen float Operanden
einen unsigend long Operanden
einen long Operanden
einen unsigned int Operanden
einen Operanden sonstigen Typs

Einfhrung in C
Dirk Husung

Typumwandlung (1)

Explizite Typumwandlung
Der expliziten Typumwandlung dient der cast-Operator.
Beispiel: Zugriff auf die einzelnen Bytes einer intVariablen i:
((unsigned char *) & i)[0];
:
((unsigned char *) & i)[sizeof(i)-1];

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Typumwandlung (2)

3 Kontrollstrukturen
3.1 Block-Anweisung
Jede Anweisung kann eine Block-Anweisung sein.
Innerhalb jedes Anweisungsblocks ist die Definition
lokaler Variablen mglich.
{

definitions
statements
}

TUHH

Rechenzentrum

int t = a;
a = b; b = t;
}

Einfhrung in C
Dirk Husung

Block-Anweisung (1)

3.2 Verzweigungs-Anweisungen
if-, if-else-Anweisung
if (int_expr)
statement

if (i < 10) {
element[0][i] = i;
element[1][i] = i*i;
}

1
ja

2
int_expr != 0

3
statement
4

if (int_expr)
statement1
else
statement2

if (i < 2)
element[i] = i;
else
element[i] = element[i-2]
+ element[i-1];
1
ja

nein

int_expr != 0
3

statement1

statement2
5

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Verzweigungs-Anweisungen (1)

switch-Anweisung
switch (int_expr) {
case int_const:
statements
[break;]
default:
statements
}
switch (c) {
case \n: /* Zeilenende */
number_of_lines++;
case \t: /* Tabulator oder */
case : /* Leerzeichen */
number_of_words++;
break;
default:
/* bel. sonstiges Zeichen */
number_of_characters++;
break;
}

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Verzweigungs-Anweisungen (2)

3.3 Wiederholungs-Anweisungen
while-Anweisung
while (int_expr)
statement

i = 0;
while (i < DIM) {
element[0][i] = i;
element[1][i] = i*i;
i++;
}

for-Anweisung
for (init_expr; int_expr; reinit_expr)
statement

quivalent zu:
init_expr;
while (int_expr) {
statement
reinit_expr;
}
for (i = 0; i < DIM; i++) {
element[0][i] = i;
element[1][i] = i*i;
}

do-while-Anweisung
do {
statements
} while (int_expr);

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

do {
element[0][i] = i;
element[1][i] = i*i;
} while (++i < DIM);

Wiederholungs-Anweisungen (1)

do {
while (int_expr ) for (init_expr ;
statement
statement
int_expr ; reinit_expr )
} while (int_expr );
statement

1
2

init_expr

statement

nein

int_expr != 0

3
statement

ja
4
int_expr != 0
4

int_expr != 0

nein
4

5
statement

6
reinit_expr

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Wiederholungs-Anweisungen (2)

3.4 Spezielle Anweisungen


break-, continue-Anweisung
i = 0;
for (;;) {
i++;
if (i == 17) break;
i++;
}
i = 0;
while (++i < 16) {
func1 (i);
if (i < 8) continue;
func2 (i);
}

return-Anweisung
return (i);

goto-Anweisung
goto STORAGE_ERROR;
/* ... */
STORAGE_ERROR:
fprintf (stderr, "zu wenig Speicher");
exit (1);

leere Anweisung
;

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Spezielle Anweisungen (1)

3.5 Beispielprogramme
Zeichenkette kopieren
char
achSrc [] = "Zeichenkette";
char
achDest [20];
char * pchSrc
= achSrc;
char * pchDest
= achDest;
int i = 0;
while ((pchDest[i] = pchSrc[i]) != 0)
i++;
oder:
while ((*pchDest = *pchSrc) != 0) {
pchDest++;
pchSrc++;
}
oder:
while ((*pchDest++ = *pchSrc++) != 0)
;
oder:
while (*pchDest++ = *pchSrc++)
;

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Beispielprogramme (1)

/*******************************************
* cel2fahr: Celsius-Fahrenheit-Tabelle
********************************************/
#include <stdio.h>
int main (void)
{
double dCel;
printf ("Celsius

Fahrenheit\n");

for (dCel = 300; dCel >= 0; dCel -= 20)


printf ("%6.0f
%6.1f\n",
dCel, (dCel*9)/5 + 32);
return (0);
} /* main */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Beispielprogramme (2)

/*******************************************
* wc: Zeichen, Woerter, Zeilen zaehlen.
********************************************/
#include <stdio.h>
#define FALSE
#define TRUE

0
1

int main (void)


{
int nChars =
int nWords =
int nLines =
int fInWord =
int c;

0;
0;
0;
FALSE;
/* eingelesenes Zeichen */

while ((c = getchar()) != EOF) {


++nChars;
if (c == \n)
++nLines;
if (c == || c == \n || c == \t)
fInWord = FALSE;
else if (fInWord == FALSE) {
fInWord = TRUE;
++nWords;
}
} /* while */
printf("%d Zeichen, %d Woerter, %d Zeilen\n",
nChars, nWords, nLines);
return (0);
} /* main */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Beispielprogramme (3)

/*******************************************
* dos2unix: <CR,LF> durch <LF> ersetzen.
********************************************/
#include <stdio.h>
#define CR 0x0D
#define LF 0x0A
int main (void)
{
int
c;
while ((c = getc (stdin)) != EOF) {
switch (c) {
case CR :
do {
if ((c = getc (stdin)) == LF)
break;
putc (CR, stdout);
if (c == EOF) goto ENDWHILE;
} while (c == CR);
/* kein break */
default :
putc (c, stdout);
break;
}
} ENDWHILE:
return (0);
} /* main */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Beispielprogramme (4)

/*******************************************
* unix2dos: <LF> durch <CR,LF> ersetzen.
********************************************/
#include <stdio.h>
#define CR 0x0D
#define LF 0x0A
int main (void)
{
int
c;
while ((c = getc (stdin)) != EOF) {
switch (c) {
case CR :
do {
putc (CR, stdout);
} while ((c = getc (stdin)) == CR);
if (c == EOF) goto ENDWHILE;
putc (c, stdout);
break;
case LF :
putc (CR, stdout);
default :
putc (c, stdout);
}
} ENDWHILE:
return (0);
} /* main */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Beispielprogramme (5)

/*******************************************
* tabexp: Tabulatorzeichen expandieren.
********************************************/
#include <stdio.h>
#define TABWIDTH 8
int main (void)
{
int iColumn;
int c;
iColumn = 0;
while ((c = getc (stdin)) != EOF) {
switch (c) {
case \t :
do {
putc ( , stdout);
} while (++iColumn % TABWIDTH);
break;
case \n :
putc (\n, stdout); iColumn = 0;
break;
default :
putc (c, stdout); iColumn++;
break;
} /* switch */
} /* while */
return (0);
} /* main */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Beispielprogramme (6)

4 Hhere Datentypen
4.1 Benutzerdefinierte Datentypen
Komplexere Vereinbarungen lassen sich schrittweise lesen, wenn die durch Klammerung und Prioritten vorgegebene Reihenfolge beachtet wird; mit
(term)[] Feld von
(term)() Funktion mit Wert
*(term) Zeiger auf

beispielsweise:
int
int
int
int

*x[8];
*x(int);
(*x)[];
(*x)(int);

Feld von 8 Zeigern auf int


Funktion mit Wert Zeiger auf int
Zeiger auf Feld von int
Zeiger auf Funktion mit Wert int

wichtig:
In der Definition:
int * a, b;

wird a als Zeiger auf int, b jedoch lediglich als


int erklrt!
TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Benutzerdefinierte Datentypen (1)

Abhilfe: benutzerdefinierte Typen


Typdefinitionen:
#define VOID
typedef VOID *

void
PVOID;

#define INT
typedef INT *
typedef PINT *

int
PINT;
PPINT;

#define SIZE
size_t; /* aus stdlib.h */
typedef SIZE * PSIZE;
typedef PSIZE * PPSIZE;
typedef INT
typedef FINT *

FINT (INT);
PFINT;

damit:
PINT
PINT
PPINT
PFINT

TUHH

Rechenzentrum

x [8];
x (INT);
x;
x;

Einfhrung in C
Dirk Husung

Benutzerdefinierte Datentypen (2)

4.2 Mehrdimensionale Felder


statische Felder
INT IntMatrix [2][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8}
};
IntMatrix [0][0] = 0;

Allokierung eines zusammenhngenden Speicherbereichs fester Dimension.


zeilenweise Speicherung einer Matrix.
der letzte Index bezieht sich auf ein Element
vom Grundtyp.

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Mehrdimensionale Felder (1)

dynamische Felder
Mat

Mat[0]
Mat[1]
Mat[2]
Mat[3]

#define NROWS

Mat[0][0]
Mat[1][0]
Mat[2][0]
Mat[3][0]

Mat[0][1] Mat[0][2] Mat[0][3]


Mat[1][1] Mat[1][2]
Mat[2][1]

PPINT ppIntMatrix;
SIZE i;
ppIntMatrix = (PPINT) malloc (
NROWS * sizeof (PINT));
for (i = 0; i < NROWS; i++) {
SIZE uSize = (NROWS - i) * sizeof (INT);
ppIntMatrix [i] = (PINT) malloc (uSize);
memset (ppIntMatrix [i], 0, uSize);
}
ppIntMatrix [0][0] = 1;

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Mehrdimensionale Felder (2)

4.3 Strukturen und Varianten


Strukturen
typedef struct _NODE {
INT
Elmt;
struct _NODE *Next;
} NODE;
typedef NODE * PNODE;
NODE Node;
PNODE pNode = & Node;
Node.Elmt = 1;
(*pNode).Elmt = 1;
pNode -> Elmt = 1;

Varianten (der Speicherbereich einer jeden Komponente beginnt an derselben Adresse)


typedef union {
DOUBLE x;
UCHAR c [8];
} CONV;
CONV d;
d.x = 1.2;
d.c[7] = -d.c[7];

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Strukturen und Varianten (1)

Operationen auf Strukturen


Adresse einer Struktur bestimmen (&-Operator)
Zugriff auf Komponenten einer Struktur (.- und
->-Operator)
Gre einer Struktur bestimmen
(sizeof-Operator)
Zuweisung als Ganzes
Dies beinhaltet Argumentbergabe und Ergebnisrckgabe eines Funktionsaufrufs (per Wert).
In der Regel ist die bergabe bzw. Rckgabe
eines Zeigers auf eine Struktur effizienter! (In
lteren K&R-C Versionen steht die Zuweisung
von Strukturen nicht zur Verfgung; hier Zuweisung mit memcpy().)
Strukturen knnen nicht mit Vergleichsoperatoren verglichen werden (Vergleich auf Gleichheit
mit memcmp().)

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Strukturen und Varianten (2)

4.4 Aufzhlungstyp, Bitfelder


Aufzhlungstyp
typedef enum {
FALSE, TRUE, OFF = 0, ON
} BOOLEAN;

Bit-Felder
typedef struct {
unsigned Day
: 5; /* Bits 0..4 */
unsigned Month : 4; /* Bits 5..8 */
unsigned Year : 7; /* Bits 9..15 */
} DATE;

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Aufzhlungstyp, Bitfelder (1)

5 Funktionen
Eine Funktion wird deklariert (Funktionsprototyp) in
der Form
[extern] [Ergebnistyp] Funktionsname ([Parameterliste]);

oder:
static [Ergebnistyp] Funktionsname ([Parameterliste]);

Eine Funktion wird definiert in der Form


[static] [Ergebnistyp] Funktionsname ([Parameterliste])
{
definitions
statements
}

Darin sind die Parameter einer Parameterliste durch


Kommata getrennt anzugeben in der Form einer
Variablendefintion (ohne Initialisierung).
In der Funktionsdeklaration kann die Angabe eines
Parameternamens entfallen.
TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Funktionen (1)

Eine Funktion ist vor ihrer Benutzung zu deklarieren.


Eine Funktion ist standardmig programmweit
ab ihrer Deklaration sichtbar.
Eine als static vereinbarte Funktion ist ab ihrer Deklaration modulweit sichtbar.
Eine Funktion eines anderen Moduls sollte als
extern deklariert werden.
Die Definition einer Funktion kann ihre Deklaration ersetzen.
Eine Prozedur (ohne Ergebnistyp) kann als
Funktion mit dem Ergebnistyp void vereinbart
werden.
Fehlt die Angabe des Ergebnistyps, so gilt der
Ergebnistyp int als vereinbart.
Einer aufrufenden Funktion ist es freigestellt,
das Ergebnis einer aufgerufenen Funktion zu
verwenden oder nicht.
Eine parameterlose Funktion ist als Funktion mit
der Parameterliste (void) zu vereinbaren.
Argumente werden stets per Wert bergeben.
Funktionen knnen rekursiv aufgerufen werden.

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Funktionen (2)

5.1 Beispiel: Konvertierung


Zeichenkette ganze Zahl
#include <ctype.h>
int atoi (char * pszNumber)
{
int iNumber = 0;
int iSign;
while (isspace (*pszNumber))
pszNumber++;
iSign = (*pszNumber == -) ? -1 : 1;
if (*pszNumber == - || *pszNumber == +)
pszNumber++;
while (isdigit (*pszNumber))
iNumber =
iNumber * 10 + (*pszNumber++ - 0);
return (iSign * iNumber);
} /* atoi */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Konvertierung: Zeichenkette ganze Zahl (1)

5.2 Argumentbergabe per Wert


so nicht:
void Swap (int a, int b)
{
int t = a;
a = b; b = t;
} /* Swap */

sondern so:
void Swap (int * pa, int * pb)
{
int t = *pa;
*pa = *pb; *pb = t;
} /* Swap */

alternativ:
#define Swap(a, b) {
int t = a;
a = b; b = t;
}

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

\
\
\

Argumentbergabe per Wert (1)

5.3 Rekursiver Aufruf von Funktionen


int fac (int n)
{
if (n <= 1)
return (1);
else
return (n*fac(n-1));
} /* fac */

_fac:
push
mov

ebp
ebp, esp

cmp
jg

[ebp+8],1
L1

mov
jmp

eax,1
L2

mov
dec
push
call
add
imul

eax,[ebp+8]
eax
eax
_fac
esp, 4
eax, [ebp+8]

mov
pop
ret

esp, ebp
ebp

L1:

0x1001C:
0x10018:
0x10014:
8
0x10010: ret-addr
0x1000C:
bp sp
0x10008:
0x10004:
0x10000:

L2:

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Rekursiver Aufruf von Funktionen (1)

5.4 Argumente der main-Funktion


Mgliche Definitionsformen der main-Funktion:
Ohne Bercksichtigung von Aufrufargumenten:
int main (void)
{
...
}

Mit Zugriff auf Argumente bei Programmaufruf:


int main (int nArgs, char* aArg[])
{
...
}

Dabei liefert:
aArg[0] den Namen des aufgerufenen Programms.
aArg[1] . . . Zeiger auf Aufrufargumente.
aArg[nArgs] den Wert NULL.
Mit zustzlichem Zugriff auf Umgebungsvariablen:
int main (int nArgs, char* aArg[],
char* pEnv[])
{
...
}

Der letzte Eintrag von pEnv besitzt den Wert NULL.

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Argumente der main-Funktion (1)

5.5 Variable Parameteranzahl


#include <stdarg.h>
void ErrorMsg (
int iLine, int iCol, int iErrorClass, ... )
{
va_list Argument; /* fuer va_...-Macros */
va_start (Argument, iErrorClass);
switch (iErrorClass) {
case eReservedSym:
/* ... */
break;
case eUnknownFunc: {
char * pchText = va_arg (
Argument, char *);
/* ... */
vprintf (pchText, Argument);
} break;
}
va_end (Argument);
} /* ErrorMsg */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Variable Parameteranzahl (1)

5.6 Unterschiede: ANSI-C K&R-C


ANSI-C mit Funktionsprototyp:
double CylinderVolume (
double rad, double height);
double CylinderVolume (
double rad, double height)
{
return (height*rad*rad*3.14159);
} /* CylinderVolume */

Aufruf:
CylinderVolume (1, 2);

implizite Typanpassung!
oder K&R-C:
double CylinderVolume ();
double CylinderVolume (rad, height)
double rad, height;
{
return (height*rad*rad*3.14159);
} /* CylinderVolume */

Aufruf:
CylinderVolume (1, 2);

Laufzeitfehler!
TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Unterschiede: ANSI-C K&R-C (1)

6 Beispiele
6.1 Taschenrechner
# ----------------------------------------# Makefile (dmake): Taschenrechner
# ----------------------------------------CC
CFLAGS

= gcc
= -Wall -O2 # alle Warnungen,
# Optimierungen

OBJS

= calc.o scanner.o stack.o

# ---- Programme -------------------------calc.exe: $(OBJS)


$(CC) $(OBJS) -o calc.exe
# ---- Abhaengigkeiten -------------------calc.o:
calc.o:
calc.o:

calc.c
scanner.h
stack.h

scanner.o:

scanner.c scanner.h

stack.o:

stack.c stack.h

# ---- Regeln ----------------------------.o: .c


$(CC) -c $(CFLAGS) $< -o $@

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Taschenrechner (1)

/******************************************
* calc.c: einfacher Taschenrechner
*******************************************/
#include <stdio.h>
#include <math.h>
#include "scanner.h"
#include "stack.h"
#define loop

for(;;)

/******************************************
* Konstanten-Definitionen
*******************************************/
#define TOKENSIZE

256

/******************************************
* Hauptprogramm
*******************************************/
int main (void)
{
/* ... */
} /* main */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Taschenrechner (2)

int main (void)


{
char achToken [TOKENSIZE];
loop {
switch (GetToken (achToken)) {
case NUMBER:
Push (atof (achToken));
break;
case +:
Push (Pop () + Pop ());
break;
case -: {
double dOp = Pop ();
Push (Pop () - dOp);
} break;
case *:
Push (Pop () * Pop ());
break;
case /: {
double dOp = Pop ();
if (dOp == 0)
printf ("division by zero\n");
Push (Pop () / dOp);
} break;
case \n:
printf ("%g\n", Pop ());
break;
case EOF:
return (0);
default:
printf ("unknown command %s\n",
achToken);
break;
}
} /* loop */
} /* main */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Taschenrechner (3)

/******************************************
* scanner.h: Scanner
*******************************************/
#ifndef __SCANNER__
#define __SCANNER__
/******************************************
* Konstanten-Definitionen
*******************************************/
#define NUMBER

256

/******************************************
* Funktions-Prototypen
*******************************************/
extern int GetToken (char * pchToken);
#endif

/******************************************
* scanner.c: Scanner
*******************************************/
#include <stdio.h>
#include <ctype.h>
#include "scanner.h"
/******************************************
* Implementierung globaler Funktionen
*******************************************/
int GetToken (char * pchToken)
{
/* ... */
} /* GetToken */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Taschenrechner (4)

int GetToken (char * pchToken)


{
int c;
/* Zwischenraumzeichen ueberlesen */ {
while ((c = getc (stdin)) ==
|| c == \t)
;
}
/* ggf. Zahl einlesen */ {
if (isdigit (c) || c == .) {
if (isdigit (c))
do {
*pchToken++ = c;
} while (isdigit (c = getc (stdin)));
if (c == .)
do {
*pchToken++ = c;
} while (isdigit (c = getc (stdin)));
*pchToken = 0;
ungetc (c, stdin);
return (NUMBER);
}
}
/* sonstige Zeichen */ {
*pchToken++ = c;
*pchToken
= 0;
return (c);
}
} /* GetToken */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Taschenrechner (5)

/******************************************
* stack.h: double-Stack
*******************************************/
#ifndef __STACK__
#define __STACK__
/******************************************
* Funktions-Prototypen
*******************************************/
extern void
Push (double dValue);
extern double Pop (void);
#endif

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Taschenrechner (6)

/******************************************
* stack.c: double-Stack
*******************************************/
#include <stdio.h>
#include "stack.h"
/******************************************
* Konstanten- und Variablen-Definitionen
*******************************************/
#define STACKSIZE

32

static double aStack [STACKSIZE];


static int
iStack = 0;
/******************************************
* Implementierung globaler Funktionen
*******************************************/
void Push (double dValue)
{
if (iStack == STACKSIZE)
printf ("stack overflow\n");
else
aStack [iStack++] = dValue;
} /* Push */
double Pop (void)
{
if (iStack)
return (aStack [--iStack]);
else {
printf ("stack underflow\n");
return (0.0);
}
} /* Pop */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Taschenrechner (7)

6.2 Portabilitt
/******************************************
* Portab.h
Spracherweiterungen,
*
Maschinenabhaengigkeiten
*******************************************/
#ifndef __PORTAB__
#define __PORTAB__
#include <stdlib.h>
#if defined (__GNUC__)
#define __ANSI__
#ifndef __32BIT__
#define __32BIT__
#endif
#define __LOWBYTEFIRST__
#endif
#if defined (__XLC__)
#define __32BIT__
#define __HIGHBYTEFIRST__
#endif
#if defined (__STDC__) ||\
defined (__ANSI__) ||\
defined (__cplusplus)
#define ARGS(parameters)
#define NOARGS
#else
#define ARGS(parameters)
#define NOARGS
#endif

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

parameters
VOID
()

Portabilitt (1)

/******************************************
* Konstantendefinitionen
*******************************************/
#define TRUE
#define FALSE

1
0

#define SUCCESS
#define FAILURE

0
(-1)

#if defined (__LOWBYTEFIRST__)


#define LO
0
#define HI
1
#elif defined (__HIGHBYTEFIRST__)
#define LO
1
#define HI
0
#else
#error byte order undefined!
#endif
/******************************************
* Verschiedenes
*******************************************/
#if !defined (NULL)
#define NULL
0L
#endif
#define
#define
#define
#define
#define

loop
for (;;)
sqr(a)
((a)*(a))
min(a,b)
(((a) < (b)) ? (a) : (b))
max(a,b)
(((a) > (b)) ? (a) : (b))
dimof(array)\
(sizeof(array) / sizeof(*(array)))

#endif /* !__PORTAB__ */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Portabilitt (2)

6.3 Dynamische Speicherverwaltung


/******************************************
* DynMem.h
*******************************************/
#ifndef __DYNMEM__
#define __DYNMEM__
extern PVOID _MemNew ARGS ((SIZE uSize));
/****************************************
* Funktion : Allokiert uSize Bytes
*
Speicher.
* Eingaben : uSize: Groesse des Speicher*
bereichs.
* Ergebnis : Zeiger auf Speicherbereich.
* Annahmen : uSize ist ohne Rest durch 4
*
teilbar.
*/
extern VOID _MemDelete ARGS ((
PVOID pMemory, SIZE uSize));
/****************************************
* Funktion : Gibt einen mit _MemNew()
*
allokierten Speicherbereich
*
frei.
* Eingaben : pMemory: Zeiger auf freizu*
gebenden Speicher*
bereich.
*
uSize : Groesse des
*
Speicherbereichs.
* Annahmen : uSize ist ohne Rest durch 4
*
teilbar.
*/
#endif /* !__DYNMEM__ */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Dynamische Speicherverwaltung (1)

/******************************************
* DynMem.c
*******************************************/
#include "Portab.h"
#include "DynMem.h"
PVOID _MemNew (SIZE uSize)
{
PPVOID pMemory;
if (uSize <= MEM_MAXSIZE
&& (pMemory = (PPVOID) *((PPVOID)
((PCHAR) MemStore + uSize))) != NULL) {
*((PPVOID) ((PCHAR) MemStore + uSize)) =
*pMemory;
}
else if ((pMemory = (PPVOID) malloc (
uSize)) == NULL) {
INT iErrorClass = 0;
do {
(*MemErrorHandler) (iErrorClass++);
} while ((pMemory = (PPVOID) malloc (
uSize)) == NULL);
}
#if defined (__MEMTEST__)
ulMemUsed += uSize;
if (ulMemUsed > ulMaxMemUsed)
ulMaxMemUsed = ulMemUsed;
#endif
#if defined (__PROTOCOL__)
printf ("MemNew: %p (%d Bytes)\n",
pMemory, uSize);
#endif
return (PVOID) pMemory;
} /* _MemNew */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Dynamische Speicherverwaltung (2)

VOID _MemDelete (PVOID pMemory, SIZE uSize)


{
if (uSize <= MEM_MAXSIZE) {
*((PPVOID) pMemory) =
*((PPVOID) ((PCHAR) MemStore + uSize));
*((PPVOID) ((PCHAR) MemStore + uSize)) =
pMemory;
}
else
free ((PCHAR) pMemory);
#if defined (__MEMTEST__)
ulMemUsed -= uSize;
#endif
#if defined (__PROTOCOL__)
printf ("MemDelete: %p (%d Bytes)\n",
pMemory, uSize);
#endif
} /* _MemDelete */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Dynamische Speicherverwaltung (3)

6.4 Automatische Differentiation


Mit Hilfe der automatischen Differentiation ist die
direkte numerische Berechnung des Wertes einer
Funktion und des Wertes ihrer (ersten) Ableitung
an einer gegebenen Stelle mglich.
Dazu kann hnlich den komplexen Zahlen ein Typ
GRADIENT als Zahlenpaar F = (f (x), f (x))|x=x0
erklrt werden mit folgenden Eigenschaften:
F = G+H : (f (x), f (x))|x=x0
= ((g + h)(x), (g + h) (x))|x=x0
= (g(x) + h(x), g (x) + h (x))|x=x0
analog fr , , /
F = GH : (f (x), f (x))|x=x0
= (g(h(x)), g (h(x)) h (x))|x=x0

TUHH

Rechenzentrum

F =c:

(f (x), f (x))|x=x0
= (c, 0)

F =x:

(f (x), f (x))|x=x0
= (x0, 1)

Einfhrung in C
Dirk Husung

Automatische Differentiation (1)

/******************************************
* Gradient.h: Automatische Differentiation
*******************************************/
#ifndef __GRADIENT__
#define __GRADIENT__
#include <stdio.h>
#include <math.h>
typedef struct {
DOUBLE x;
/* Wert
*/
DOUBLE dx;
/* Wert der 1. Ableitung */
} GRADIENT;
typedef GRADIENT * PGRADIENT;
GRADIENT Const (DOUBLE d);
GRADIENT Deriv (DOUBLE d);
GRADIENT
GRADIENT
GRADIENT
GRADIENT

Add
Sub
Mul
Div

(GRADIENT
(GRADIENT
(GRADIENT
(GRADIENT

a,
a,
a,
a,

GRADIENT
GRADIENT
GRADIENT
GRADIENT

b);
b);
b);
b);

GRADIENT Exp (GRADIENT a);


GRADIENT Sin (GRADIENT a);
GRADIENT Cos (GRADIENT a);
#endif /* !__GRADIENT__ */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Automatische Differentiation (2)

/******************************************
* Gradient.c: Automatische Differentiation
*******************************************/
#include "Portab.h"
#include "Gradient.h"
GRADIENT Const (DOUBLE d)
{
GRADIENT r;
r.x = d;
r.dx = 0.0;
return (r);
} /* Const */
GRADIENT Deriv (DOUBLE d)
{
GRADIENT r;
r.x = d;
r.dx = 1.0;
return (r);
} /* Deriv */
GRADIENT Add (GRADIENT a, GRADIENT b)
/* (a, a) + (b, b) = (a+b, a+b) */
{
GRADIENT r;
r.x = a.x + b.x;
r.dx = a.dx + b.dx;
return (r);
} /* Add */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Automatische Differentiation (3)

/* todo: Sub */
GRADIENT Mul (GRADIENT a, GRADIENT b)
/* (a, a) * (b, b) = (a*b, a*b+a*b) */
{
GRADIENT r;
r.x = a.x * b.x;
r.dx = a.dx * b.x + a.x * b.dx;
return (r);
} /* Mul */
/* todo: Div */
GRADIENT Exp (GRADIENT a)
/* exp (a, a) = (exp(a), exp(a) * a) */
{
GRADIENT r;
r.x = exp (a.x);
r.dx = exp (a.x) * a.dx;
return (r);
} /* Exp */
GRADIENT Sin (GRADIENT a)
/* sin (a, a) = (sin(a), cos(a) * a) */
{
GRADIENT r;
r.x = sin (a.x);
r.dx = cos (a.x) * a.dx;
return (r);
} /* Sin */
/* todo: Cos */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Automatische Differentiation (4)

#if defined (__MAIN__)


INT main (VOID)
/* Test: f(x) = x + exp (sin (2*x)) */
{
DOUBLE d;
for (d = 0; d < 3; d += 0.25) {
GRADIENT x = Deriv (d);
GRADIENT fx = Add (x,
Exp (Sin (Mul (Const (2), x))));
printf ("f(%4.2f) = %11.8f, "
"f(%4.2f) = %11.8f\n",
d, fx.x, d, fx.dx);
}
return (0);
} /* main */
#endif /* __MAIN__ */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Automatische Differentiation (5)

6.5 Aufruf von Fortran-Routinen aus C


Die Kopplung von f77- und C-Routinen ist z.B.
dann von Bedeutung, wenn man Programmbibliotheken, die in Fortran geschrieben sind (z.B. die
NAG-Bibliothek), von C aus benutzen mchte.
Die Form eines solchen Aufrufs ist jedoch compilerabhngig!
Allgemeine Hinweise:
Unterprogrammnamen
cc- und f77-Compiler von HP verwenden gleiche Namenskonventionen.
(Einige Fortran-Compiler hngen beim bersetzen jeweils einen Unterstrich an die Routinenamen an. Beim Aufruf einer f77-Routine von C
aus mu dann dieser Unterstrich angefgt werden.)
Datentypen
Es gibt folgende Korrespondenzen bei den wichtigsten Typen:
TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Aufruf von Fortran-Routinen aus C (1)

FORTRAN

INTEGER i
long int i;
REAL x
float x;
DOUBLE PRECISION s double s;
COMPLEX*8 z
struct {float re, im;} z;
COMPLEX*16 w
struct {double r, i; } w;
CHARACTER*6 c
char c[6];

Argumentbergabe
In Fortran werden Argument stets by reference bergeben. Hierbei erhlt das aufgerufene Unterprogramm die Adresse der bergebenen Variable.
In C hingegen werden Argumente stets by value bergeben. Das Unterprogramm erhlt nur
eine Kopie mit dem aktuellen Wert des Arguments, kann so jedoch nicht den Argumentwert
selbst verndern (hierzu mte die Adresse bekannt sein).
Um in C Adressen zu bergeben, benutzt man
den Operator & vor dem Variablennamen.
FORTRAN

INTEGER a, b, sum
int a, b, sum;
call add (a, b, sum) add (&a, &b, &sum);

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Aufruf von Fortran-Routinen aus C (2)

CHARACTER-Datentypen aus f77 entsprechen


Feldern in C; die Lnge des Feldes mu jedoch
in C zustzlich als ein long int bergeben
werden.
FORTRAN

CHARACTER*5 sss
char sss[5];
CHARACTER*8 tt
char tt[8];
call sub (sss, tt) sub (sss, tt, 5L, 8L);

Bei der bergabe mehrdimensionaler Felder ist


Vorsicht geboten, da diese in f77 spaltenweise,
in C hingegen zeilenweise gespeichert werden.
Die bergabe von Funktionen in der Argumentliste wird weiter unten an einem Beispiel demonstriert.
Ein-/Ausgabe
Fortran und C benutzen ein unterschiedliches
Ein-/ Ausgabesystem. Daher kann es zu Problemen fhren, wenn sowohl von C als auch von
Fortran aus Ein- oder Ausgaben vorgenommen
werden sollen.

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Aufruf von Fortran-Routinen aus C (3)

Beispiel:
/******************************************
* C-Programm: fprog1.c
*******************************************/
#include <stdio.h>
#if defined (HP)
#define SUBROUTINE(Name) Name
#elif defined (CONVEX)
#define SUBROUTINE(Name) Name_
#endif
float fkt (float *x);
void SUBROUTINE(fkt_uebergabe) (
float *x, float (*f)(float *), float *y);
int main(void)
{
float x=2.0; float y=0.0;
printf ("\n Funktionsname als Argument:\n");
SUBROUTINE(fkt_uebergabe) (&x, fkt, &y);
printf (" x= %g, fkt(x) = %g\n", x, y);
return (0);
}
/******************************************
* C-Programm: fprog2.c
*******************************************/
float fkt(float *x)
{
return(2.0* *x);
}

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Aufruf von Fortran-Routinen aus C (4)

C ----------------------------------------C f77-Unterprogramm: fprog3.f


C ----------------------------------------subroutine fkt_uebergabe(x, f, y)
external f
real f, x, y
y=f(x)
end

bersetzung auf hpxx und hydra mit:


cc -Aa -c -DHP fprog1.c
cc -Aa -c fprog2.c
f77 fprog1.o fprog2.o fprog3.f

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Aufruf von Fortran-Routinen aus C (5)

6.6 Tcl/Tk und C


Zu Tcl und Tk
Variablen:
set a
set b
set c
unset

1
a+2
[expr $a+2]
a

set Umsatz(Jan) 87966


set Umsatz(Feb) 95400
set GesamtUmsatz 0
foreach Monat {Jan Feb} {
incr GesamtUmsatz $Umsatz($Monat)
}
return $GesamtUmsatz

Ausdrcke:
expr 24/3.2
lindex {rot gelb blau lila} 2
string length "Dies ist ein Test"

Substitutionen:
Variablenersetzung
Befehlsersetzung
Backslash-Substitution

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Tcl/Tk und C (1)

Kontrollstrukturen:
eval
expr
if
elseif
switch
for
foreach
while

Prozeduren:
proc Potenz {Basis Exponent} {
set Ergebnis 1
while {$Exponent > 0} {
set Ergebnis [expr $Ergebnis*$Basis]
set Exponent [expr $Exponent-1]
}
return $Ergebnis
}

Innerhalb einer Prozedur sind alle Variablen lokal.

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Tcl/Tk und C (2)

Beispiele
Hello, World:
#!/usr/local/bin/wish -f
button .b -text "Hello, world!" -command exit
pack .b

Potenzberechnung:
#!/usr/local/bin/wish -f
proc Potenz {Basis Exponent} {
set Ergebnis 1
while {$Exponent > 0} {
set Ergebnis [expr $Ergebnis*$Basis]
set Exponent [expr $Exponent-1]
}
return $Ergebnis
}
entry .basis -width 6 -relief sunken\
-textvariable Basis
label .label1 -text "ist in der"
entry .exponent -width 6 -relief sunken\
-textvariable Exponent
label .label2 -text ". Potenz"
label .ergebnis -textvariable Ergebnis
pack .basis .label1 .exponent .label2\
.ergebnis -side left -padx 1m -pady 2m
bind .basis <Return> {
set Ergebnis [Potenz $Basis $Exponent]}
bind .exponent <Return> {
set Ergebnis [Potenz $Basis $Exponent]}

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Tcl/Tk und C (1)

Tcl/Tk und C:
/********************************************
* $Id: draw.c
Tcl/Tk-Beispiel
*********************************************/
#include <stdio.h>
#include <tcl.h>
#include <tk.h>
/********************************************
* Variablen-Definitionen
*********************************************/
static Tcl_Interp * interp;
/********************************************
* Prototypen lokaler Funktionen
*********************************************/
static void tcltkInit (
int nArgs, char * aArg []);
static void tcltkTerm (void);
static int drawLine (
int x0, int y0, int x1, int y1);
/********************************************
* Implementierung lokaler Funktionen
*********************************************/
static void tcltkInit (
int
nArgs,
char *
aArg [])
{
char * pArg;
char
ach [16];

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Tcl/Tk und C (2)

Tcl_FindExecutable (aArg [0]);


interp = Tcl_CreateInterp ();
pArg = Tcl_Merge (nArgs-1, aArg+1);
Tcl_SetVar (interp,
"argv", pArg, TCL_GLOBAL_ONLY);
Tcl_Free (pArg);
sprintf (ach, "%d", nArgs-1);
Tcl_SetVar (interp,
"argc", ach, TCL_GLOBAL_ONLY);
Tcl_SetVar (interp,
"argv0", aArg [0], TCL_GLOBAL_ONLY);
Tcl_SetVar (interp,
"tcl_interactive", "0", TCL_GLOBAL_ONLY);
if (Tcl_Init (interp) == TCL_ERROR) {
fprintf (stderr, "Tcl_Init: %s\n",
interp -> result);
exit (1);
}
if (Tk_Init (interp) == TCL_ERROR) {
fprintf (stderr, "Tk_Init: %s\n",
interp -> result);
exit (1);
}
Tcl_StaticPackage (interp,"Tk", Tk_Init, 0);
} /* tcltkInit */
static void tcltkTerm (void)
{
Tcl_DeleteInterp (interp);
Tcl_Exit (0);
} /* tcltkTerm */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Tcl/Tk und C (3)

static int drawLine (


int x0, int y0, int x1, int y1) {
char command [64];
sprintf (command,
".c create line %d %d %d %d",
x0, y0, x1, y1);
return Tcl_Eval (interp, command);
} /* drawLine */
/********************************************
* Hauptprogramm
*********************************************/
int main (int nArgs, char * aArg[])
{
tcltkInit (nArgs, aArg);
atexit (tcltkTerm);
Tcl_Eval (interp,
"canvas .c -width 640 -height 480");
Tcl_Eval (interp, "pack .c");
Tcl_Eval (interp,
"button .b -text \"Quit\" -command exit");
Tcl_Eval (interp, "pack .b");
Tcl_Eval (interp, "focus .c");
drawLine (10, 10, 200, 100);
while (Tcl_DoOneEvent (0))
;
return (0);
} /* main */

TUHH

Rechenzentrum

Einfhrung in C
Dirk Husung

Tcl/Tk und C (4)