mikrorechentechnik 1 einführung in die programmiersprache c · mrt1-003-c 00_hallo. 2 sw für...
TRANSCRIPT
Fakultät Elektrotechnik und Informationstechnik, Professur für Prozessleittechnik
Mikrorechentechnik 1
Einführung in die Programmiersprache C
Professur für ProzessleittechnikWintersemester 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 <stdio>
• 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;
}
Hallo: Vergleich Assembler - C
/* Hallo in C */#include <stdio.h>
char *m = "Hallo\n";
int main(){
printf(m); return 0;
}
; Hallo in NASMsegment .datam: DB "Hallo",10,0
segment .textextern printfglobal mainmain: push m call printf add esp, 4
mov eax, 1ret
MRT1-003-C00_Hallo
2 SW für zusammen-gesetzte Datenobjekte
struct
union
1 SW für die Größe von Datenobjekten
sizeof
Schlüsselwörter (1)
9 SW für elementare Datenobjekte
charshort/int/longfloat/doublesigned/unsignedenum
Schlüsselwörter (2)
Speicherklasse von Objektenautoregisterstaticextern
Typqualifizierung von Objektenconstvolatile
Programmablaufif / elsewhilefordo (do … while)switchcase, defaultbreakcontinuegotoreturn
C ist EINFACH!
31 Schlüsselwörterchar, 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.
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
MRT1-003-C01_Datentypen
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 == AusdruckAusdruck != Ausdruck
• Relation
Ausdruck < <= >= > Ausdruck
• Logische Verknüpfung (nur für Ganzzahltypen)
! AusdruckAusdruck || AusdruckAusdruck && 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)
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 + (...)
MRT1-003-C03_Ausdruck
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
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
MRT1-003-C03_Ausdruck
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
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)
MRT1-003-C03_Ausdruck
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 ) Anweisungelse if ( Ausdruck ) Anweisungelse 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]…;
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} }
MRT1-003-C10_vector
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
• Deklarationstruct bauteil { long number; char type; double value; //...};
• Achtung: Nur der Typ struct bauteil wird deklariert!
• Definition einer Variablen:
struct bauteil bt;
• Deklaration + Definition :
struct bauteil { long number; char type; double value; //...} bt;
Initialisierung von Strukturen
• Initialisierung analog zu Feldernstruct 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 char code // 1 byte Befehl};struct rcv_vendor { // Identifikation int status; long version; char vendor[16]; char model[16];};struct rcv_error { // Fehlerantwort int status; long errno; char msg[56];};
union buffer { struct snd send; struct rcv_vendor recv_vend; struct rcv_error recv_err; char code[60];};
Unterschied zwischen struct und union
struct t_s { int a; char b[4];} s;
• struct: a,b sind unterschiedliche Speicherplätze
union t_u { int a; char b[4];} u;
• union: a, b am selben Speicherplatz!
• Welches Ergebnis liefern sizeof(s) und sizeof(u)?
• Was steht in a nach
u.b[0] = 1;
s.b[0] = 1;
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 intint a[5] = {0,1,2,3,4}; // int-variableint* 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/Dekrementb++; // 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:int a,i=3;
int x[4];int *px;
• Adresszuweisung:px = x;px = &x[0];
• Zugriff auf Feldera = x[i];a = *(px+i);a = px[i];
• Nächstes Feld:px++;x++; //!! Fehler
Zeigerarithmetik 2
• Vergleich von Zeigernint x,a[5] = {0,1,2,3,4}; // int-variableint *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 zeigenint x, y;int *px = &x; // ptr to intint **ppx = &px; // ptr to (ptr to int)
• Zugriff auf das Objekt an Adresse &xy = x; y = *px;y = **ppx;
Rangordnung der Zeigeroperatoren
• Ausdruck
*++p
*p+1
*&j
*p**p
-*p
a/ *p
a/*p
• mit Klammern
*(++p) = *(p=(p+1))
(*p)+1
*(&j) = j
(*p) * (*p)
-(*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 <stdio.h> 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 <string.h> 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++;