Einführung in die Programmiersprache C 5.Tag Institut für Mathematische Optimierung - Technische Universität Braunschweig
Zeichenketten Zeichenketten (Strings) werden in C als Felder von Zeichen (char) realisiert. Das Ende wird durch das Zeichen 0 markiert. Die Zeichenkette „Wort" ist also fünf Zeichen lang: Die Länge einer Zeichenkette kann so bestimmt werden: int len; char *str;... len = 0; while (str[len]!=0) { len++; }
Ersetzen von Buchstaben Möchte man alle ’a’ durch ’b’ ersetzen, geht das so: char *str, *p;... for (p=str; *p!=0; p++) { if (*p==’a’) *p==’b’; } Institut für Mathematische Optimierung – Technische Universität Braunschweig
Lexikographischer Vergleich Ein lexikographischer Vergleich ist so umsetzbar: char *str1, *str2; int i;... for (i=0; ; i++) { if (str1[i]<str2[i]) /* "str1 < str2" */ if (str1[i]>str2[i]) /* "str1 > str2" */ if (str1[i]==0) /* "str1 == str2" */ } Institut für Mathematische Optimierung – Technische Universität Braunschweig
String.h Zur Bearbeitung von Zeichenketten stellt die Standardbibliothek string.h diverse Funktionen zur Verfügung. Beispiele: int strcmp(char *s1,char *s2) Vergleicht zwei Strings lexikographisch. Ergebnis : 0 (wenns1 größer als s2). int strncmp(char *s1,char *s2, int n) Vergleicht zwei Strings lexikographisch, berücksichtigt höchstens die ersten n Stellen. Institut für Mathematische Optimierung – Technische Universität Braunschweig
String.h int strlen(char *s) Bestimmt die Länge eines Strings (ohne Zeichen '0'). char* strcpy(char* ziel, char* quelle) Kopiert den String aus quelle nach ziel. char* strncpy(char* ziel, char* quelle,int n) Kopiert den String aus quelle nach ziel, jedoch höchstens n Zeichen. char* strcat(char* ziel, char* quelle) Kopiert den String aus quelle an das Ende von ziel (Zeichen '0' von ziel wird überschrieben). Institut für Mathematische Optimierung – Technische Universität Braunschweig
String.h char *strchr(const char *text, int a) Bestimmt Zeiger auf erstes Vorkommen des Zeichens a im String text oder auf NULL, falls a nicht in text enthalten. char *strrchr(const char *s, int a) Wie zuvor, nur letztes Vorkommen. char *strstr(char *text, char *wort) Wie zuvor für Teilstring wort. Institut für Mathematische Optimierung – Technische Universität Braunschweig
sprintf und sscanf Analog zu printf(), scanf(), fprintf() und fscanf() gibt es auch sprintf() und sscanf(). Sie schreiben die Ausgabe in einen String bzw. lesen die Daten aus einem String. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Beispiel mit sprintf char fname[64]; int i; FILE* f;... for (i = 1; i <= 100; i++) { sprintf(fname,"datei%i.txt",i); f = fopen(fname,"w");... }
ctype.h Die Funktionen aus ctype.h dienen zum Kategorisieren von Zeichen. Auswahl der Funktionen (Rückgabewerte: 1 für wahr, 0 für falsch): I.int isalnum(int c)alphanumer. Zeichen(a-z,A-Z,0-9)? II.int isalpha(int c)Buchstabe (a-z, A-Z)? III.int isblank(int c)Leerzeichen? IV.int iscntrl(int c)Steuerzeichen (\n, \t,…)? V.int isdigit(int c)Dezimalziffer (0-9)? VI.int islower(int c)Kleinbuchstabe (a-z)? VII.int ispunct(int c)druckbares Interpunktionszeichen? VIII.int isspace(int c)Zwischenraumzeichen (Leerzeichen, \n, \t,…)? IX.int isupper(int c)Grossbuchstaben (A-Z)?
Beispiel (1. Teil) … char name[128], *p; int ok; do { printf("Geben Sie Ihren Namen ein:"); scanf("%s",&name); ok = 1; Institut für Mathematische Optimierung – Technische Universität Braunschweig
Beispiel (2. Teil) for (p=name; *p != 0; p++) { if (!isalpha(*p)) { printf("unerlaubtes Zeichen ’%c’\n",*p); ok = 0; } }while(!ok); … Institut für Mathematische Optimierung – Technische Universität Braunschweig
Konstante Variablen Das Schlüsselwort const vor einer Variablendeklaration verbietet ein Verändern dieser Variable. Beispiel: const int i; i = 17; erzeugt einen Kompilerfehler. Gleiches gilt für call-by- reference Parameter von Funktionen: void fkt(const int *p) { *p = 17; }
Konstante Variablen Variablen dürfen als konstante Parameter übergeben werden: int i;... fkt(&i); … void fkt(const int *p) { printf("%i",*p); }
Konstante Variablen Konstante Variablen dürfen nicht als variable Parameter übergeben und dann verändert werden: const int i;... fkt(&i); … void fkt(int *p) { *p = 5; }
Aufzählungstypen In C können Aufzählungstypen, d.h. Datentypen mit endlich vielen Werten definiert werden. Beispiel: enum tag{montag, Dienstag, mittwoch}; definiert den Datentyp enum tag. Anwendung: enum tag t1, t2;... t1=mittwoch; t2=t1; if (t2==montag) {...}
Union Eine union ähnelt dem bereits bekannten struct, es kann jedoch nur eines der definierten Elemente verwendet werden. Beispiel: union student { int matrikel; char name; float note; }; Die Elemente matrikel, name und note benutzen den gleichen Speicherbereich. Beim struct hätte jedes Element einen eigenen Speicherbereich. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Union int main(void) { union student s1; s1.matrikel=5478; printf("matr.nr.: %d\n",s1.matrikel); s1.note=2.7; printf("matr.nr.:%d\nnote:%.2f\n",s1.matrikel,s1.note); return 0; }Führt zu einer zufälligen Ausgabe von s1.matrikel.
Deklaration mit inline Kurze Funktionen können als inline deklariert werden, um die Geschwindigkeit zu steigern. Dadurch wird keine echte Funktion erzeugt, sondern die Funktion wird an den nötigen Stellen eingefügt. Anwendung: inline int max(int a,int b) { return (a<b) ? : a : b; } Bemerkung: Besser als Makros definieren (später). Institut für Mathematische Optimierung – Technische Universität Braunschweig
Der Präprozessor Das Kompilieren eines C-Programms erfolgt (logisch) in mehreren Schritten, der erste ist der Präprozessor. Die Präprozessor-Anweisungen beginnen mit #. Wir kennen bereits: #include Um eine Datei aus dem aktuellen Verzeichnis einzubinden, verwendet man: #include "dateiname" Institut für Mathematische Optimierung – Technische Universität Braunschweig
Konstanten Über: #define PI double kreisflaeche[radius]; wird eine Konstante PI definiert. Der Funktion kreisflaeche braucht nur noch die Variable radius übergeben werden. Die Namen der Konstanten bestehen üblicherweise aus Großbuchstaben. Dabei können auch kompliziertere Konstrukte verwendet werden: #define PI2 ( * ) Institut für Mathematische Optimierung – Technische Universität Braunschweig
Konstanten Achtung: Konstanten werden einfach an den verwendeten Stellen eingesetzt. Dies kann zu Fehlern führen: #define N printf("%i\n",2*N); Gibt 3 aus, nicht 4. Das gewünschte Ergebnis erreicht man mit: #define N (1+1) Institut für Mathematische Optimierung – Technische Universität Braunschweig
Makros Bei diesen Definitionen können auch Parameter angegeben werden, dadurch entstehen Makros: #define MAX(a,b) ((a>b) ? a : b)... int imax,i1,i2; float fmax,f1,f2;... imax = MAX(i1,i2); fmax = MAX(f1,f2); Da die Ausdrücke einfach ersetzt werden, findet kein Funktionsaufruf statt und das Makro ist unabhängig vom verwendeten Datentyp. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Beispiel #define MAX(a,b) ((a>b) ? a : b) double langsam(double);... printf("%lf\n",MAX(langsam(1.3),langsam(2.2))); Hier wird die Funktion langsam() dreimal ausgeführt. Definiert man das Makro als inline-Funktion passiert dies nicht. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Bedingte Kompilierung Quellcode, der hinter #if steht, wird nur übersetzt, falls die if-Bedingung erfüllt ist. Dieses muss beim Kompilieren überprüfbar sein. Außerdem muss jedes #if mit einem #endif abgeschlossen werden. Beispiel: #define K 1... int var=0; … #if (K==1) var++; #endif
Bedingte Kompilierung Zudem darf die Bedingung von #if nur aus konstanten Integerausdrücken bestehen, also nicht wie folgt aussehen: #define K int var=0; … #if (K==1.1) var++; #endif
Bedingte Kompilierung Es gibt auch eine #else-Anweisung: #if (K==1) var++; #else var--; #endif Nützlich zur Fehlersuche: __LINE__ wird durch die Zeilenummer im Quelltext ersetzt. Mit: printf("%i\n",__LINE__); kann man überprüfen, ob das Programm die entsprechende Zeile erreicht und so Fehler lokalisieren. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Aufteilen von Programmen Bei großen Programmen verteilt man die Funktionen auf verschiedene Dateien. Diese werden zuerst einzeln zu Objektdateien (*.o unter Linux) kompiliert und dann zum Programm verbunden (gelinkt). gcc -Wall -c main.c erzeugt die Objektdatei main.o (analog: ausgabe.c). Mit: gcc -Wall main.o ausgabe.o -o programm werden zwei Objektdateien zu einem ausführbaren Programm gelinkt. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Aufteilen von Programmen Vorteile: Es müssen nur die veränderten Dateien neu kompiliert werden (Zeitgewinn) und die Funktionen werden modularisiert. Damit Funktionen, Strukturen und Makros in anderen Dateien verwendet werden können, erzeugt man eine Headerdatei (*.h) in der die Prototypen und Definitionen enthalten sind. Diese wird dann mittels: #include "dateiname.h" in jede Datei einzeln eingebunden. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Aufteilen von Programmen Funktionen und globale Variablen, die nur innerhalb einer Datei verwendet werden, sollten dort als statisch definiert werden: static int hilfsfunktion(int x, float y) {...} static int globale_variable; Dies vermeidet Namenskonflikte. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Aufteilen von Programmen Globale Variablen, die in mehreren Dateien benutzt werden, können neben der Datei, in der sie zum ersten Mal deklariert werden, in den anderen Dateien über den Zusatz extern deklariert werden. int var=0;/*Deklaration und Initiali- sierung in erster Datei*/ extern int var;/*Deklaration danach*/ Institut für Mathematische Optimierung – Technische Universität Braunschweig
Das Programmierwerkzeug Make Um das teilweise Neukompilieren zu automatisieren dient unter Linux/Unix das Programm make. Welche Dateien neu kompiliert und welche zusammen gelinkt werden, muss in einer Datei Makefile angegeben werden. Der logische Aufbau sieht dabei wie folgt aus: Ziel: Abhaengigkeiten Befehl Institut für Mathematische Optimierung – Technische Universität Braunschweig
Beispiel zu make Beispiel: programm: main.o ausgabe.o gcc -Wall -o programm main.o ausgabe.o main.o: main.c inhalt.h gcc -Wall -c main.c ausgabe.o: ausgabe.c inhalt.h gcc -Wall –c ausgabe.c Institut für Mathematische Optimierung – Technische Universität Braunschweig
Das Programmierwerkzeug Make Achtung: Vor der Kompileranweisung muss ein Tabulatorzeichen stehen, nicht acht Leerzeichen. Die Anweisung: make programm oder einfach: make erzeugt das ausführbare Programm. Dabei werden Abhängigkeiten und Änderungsdaten der Dateien geprüft. make main.o würde nur die Objektdatei main.o neu erzeugen. Institut für Mathematische Optimierung – Technische Universität Braunschweig
Makros Um sich das Leben etwas zu vereinfachen, kann man auch durch Setzen von Makros die Schreibarbeit sparen: CC=gcc # Compiler CFLAGS=-Wall -ansi # Compiler-Schalter OBJFILES= main.o ausgabe.o programm: $(OBJFILES) $(CC) -o programm $(OBJFILES) main.o: main.c $(CC) $(CFLAGS) -c main.c ausgabe.o: ausgabe.c $(CC) $(CFLAGS) –c ausgabe.c