Mikrorechentechnik 1 Einführung in die Programmiersprache C · MRT1-003-C 00_Hallo. 2 SW für...

Post on 24-May-2020

1 views 0 download

Transcript of Mikrorechentechnik 1 Einführung in die Programmiersprache C · MRT1-003-C 00_Hallo. 2 SW für...

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++;