Vorlesung 1 • • • • C Sprache Algorithmen Effektivität von Algorithmen Programme specifizieren, Algorithmen zu ausarbeiten, Quelltext generieren, dokumentieren Elektrotechnik • Kleine Klausuren: max. 6 P. (3 * 2P.) • Laboren(8-13 Wochen): max. 18 P. (6 * max. 3P.) • Hausaufgabe: max. 10 P. (Note * 2P.) • Grosse Klausur : max. 10 P. (Note * 2P.) • Zusammen: max. 44 P. Elektrotechnik 38 - 44 P. Note 5 32 - 37 P. Note 4 26 - 31 P. Note 3 20 - 25 P. Note 2 Informatik • Grosse Klausur: es soll einen Note 2 erreicht werden • Schriftliche Prüfung im Prüfungsperiod Informatik labor • 3 kleine Klausur • Hausaufgabe • Durchschnitt + od. - 1 • Vor C: Multics project—General Electric, MIT, und Bell Laboratory (1969) (kein Erfolg) – zu große OP System Bell Laboratory - Ken Thompson, Dennis Ritchie, Brian Kernighan – „UNIX” Ken Thompson – prog. Sprache B • BCPL und B sind typenlose Sprachen • C hat eine Reihe von Datentypen – Zeichen, ganze Zahlen, Gleitpunktzahlen – Es gibt eine Hierarchie von abgeleitete Datentypen (mit Hilfe von Zeigern, Vektoren, Strukturen und Unionen erzeugt) – Kontrollstrukturen, die für wohlstrukturierte Programme nötig sind: – Kontrollstrukturen, die für wohlstrukturierte Programme nötig sind: • Zusammenfassung von Anweisungen { } • Entscheidungen (if-else) • Auswahl von einem aus einer Menge von möglichen Fällen (switch) • Schleifen mit Test des Abbruchkriteriums am Anfang (while, for) • oder am Ende (do) • Vorzeitiges Verlassen einer Schleife (break) – Funktionen können Werte der elementare Typen, aber auch von Strukturen, Unionen oder als Zeigern als Resultat liefern. – Jede Funktion darf rekursiv aufgerufen werden – Die lokalen Variablen einer Funktion sind typischerweise „automatisch”, das heißt, sie werden bei jedem Aufruf der Funtion neu erzeugt werden – Funktionsdefinitionen können nicht verschachtelt werden, – Die Funktionen eines C Programms können sich in verschiedenen Quelldateien befinden, die getrennt voneinander übersetzt werden – Ein Preprozessor ersetzt Makros im Programmtext, fügt andere Quelldateien ein und ermöglicht bedingte Übersetzung – ANSI C standard 1988 – Definition einer Bibliothek, die zu C gehört • Funktionen zum Zugriff auf das Betriebsystem (Dateien zu lesen und schreiben) • Funktionen für formattierte Ein- und Ausgabe • Funktionen für Speicherverwaltung etc. #include <stdio.h> main() { printf(”hello, world\n”); } #include <stdio.h> int main() { int a,b,c; int summe; a = 1; b = 2; c = 3; summe = a+b+c; printf(”summe=%d \n”,summe); return 0; } • Arithmetische Operatoren binäre +, -, /, *, % unäre +, +, - (unären) • Vorrang *, / , % +, - (binären) arithmetische Operatoren werden von links her zusammenfaßt • Verbindung von arithmetische Operatoren c = a = d+e; von rechts her Datentypen • 4 elementare Datentypen char ein Byte, ein Zeichen – Grundelement des Speichers int ganzahliger Wert, 16 oder 32 Bits float ein einfach genauer Gleichpunktwert double ein doppelt genauer Gleichpunktwert Varianten dieser elementaren Typen • short int • long int das Wort int kann ausgelassen werden short und int haben wenigstens 16 Bits long hat mindestens 32 Bits short ist nicht länger als int int ist nicht länger als long Varianten dieser elementaren Typen • signed • unsigned char oder int (sind ≥ 0) • Wertebereich int -32768...32767 unsigned int 0...65535 float 3.4e-38...3.4e+38 double 1.7e-308...1.7e+308 long double 3.4e-4932...1.1e+4932 Konstanten • • • • • • • • ganzzahlige Kostante 1234 hat den Typ int long-Konstante 12345678l oder 12345678L vorzeichenlose Kostante 456u oder 456U 5789ul oder 5789UL unsigned long 036 oktal 0x36 oder 0X36 hexadezimal 0XFUL unsigned long mit Dezimalwert 15 Gleitpunktkonstanten 123.4 (enthalten einen Dezimalpunkt) oder 1e-2 (enthalten einen Exponenten) sind double • 113.6f oder 113.6F hat Typ float • 113.6l oder 113.6L hat Typ long double Elementare printf Umwandlungen Zeichen Argument; Ausgabe als d,i int; dezimale Zahl o int; oktale Zahl ohne Vorzeichen int; hexadezimale Zahl ohne Vorzeichen int; dezimale Zahl ohne Vorzeichen int; einzelnes Zeichen x, X u c • %d als dezimale ganze Zahl ausgeben • %6d als dezimale ganze Zahl ausgeben, mindestens 6 Zeichen breit • %f als Gleitpunktzahl ausgeben • %6f als Gleitpunktzahl ausgeben, mindestens 6 Zeichen breit • %.2f als Gleitpunktzahl ausgeben, 2 Zeichen hinter Dezimalpunkt (abgerundete Zahl) • %6.2f als Gleitpunktzahl ausgeben, 6 Zeichen breit und 2 Zeichen hinter Dezimalpunkt • float f = 1.23456789; • printf("f=%f \n",f); 1.234568 • printf("f=%15f \n",f); 1.234568 • printf("f=%-15f \n",f); 1.234568 • printf("f=%.3f \n",f); 1.235 • float f = 123.23456789; • printf("f=%f \n",f); 123.234566 • printf("f=%3.3f \n",f); 123.235 • printf("f=%15e \n",f); 1.232346e+002 • printf("f=%15.2e \n",f); 1.23e+002 Elementare printf Umwandlungen Zeichen Argument; Ausgabe als s char*; aus der Zeichenkette werden Zeichen ausgegeben double; [-]m.dddddd , wobei die Genauigkeit die Anzahl der d festlegt double; [-]m.dddddde±xx , wobei die Genauigkeit die Anzahl der d festlegt f e, E • zeile ist ”hello, world” Zeichenkette printf(”:%s:”,zeile); :hello, world: printf(”:%10s:”,zeile); :hello, world: printf(”:%.10s:”,zeile); :hello, wor: printf(”:%-15s:”,zeile); :hello, world : printf(”:%15.10s:”,zeile); : hello, wor: printf(”:%-15.10s:”,zeile); :hello, wor : • Vereinbarungen int i,j,k; double a,b; • Eine Variable kann bei ihrer Vereinbarung auch initialisiert werden double a = 1.3, b = 2.3; • Mit dem Attribut const kann bei der Vereinbarung einer Variablen angegeben werden, daß sich ihr Wert nicht ändert. const int a=3; dann a=a+1; /*ist falsch*/ • Das Komma Operator mehrere Zuweisungen kann verbindet werden int i,j,k; i = 3; j = 4; k = i, i = j; die Auswertung geht von links her Mathematische Bibliothekfunktionen • in <math.h> deklariert abs int abs(int) acos double acos(double) asin, atan, atan2 double atan2(double,double) atof, string to a floating point double atof(const char*) cabs, ceil(x), kleinster ganzzahliger Wert, der nicht kleiner als x ist cos, cosh, exp, fabs, floor(x), größter ganzzahliger Wert, der nicht größer als x ist log, log10, pow, sin, sinh, sqrt, tan, tanh long a; float f = 123.9; a=f; printf("a=%ld \n",a); a=123 long a; float f = 123.9; f=f-(a=f); printf("a=%ld \n",a); printf("f=%15.2e \n",f); a=123 f= 9.00e+002 Schleifen • for Schleife • while Schleife while (Ausdruck) Anweisungen • do while Schleife do Anweisungen while (Ausdruck); do while Schleife do Anweisungen while (Ausdruck); Anweisung(en) Ausdruck ≠ 0 Ausdruck Ausdruck = 0 Anweisungen werden durchgeführt bis Ausdruck bleibt von 0 verschieden j = 0; i = 4; do { j = j+i; i = i-1; } while (i>0); j = 0; i = 4; do { j = j+i; i = i-1; } while (i); j = 0; i = 4; do j = j+i; while (i = i-1); while Schleife while (Ausdruck) Anweisungen Ausdruck Ausdruck ≠ 0 Anweisung(en) Ausdruck = 0 Ist Ausdruck von 0 verschieden, so wird Anweisung ausgeführt und anshließend Ausdruck erneut bewertet i = 10; sum = 0; while (i>0) { sum=sum+i;i= i-1}; i = 10; sum = 0; while (i) { sum=sum+i;i= i-1}; for Schleife for (init;test;post-expr) statement; if else Anweisung if (Ausdruck) Anweisung1 else Anweisung2 Ausdruck ≠ 0 Ausdruck = 0 Ausdruck Anweisung1 Anweisung2 Ausdruck hat einen von 0 verschiedenen Wert, so wird Anweisung 1 ausgeführt. Bei 0 wird Anweisung 2 ausgeführt. Inkrement- und DekrementOperatoren • Der Inkrement-Operator ++ (addiert 1 zu seinem Operanden) • Der Dekrement-Operator -- (substrahiert 1) • Präfix-Notation ++n • Postfix-Notation n++ n = 5; n = 5; x = n++; /* x ist 5, n ist 6 */ x = ++n; /* x ist 6, n ist 6 */ b a b a N f ( x)dx f (a (i 1) ) i 1 b a / N #include <stdio.h> #include <math.h> int main() { int i,N=10; double a=1,b=2,del,x,sum,f,integral; del = (b-a)/N; sum = 0.0; for(i=1;i<=N;i=i+1) { x = a+del*(i-1); f = sin(x); sum = sum + f; } integral = sum*del; printf("Integral = %lf\n",integral); printf("Integral = %lf\n",-cos(b)+cos(a)); return 0; } Bedingter Ausdruck if (a>b) z = a; else z = b; z = (a>b)?a:b; Auch in Form Ausd1?Ausd2:Ausd3 Zuweisungen und Ausdrücke i = i+2; Ausdruck mit Zuweisungsoperator ( +=) i += 2; (+, -, *, /, %, <<, >>, &, |, ^) #include <stdio.h> #include <math.h> int main() { int i,N=10; double a=1,b=2,del,x,sum,f,integral; del = (b-a)/N; sum = 0.0; for(i=1;i<=N;i+=1) { x = a+del*(i-1); f = sin(x); sum += f; } integral = sum*del; printf("Integral = %lf\n",integral); printf("Integral = %lf\n",-cos(b)+cos(a)); return 0; } Operatoren • Vergleichsoperatoren == prüft auf Gleicheit ( a == b ) != prüft auf Ungleicheit ( a != b ) >, >=, <, <= • Verknüpfungen && AND (und-Verknüpfung) || OR (oder-Verknüpfung) ! NOT (Komplement; unär) Beispiel (a == b) && (c == d) || !(c == e) #include <stdio.h> int main() { int z1,nprim,i; z1=23; i=z1/2; nprim=0; while ((i>=2)&&(!nprim)) { if (z1%i==0) nprim=1; i--; } if (nprim) printf("Nicht Prim \n"); else printf("Prim \n"); return 1;} Die switch Anweisung Es ist eine Auswahl unter mehreren Alternativen Untersucht, ob ein Ausdruck einen von mehreren Konstanten ganzzahligen Werten besitzt. switch(Ausdruck){ case const-Ausdruck1:Anweisung1 case const-Ausdruck2:Anweisung2 default : Anweisung3 } i = 2; switch(i){ case 1: printf(”Montag”);break; case 2: printf(”Dienstag”);break; case 3: printf(”Mittwoch”);break; case 4: printf(”Donnerstag”);break; case 5: printf(”Freitag”);break; case 6: printf(”Sammstag”);break; case 7: printf(”Sonntag”);break; default : printf(”Fehler”); } Operatoren • Bit-Operatoren & Bit-AND | Bit-OR ^ Bit-XOR ~ Bit NOT >> Bitshift nach Rechts << Bitshift nach Links int i = 8; i = i >> 2; /* Dividierung mit 4 */ i= i << 2; /* Multiplizierung mit 4 */ Funktionen und Programmstruktur Funktionsdefinition Funktionstyp Funktionsname(Parameterdeklarationen) { Vereinbarungen und Anweisungen return Ausdruck } return-Anweisung liefert einen Wert als Resultat von der aufgerufenen Funktion zum Aufrufen double addiert(double a, double b) { return a+b; } void ausschreibt(double a) { printf(”%lf ”,a); } /*Funktion ohne Ausgangswert*/ #include <stdio.h> #include <math.h> double fv(double x) { return sin(x); } int main() { int i,N=10; double a=1,b=2,del,x,sum,f,integral; del = (b-a)/N; sum = 0.0; for(i=1;i<=N;i+=1) { x = a+del*(i-1); f = fv(x); sum += f; } integral = sum*del; printf("Integral = %lf\n",integral); printf("Integral = %lf\n",-cos(b)+cos(a)); return 0; } #include <stdio.h> #include <math.h> double fv(double x) { return sin(x); } int main() { int i,N=10; double a=1,b=2,del,x,sum,f,integral; del = (b-a)/N; sum = 0.0; for(i=1;i<=N;i+=1) sum += fv(a+del*(i-1)); integral = sum*del; printf("Integral = %lf\n",integral); printf("Integral = %lf\n",-cos(b)+cos(a)); return 0; } #include <stdio.h> #include <math.h> double fv(double x) { return sin(x); } int main() { int i,N=10; double a=1,b=2,del,x,sum,f,integral; del = (b-a)/N; sum = 0.0; for(i=1;i<=N;) sum += fv(a+del*(i++-1)); integral = sum*del; printf("Integral = %lf\n",integral); printf("Integral = %lf\n",-cos(b)+cos(a)); return 0; } #include <stdio.h> #include <math.h> double fv(double x) { return sin(x); } int main() { int i,N=10; double a=1,b=2,del,x,sum,f,integral; for(i=1,sum=0.0,del = (b-a)/N;i<=N;sum += fv(a+del*(i++-1))) ; integral = sum*del; printf("Integral = %lf\n",integral); printf("Integral = %lf\n",-cos(b)+cos(a)); return 0; } Zeiger und Vektoren Ein Zeiger ist eine Variable, die die Adresse einer Variablen enthält. & unäre Adress-Operator * Inhalts-Operator (indirection, dereferencing) int x = 1, y = 2; int *ip; ip = &x; y = *ip; *ip = 0; Zeiger und Vektoren Die Vereinbarung int a[10]; double v[25]; definiert einen Vektor mit 10 (25) Elementen, einen Block aus 10 (25) aufeinanderfolgenden Objekten, mit den Namen a[0] a[1] ... a[9] Zeiger und Vektoren Vereinbart man pa als Zeiger auf einen int Wert int *pa; dann zeigt pa durch die Zuweisung pa = &a[0]; auf das erste Element 0 von a; pa enthält die Adresse von a[0] Zeiger und Vektoren pa + 1 ist eine Zeiger auf das nachfolgende Element pa + i ist eine Zeiger auf das i-te Element nach (hinter) pa Statt a[i] auch *(a+i) geschrieben werden kann pa = &a[0]; equivalent mit pa = a; Zeigern als Funktionsargumente void tausch(int *px,int *py) { int temp; temp = *px; *px = *py; *py = temp; } in main() Funktion tausch(&a,&b); Zeigern als Funktionsargumente • Auswahl maximaler Element #include <stdio.h> #include <stdlib.h> int max(int *v,int g){ int maxwert = 0; if(g){ maxwert = v[0]; while(--g) if (v[g]>maxwert) maxwert = v[g]; } return maxwert; } int main() { int vekt[10],i; for (i=0;i<10;i++){ vekt[i] = rand(); } printf("%d \n",max(vekt,10)); return 0; } Char Zeiger ”konstante Zeichenkette” das ist ein Zeichenvektor der Vektor wird mit dem Nullzeichen ‘\0’ beendet char *Zeichenzeiger; Zeichenzeiger = ”Hallo”; char Zeichenpuffer[] = ”Hallo”; Zeichenzeiger: · Zeichenzeiger: · Zeichenpuffer: H a l l o \0 H a l l o \0 Char Zeiger int strlen(char *c) {int n; for(n = 0;*s!=‘\0’;s++) n++; return n; } int main(){ printf(”%d”,strlen(”Guten Tag”); Char Zeiger int strlen(char *c) {int n; for(n = 0;*s!=‘\0’;s++) n++; return n; } int main(){ char *Zeichenzeiger; Zeichenzeiger = ”Hallo”; char Zeichenpuffer[] = ”Hallo”; strlen(Zeichenpuffer); strlen(&Zeichenpuffer[]); strlen(Zeichenzeiger); strlen(Zeichenzeiger+2); strlen(Zeichenpuffer+2); void strcpy(char *s,char *t) {int i = 0; while (t[i]!=‘\0’) {s[i]=t[i];i++;} s[i]=t[i]; } void strcpy(char *s,char *t) {int i = 0; while ((s[i]=t[i])!=‘\0’) i++; } Type-Aliases (typedef) Mit typedef kann man ein Alias für einen existierenden Typ deklarieren: typedef existing-type new-type; Beispiele: typedef int INTEGER; typedef int bool; typedef unsigned int uint; Präzedenz und Bindung Englisch: „precedence” und „ associativity” („grouping”) Ohne diese ist ein Ausdruck der Art a+b*c nicht eindeutig Präzedenz: Reihenfolge der Auswertung der Operatoren Assoziativität: Reihenfolge bei Operatoren gleicher Präzedenz C preprozessor # include Definitionsdatei einfügen #include <filename> #include „filename” #define Textersatz Ersatztext #define Name Ersatztext #define sqr(x) x*x a = 2; c = sqr(a); → c = a*a; /* c wird 4 sein */ Ersatztext #define sqr(x) x*x a = 2; b = 3; c = sqr(a+b); → c = a+b*a+b; /* c wird 2+3*2+3=11 sein */ #define sqr(x) (x)*(x) c = sqr(a+b); → c = (a+b)*(a+b); Ersatztext #define sqr(x) (x)*(x) a = 1; b = 2; c = 9/sqr(a+b); → c = 9/(a+b)*(a+b); /* c wird 9/3*3=9 sein */ #define sqr(x) ((x)*(x)) Ersatztext #define ab(x) (x<0)?(-x):(x) #define max(a,b) (a)>(b)?(a):(b) Strukturen • eine Ansammlung von einer oder mehrerer Variablen (auch mit verschiedenen Typen) • unter einem einzigen Namen zusammenfassen struct point { double x; double y; }; Strukturen •das reservierte Wort struct steht am Anfang •Strukturvereinbarung – Liste von Deklarationen •Etikett – hier point •Etikett ist für Abkürzung für den Teil der Vereinbarung in geschweiften Klammern Strukturen struct point pt; •deklaration eine Variable pt, die eine Struktur vom Typ struct point ist. •Initialisieren von Strukturen struct point pt1 = {100,200}; Strukturen •Verweis auf eine Komponente einer bestimmten Struktur Struktur-Variablenname.Komponente struct point pt; pt.x = 150.5; Rekursion #include <stdio.h> void printzahl(int zahl) { if (zahl<0){ putchar('-'); zahl = -zahl; if (zahl/2) printzahl(zahl/2); putchar(zahl % 2 +'0'); } int main() { int i = 32; printzahl(i); printf("\n"); return 0; } } Argumente aus der Kommandozeile • Wenn main aufgerufen wird, werden zwei Argumente Übergeben • argc für argument count • argv für argument vector argv[0] der Programmname argv[1] das erste Argument argv[argc-1] das letzte Argument hat argc den Wert 1, gibt es keine Argumente auf der Kommandozeile #include <stdio.h> int main(int argc,char *argv[]) { int i,j; for (i=1;i<argc;i++) { j=0; while(argv[i][j])putchar(argv[i][j++]+'A'-'a'); } return 0; }