Mikrorechentechnik 1 Einführung in die Programmiersprache C - Professur für Prozessleittechnik Wintersemester 2010/2011
←
→
Transkription von Seiteninhalten
Wenn Ihr Browser die Seite nicht korrekt rendert, bitte, lesen Sie den Inhalt der Seite unten
Fakultät Elektrotechnik und Informationstechnik, Professur für Prozessleittechnik Mikrorechentechnik 1 Einführung in die Programmiersprache C Professur für Prozessleittechnik Wintersemester 2010/2011
Überblick • Teil 1 – Variablen und Ausdrücke – Schlüsselwörter, Kommentare – Vereinbarung von Variablen – Ausdrücke und Operatoren • Teil 2 – Programmsteuerung – Bedingungen, Schleifen, Funktionen • Teil 3 – Datenstrukturen – Felder, Zeiger – Strukturen, dynamische Listen
Weiterführende Literatur • Bücher – Zeiner, K. (2000) Programmieren lernen mit C.. München: Hanser – Schellong, H. (2005) Moderne C-Programmierung. Berlin: Springer – Erlenkötter, (2003) C-Bibliotheksfunktionen sicher anwenden. Reinbeck: Rowohlt – Kerningham,B., & Ritchie, D. (1983/1990) Programmieren in C. München: Hanser • WikiBooks – http://de.wikibooks.org/wiki/C-Programmierung – http://de.wikibooks.org/wiki/C_Sprachbeschreibung
Entwicklung 1969-1974 Entwicklung Bell Labs (Ritchie) 1978 Kerningham & Ritchie: The C Programming Language: K&R-Standard 1983 Deutsche Übersetzung K&R 1989 Standardisierung ANSI-C (C89) 1990 Übernahme in ISO/IEC 9899:1990 (C90) 1999 Überarbeitung ISO/IEC 9899:1999 (C99) http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf
Warum beschäftigen wir uns mit C? • Zielsystem eingebettete Systeme – Geringer Overhead gewünscht – Hardwarenahe Programmierung: Direktes Ansprechen von Speicher und Peripherie – Portierbarkeit • Nachteile Assembler: – Programmierung mit prozessorabhängigem Befehlssatz und Adressierungsarten – Richtige Interpretation von Speicherinhalten in der Verantwortung des Programmierers
Stärken von C (1/2) • Minimalistischer Sprachumfang – Der kleinste bekannte C-Compiler besteht aus 3742 Bytes C-Code und kann sich selbst kompilieren. • Hardwarenahe Programmierung, – direkter Umgang mit Bits, Bytes, – direkter Speicherzugriff über Zeiger (=Adressen) – Zeigerarithmetik (für die effiziente Behandlung von Feldzugriffen) • Dynamische Zeiger auf Funktionen – (Funktionszeiger) in Datenstrukturen speicherbar – flexible Modularisierungskonzept
Stärken von C (2/2) • C-Library – komplexe Funktionen in standardisierten Bibliotheken für viele Architekturen verfügbar. • Präprozessor – Spracherweiterung: Lesbarkeit! – Bedingte Übersetzung: Portabilität. • Optimierende C-Compiler – für nahezu jede Prozessorarchitektur. • Optimierte Embedded Controller – Auf C zugeschittene Befehlssätze / Adressierungsarten.
Schwächen von C (1/2) • Eingeschränktes Modulkonzept – Mit von .c und .h-Dateien notdürftig implementierbar • „schwache“ Typsicherheit • "Wilde" Zeiger: – Nicht initialisierte Variablen möglich • Probleme mit Feldern – Kein Schutz vor Überlauf
Schwächen von C (1/1) • Lücken in der Sprachdefinition – Abhängigkeit von Interpretation durch Compilerhersteller • Niedriger Abstraktionsgrad – Portabilitätsprobleme beim Umstieg von 32 auf 64Bit
Elemente der Programmiersprache C • Ziele der Erfinder: – Einfach, – maximale Flexibilität, – leichte Portierbarkeit • Komponentenkonzept: – Minimaler Sprachkern + – Präprozessor + – C-Bibliothek für Standardaufgaben + – ( weitere benutzerspezifische Bibliotheken)
Komponente Sprachkern • Prozedurale (imperative) Programmiersprache mit typisierten Variablen • Zeiger (=Adressen) und Zeigerarithmetik • Programmflusskontrolle • Komplexe benutzerdefinierte Datenstrukturen • unabhängig von Befehlssatzarchitektur !
Komponente Präprozessor • Direktiven für die Automatisierung von „Textbausteinen“ • Einbinden von Quelldateien #include • Textersetzung (Konstanten, Definitionen, Makros) #define … • Bedingte Übersetzung #if defined(UNIX) || defined(CYGWIN)
Komponente Bibliothek • Standardbibliothek mit Basisfunktionen zur Interaktion mit Betriebssystem und Peripherie – Ein-/Ausgabe, – Dateihandling, – Zeichenkettenverarbeitung, – Mathematik, – Speicherreservierung, – ... • ( + Vielzahl von kommerziellen sowie freien Funktionssammlungen )
Vom Quellcode zum Programm • Programm erstellen – Editieren, z.B. mit gedit, eclipse/cdt – Ergebnis: Datei hallo.c • Übersetzen (Compiler) – gcc -g -c hallo.c – Ergebnis: Objektdatei hallo.o • Binden mit C-Library (Linker) – gcc -o hallo hallo.o – Ggf. weitere Funktionsbibliotheken: -lm – Ergebnis: Ausführbare Datei hallo
C ist EINFACH! Der Sprachkern von C besteht aus sehr wenigen Schlüsselwörtern, Punktuatoren und Operatoren. – 31 Schlüsselwörter – etwa 50 Punktuatoren wie () , ; – etwa 50 Operatoren wie + - * > < Das Strukturierungselement für Programme ist die Funktion Jedes ausführbare Programm wird mit der Funktion main gestartet
Funktionsdefinition Jede Funktionsdefinition (auch main) folgt im wesentlichen folgender Syntax: Rückgabetyp FktName(Argumentliste) // Fkt.Kopf { Variablenvereinbarung Anweisung return Rückgabewert; }
MRT1-003-C 00_Hallo Hallo: Vergleich Assembler - C /* Hallo in C */ ; Hallo in NASM #include segment .data m: DB "Hallo",10,0 char *m = "Hallo\n"; segment .text int main() extern printf { global main printf(m); main: return 0; push m call printf } add esp, 4 mov eax, 1 ret
Schlüsselwörter (1) 9 SW für elementare 2 SW für zusammen- Datenobjekte gesetzte Datenobjekte struct char union short/int/long float/double 1 SW für die Größe von signed/unsigned Datenobjekten enum sizeof
Schlüsselwörter (2) Speicherklasse von Programmablauf Objekten if / else auto while register for static do (do … while) extern switch Typqualifizierung von case, default Objekten break const continue volatile goto return
C ist EINFACH! 31 Schlüsselwörter char, short, int, long, float, double, signed, unsigned, enum, struct, union, sizeof, typedef, auto, register, static, extern, const,volatile, if, else, while, for, do, switch, case, default, break, continue, goto, return Die üblichen Operatoren wie + - * / = > < & | . [] ? u.s.w Einige Punktuatoren wie { } () , ; Leerzeichen
C ist nicht immer leicht LESBAR • C „versteckt“ die Komplexität in den Operatoren und deren Kombinationsmöglichkeiten • Je nach Kontext haben gleiche Buchstaben sehr unterschiedliche Bedeutung * 1. Multiplikation, 2. Dereferenzierung von Zeiger > 1. Relation (Größer), 2. Im Kontext >> Shift Right-Operation, 3. Im Kontext -> Verweis auf ein Element einer Struktur deren Adresse wir kennen
C ist EFFIZIENT • Strukturen, Zeiger und Zeigerarithmetik erlauben effiziente Programme (die allerdings oft schwer zu verstehen sind) • Beispiel Kopiere von einer Zeichenkette zur anderen: void strcpy(char* srcPtr,char* dstPtr) { while(*dstPtr++=*srcPtr++) ; } • Eine Vielfalt von Funktionssammlungen steht zur Verfügung.
Die hohe Kust der C-Programmierung • Einstieg leicht möglich, das erste Programm ist schnell geschrieben (z.B. diese Vorlesung) • Aber: Das Schreiben portabler (8/16/32/64Bit), sicherer (Überlauf, Zeiger) und lesbarer (von Menschen) Programme ist nicht trivial!
Fakultät Elektrotechnik und Informationstechnik, Professur für Prozessleittechnik Teil1 – Datentypen, Identifier, Operationen und Ausdrücke • Zeichensatz, Kommentare • Identifier (Namen) • Datentypen • Ausdrücke • Operationen
Zeichensatz • Buchstaben: a b c … z A B C … Z • Ziffern: 0 1 2 3 4 5 6 7 8 9 • Sonderzeichen: ! " # % & ' ( ) * + , - . / : ; < = > ? [ ] \ ^ _ { | } ~ • Trennzeichen: Leerzeichen, Tabulator, Zeilenvorschub • Achtung: Programmcode ist ein 1-dimensionaler Strom aus Tokens
Kommentare • Fängt mit /* an, hört mit */ auf – Verschachtelung NICHT möglich – Ausweg #if 0 ... #endif • Seit C99 Zeilenkommentare wie in C++ oder Java: • Fängt mit // an, hört mit Zeilenvorschub auf
Identifier=Namen von Variablen und Funktionen • Fangen mit einem Buchstaben an (a-zA-Z) • Danach sind auch Zahlen und Unterstriche erlaubt • Unterstriche können vor dem ersten Zeichen stehen – Vorsicht: reserviert für interne Identifier der Bibliotheken! • Dürfen keine Schlüsselworte sein • Variablen müssen vor Verwendung deklariert sein. – Unterschied zu Java/C++: In C müssen die Variablenvereinbarung vor der ersten Anweisung des Blocks stehen.
MRT1-003-C 01_Datentypen Datentypen • Zeichen char • Kleine Ganzzahl short • Ganze Zahl int • Große Ganzzahl long Ganzzahlen und Zeichen können als signed/unsigned spezifiziert werden (wichtig für Vorzeichenbehandlung) • Gleitkommazahl float • mit doppelter Genauigkeit double • Ab C99: long long, long double
Ausdrücke und Operatoren • Zuweisungsausdruck Speicherstelle = Ausdruck • Arithmetische Ausdrücke Ausdruck Operator Ausdruck ( Ausdruck ) • Arithmetische Operatoren + - * / Addition, Subtr., Mult., Division % Modula (Rest der Ganzzahldivision)
Kombinierte Zuweisungsoperatoren • Häufig wird Ergebnis einer Operation in einer beteiligten Variable abgelegt Variable = Variable Operator Ausdruck Variable += Ausdruck Variable -= Ausdruck Variable *= Ausdruck Variable /= Ausdruck Variable %= Ausdruck
Logische Ausdrücke (1) • Gleichheit Ausdruck == Ausdruck Ausdruck != Ausdruck • Relation Ausdruck < = > Ausdruck • Logische Verknüpfung (nur für Ganzzahltypen) ! Ausdruck Ausdruck || Ausdruck Ausdruck && Ausdruck
Logische Ausdrücke (2) • Bis C99 gibt es keinen Wahrheitswert (bool, booolean) – Wahr: Alle Werte ungleich 0 – Falsch: 0 • Achtung: Ergebnis eines logischen Ausdrucks ist vom Typ int – Wahr = 1
Vorgriff: Vollständige Vorrangregelungen • Auswertung normalerweise von links nach rechts (Leserichtung!), Ebenen mit (←) rechts nach links: Ebene 1: ( ) [ ] -> . Ebene 2 (←):! ~ + - (type) sizeof ++ -- * & Ebene 3: * / % Ebene 4: + - Ebene 5: < = > Ebene 6: == != Ebene 7: && Ebene 8: || Ebene 9(←): = += -= *= /= %=
Vereinfachte Vorrangregelungen: • Auf gleicher Ebene (wenn nicht anders angegeben) erfolgt die Auswertung der Operatoren von links nach rechts: Ebene 1: ( ) Ebene 2: unär ! + - (rechts nach links) Ebene 3: * / % Ebene 4: + - Ebene 5: < = > Ebene 6: == != Ebene 7: && Ebene 8: || Ebene 9: = += -= *= /= %= (rechts nach links)
MRT1-003-C 03_Ausdruck Beispiel Auswertung 1 + 4 * 2 / ( 3 + 1 ) • Ebene 1: ( ) – (3+1) wird als eigenständiger Ausdruck behandelt und kann „parallel“ zu den anderen berechnet werden • Ebene 3: * / % – 4 * 2 / (...) , Auswertung von links nach rechts – ( 4 * 2 ) / (...) • Ebene 4: + - – 1 + (...)
Typumwandlung (1) 1) int-Promotion – Wenn Wertebereich von int ausreicht, IMMER Umwandlung nach int (= „Natürliche“ Größe der Plattform) 2) Umwandlungen, die den Wertebereich nicht beschneiden, sind wert- und vorzeichenerhaltend 3) Wandlung auf den Typ des Nachbaroperators, wenn größerer Wertebereich oder ranghöher • char, short, int, long, (float), double, long double
MRT1-003-C 03_Ausdruck Implizite Typumwandlung (2) • char und short werden in int umgewandelt, float in double A) Ist danach einer der beiden Operanden vom Typ double, so wird der andere ebenfalls nach double gewandelt und das Ergebnis ist vom Typ double B) Ist danach einer der beiden Operanden vom Typ long, so wird der andere ebenfalls nach long gewandelt und das Ergebnis ist vom Typ long
Implizite Typumwandlung (3) C) Ist einer der beiden Operanden vom Typ unsigned, so wird der andere ebenfalls nach unsigned gewandelt und das Ergebnis ist vom Typ unsigned • Trifft keiner der Fälle A,B,C zu, sind beide Operanden und das Ergebnis vom Typ int • Wenn anderes Verhalten gewünscht wird, ist ein expliziter Type-Cast notwendig: ( type ) Ausdruck
MRT1-003-C 03_Ausdruck Erweiterte Vorrangregelungen (unvollständig) • Auf gleicher Ebene (wenn nicht anders angegeben) erfolgt die Auswertung der Operatoren von links nach rechts: Ebene 1: ( ) Ebene 2: unär ! + - (type) (rechts nach links) Ebene 3: * / % Ebene 4: + - Ebene 5: < = > Ebene 6: == != Ebene 7: && Ebene 8: || Ebene 9: = += -= *= /= %= (rechts nach links)
Fakultät Elektrotechnik und Informationstechnik, Professur für Prozessleittechnik Teil 2: Steuerung des Programmflusses • Sequenz • Wiederholung • Bedingte Ausführung
Programmfluss • Lineare Sequenz von Instruktionen + • Konstrukte zur Wiederholung, Auswahl, und hierarchischen Strukturierung (Funktion) Programmiersprache C • Sequenz: Liste von Befehlen, Blöcke • Wiederholung: while, do…while, for • Auswahl: if … else if … else, switch … case • Funktionsdefinition und -vereinbarung
Sequenzen und Blöcke • Sequenz = Liste von durch SEMIKOLON getrennten Anweisungen (statement) • Block = Zusammenfassung einer Sequenz durch geschweifte Klammern { }. – wird von „außen“ wie eine Anweisung gesehen (wichtig für Wiederholung und Auswahl). – kann lokale Variablen enthalten, die nur im Block bekannt sind. – { Vereinbarung Statement }
Wiederholung einer Anweisung • Kopfgesteuerte (abweisende) Schleife while ( Ausdruck ) Anweisung • Fußgesteuerte (annehmende) Schleife do Anweisung while ( Ausdruck ) • For-Schleife for (Ausdruck1;Ausdruck2;Ausdruck3) Anweisung
For Schleife for (Ausdruck1;Ausdruck2;Ausdruck3) Anweisung • Ausdruck1: Initialisierung Kontrollvariable(n) • Ausdruck2: Testen Abbruchbedingung • Ausdruck3: Änderung Kontrollvariable(n) • Kurzform für: Ausdruck1; while (Ausdruck2) { Anweisung Ausdruck3; }
Bedingte Programmausführung: If … else • Bedingte Ausführung if ( Ausdruck ) Anweisung • .. mit Alternative(n) if ( Ausdruck ) Anweisung else if ( Ausdruck ) Anweisung else Anweisung
Bedingter Ausdruck • If … Else ist Anweisung, oft will man aber in Abhängigkeit von einer Bedingung das Ergebnis von zwei verschieden Ausdrücken haben (ohne Zwischenvariable) Ausdruck1 ? Ausdruck2 : Ausdruck3 • Beispiel erg = a1 ? a2 : a3; • Entspricht in etwa (warum nur „in etwa“?) if (a1) erg=a2; else erg=a3;
Fakultät Elektrotechnik und Informationstechnik, Professur für Prozessleittechnik Teil 3: Komplexe Daten • Felder und Matrizen • Struktur und Union • Zeiger
Feld • Zusammenfassung einer definierten Anzahl GLEICHARTIGER Datensätze zu einer Einheit • Minimal notwendige Operation: Auswahl eines bestimmten Datensatzes über einen Index
Eindimensionale Felder • Vereinbarung eines Felds analog Elementarobjekte typ identifier [ PositiveGanzzahl ]; • Elemente werden im Speicher in aufsteigender Reihenfolge angelegt • Zugriff erfolgt durch []-Operator, Indizierung beginnt mit 0!!!! identifier[Ausdruck] = wert; wert = identifier[Ausdruck];
Mehrdimensionale Felder • Vereinbarung typ identifier[PosGanzzahl][PosGanzzahl]...; • Elemente werden im Speicher in aufsteigender Reihenfolge angelegt • Letzter Index „wandert“ zuerst • Indizierung beginnt mit 0!!!! Zugriff erfolgt durch identifier[Ausdruck][Ausdruck]…;
MRT1-003-C 10_vector Initialisierung von Feldern • Deklaration mit Initialisierung: type identifier[zahl] = { Liste }; • Elemente werden mit KOMMA getrennt, • Liste muss nicht vollständig sein, nicht erfasste Elemente werden mit 0 initialisiert • Für mehrdimensionale Felder Verschachtelung von Listen : int a[2][3] = { {1, 2, 3}, {4, 5, 6} }
Erweiterte Vorrangregelungen (unvollständig) • Auf gleicher Ebene (wenn nicht anders angegeben) erfolgt die Auswertung der Operatoren von links nach rechts: Ebene 1: ( ) [ ] Ebene 2: unär ! + - (type) (rechts nach links) Ebene 3: * / % Ebene 4: + - Ebene 5: < = > Ebene 6: == != Ebene 7: && Ebene 8: || Ebene 9: = += -= *= /= %= (rechts nach links)
Strukturen • Zusammenfassung einer definierten Menge UNTERSCHIEDLICHER Datenobjekte zu einer Einheit • Beispiel Person – Geburtstag, Geschlecht, Adresse, … • Beispiel Abteilung – Liste von Personen, Räume, Rollen, Budget, … • Beispiel Schaltungselement – Nummer, Bauteil, Eigenschaftswert, – Knoten1, Knoten2, …
Deklaration und Definition • Deklaration • Definition einer struct bauteil { Variablen: long number; struct bauteil bt; char type; double value; • Deklaration + //... Definition : }; struct bauteil { long number; • Achtung: Nur der Typ char type; struct bauteil wird double value; deklariert! //... } bt;
Initialisierung von Strukturen • Initialisierung analog zu Feldern struct bauteil { long number; char type; double value; }; struct bauteil bt1 = { 1, 'R', 100 }; struct bauteil bt[4] = { { 1, 'R', 100 },{ 2, 'C', 90 }, { 3, 'V', 0.9 },{ 4, 'R', 1000 } };
Speicherplatzbedarf von Strukturen • Tatsächlicher Speicherplatz für eine Struktur ist von Compiler und System abhängig – Manche Objekte müssen an Adressen ausgerichtet sein, die ein Vielfaches von 2 oder 4 sind – Compiler füllt automatisch aus •
Union • Union: Datentyp mit Fallunterscheidung • Daten unterschiedlichen Typs und Länge in einem Speicherbereich • Beispiel: Unterschiedliche Sichten auf einen Sende/Empfangspuffer – Anwendungsebene: Strukturorientiert – Treiberebene: Byteorientiert • Vereinbarung wie struct, einfach union anstelle Schlüsselwort struct
Sende/Empfangspuffer struct snd { // Befehl union buffer { char code // 1 byte Befehl struct snd send; }; struct rcv_vendor recv_vend; struct rcv_vendor { // Identifikation struct rcv_error recv_err; int status; char code[60]; long version; }; char vendor[16]; char model[16]; }; struct rcv_error { // Fehlerantwort int status; long errno; char msg[56]; };
Unterschied zwischen struct und union struct t_s { • Welches Ergebnis int a; char b[4]; liefern sizeof(s) und } s; sizeof(u)? • struct: a,b sind • Was steht in a nach unterschiedliche u.b[0] = 1; Speicherplätze s.b[0] = 1; union t_u { int a; char b[4]; } u; • union: a, b am selben Speicherplatz!
Bitfelder • Können nur innerhalb von struct und union definiert werden identifier : bit_anzahl • Bitfelder folgen in einer Speichereinheit lückenlos aufeinander • Achtung: – Bitfelder haben keine Adresse – Reihenfolge der Bits ist nicht spezifiziert ( Implementierungsabhängig! )
Beispiel struct bitfeld { unsigned short a:1, b:2, c:3, d:4; } bf = { 1, 2, 4, 8 }; bf.a = 0; bf.d = 11; • Auf Intelarchitektur in der Regel wie folgt: 0000 0010 0010 0101 = 0x0225 0000 0010 0010 0100 = 0x0224 0000 0010 1110 0100 = 0x02E4
Leerfelder und Sprünge an Wortgrenzen • struct bitfeld { • unsigned short a:1, b:2, :4, • c:3, d:4, :0, • e:5 ; • } bf = { 1, 2, 4, 8, 16 }; • Initialisierung auf Intelarchitektur in der Regel wie folgt: • 00000000000.1000000.1000.100.0000.10.1
Zeiger • Zeiger = Adresse eines Objekts – lineares Speichermodell – im allgemeinen nicht „unendlich“ • Voraussetzung für dynamische Speicherverwaltung • Voraussetzung für dynamische Funktionszuweisung
Zeiger • Variablen werden normalerweise über ihren Namen angesprochen int summe, i = 1, j = 2; summe = i + j; • Jede Variable liegt im Speicher an einer bestimmten Stelle (Adresse, Aufgabe von Compiler+Linker). • Zeiger (auf Variablen) enthalten genau diese Adresse einer Variablen • Zeiger sind dabei selbst auch „nur“ Variablen
Bestandteile von Zeigern • Adresse des Zielobjekts – An welcher Stelle im Speicher steht der referenzierte Wert? • Typ des Zielobjekts (char, int, …) – Wie muss der Inhalt an der adressierten Speicherstelle interpretiert werden? • Größe des Zielobjekts? – Wo steht das nächste Zielobjekt (wenn der Zeiger auf ein Feld von Zielobjekten zeigte)
Zeiger zeigen auf... • vereinbarte Variablen und Funktionen • dynamisch reservierten Speicher während der Laufzeit • virtuellen oder physikalischen Speicher oder Peripherie eines Computers (z.B. Bildschirmspeicher)
Zeigergrundoperationen • Deklaration von Zeigern mit typ * int a=10; int* b, c; int *d, e; • Adressoperator & b = &a • Dereferenzierungs- operator * *b = 11
Zeigerarithmetik (1) • Addition/Subtraktion von Zeiger und int int a[5] = {0,1,2,3,4}; // int-variable int* b = &a[0]; // b zeigt auf a[0] int* b = a; // b zeigt auf a[0] b = b + 2; // b zeigt auf a[2] • Increment/Dekrement b++; // b zeigt auf a[3] b -= 2; // b zeigt auf a[1] • Vorrang Incr/Decr vor Deref. *b-- = 1 // a[0] = 1
Zusammenhang zwischen Zeigern und Feldern • Objektdefinition: • Zugriff auf Felder int a,i=3; a = x[i]; a = *(px+i); int x[4]; a = px[i]; int *px; • Nächstes Feld: • Adresszuweisung: px++; px = x; x++; //!! Fehler px = &x[0];
Zeigerarithmetik 2 • Vergleich von Zeigern int x,a[5] = {0,1,2,3,4}; // int-variable int *b = &a[0]; // b zeigt auf a[0] int *c = &a[2]; // c zeigt auf a[2] if (b != c) { … } // < >= == != • Subtraktion von Zeigern x = b – c; // Anzahl Elemente zwischen b und c
Zeiger auf Zeiger • Zeiger können auch Zeiger zeigen int x, y; int *px = &x; // ptr to int int **ppx = &px; // ptr to (ptr to int) • Zugriff auf das Objekt an Adresse &x y = x; y = *px; y = **ppx;
Rangordnung der Zeigeroperatoren • Ausdruck • mit Klammern *++p *(++p) = *(p=(p+1)) *p+1 (*p)+1 *&j *(&j) = j *p**p (*p) * (*p) -*p -(*p) a/ *p a / (*p) a/*p /* beginnt Kommentar
Vollständige Vorrangregelungen • Auswertung normalerweise von links nach rechts (Leserichtung!), Ebenen mit (←) rechts nach links: Ebene 1: ( ) [ ] -> . Ebene 2 (←):! ~ + - (type) sizeof ++ -- * & Ebene 3: * / % Ebene 4: + - Ebene 5: < = > Ebene 6: == != Ebene 7: && Ebene 8: || Ebene 9(←): = += -= *= /= %=
Anwendungsbeispiel: Einfache verkettete Liste struct list_el { struct list_el *next; // nächstes Element double info; // information }; struct liste { struct list_el *head; // Kopf der Liste struct list_el *tail; // Ende der Liste };
Zeichenketten sind Zeiger auf char • Zeichenketten sind (fast immer) char-Felder • Funktionen erkennen Ende am \0-Zeichen • Initialisierung: char s1[7] = "ABCD"; char s2[] = "hallo"; char *s3, *s4; s3 = s1; s4 = (char *) malloc(15); s3 = "neu"; // !! Fehler s3[3] = 'c';
Ein/Ausgabe von Zeichenketten • Funktionen zur Ein/Ausgabe von Zeichenketten über Konsole sind in deklariert: char *gets(char *s); int puts(const char *s); scanf(const char *format, ...); printf(const char *format, ...); char getchar(); void putchar(const char c);
Formatangaben • % Formatangabe: Flags Breite.Genauigkeit Modifizierer Umwandlung • Flags: – - linksbündig – + Vorzeichenbehaftet – 0 Mit führenden Nullen • Modifizierer: – hh,h,l,ll,L: char/short/long/long long/long double • Umwandlung: – Ganzzahl: i, d (dezimal), u (unsigned), o (octal), x (hex), X (HEX), – Fließkomma: f, e – Zeichen: c – Zeichenkette: s – Adresse: p
Bearbeiten von Zeichenketten • Funktionen zur Manipulation von Zeichenketten sind in deklariert: char *strcat(char *dest, const char *src); char *strcpy(char *dest, const char *src); char *strchr(const char *s, int c); char *strrchr(const char *s, int c); char *strstr(const char *s1, const char *s2); size_t strlen(const char *s);
Felder von Zeigern auf zeichenketten • Zeiger auf Zeichenketten sind Zeiger auf Zeiger auf char char *worte[4]; // reserviert 4 Zeiger char **ppc; // reserviert 1 Zeiger ppc = worte; // ppc zeigt auf worte[0] • Adressierung von Worten char *first, *second; first = worte[0]; second = worte[1]; first = *ppc; second = *ppc++;
Sie können auch lesen