• Keine Ergebnisse gefunden

Fakultät EIM, Fachbereich Elektrotechnik und Informationstechnik

N/A
N/A
Protected

Academic year: 2022

Aktie "Fakultät EIM, Fachbereich Elektrotechnik und Informationstechnik"

Copied!
207
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Verlässliches Programmieren in C/C++

Teil A: Grundlagen zu C

(übernommen aus dem Manuskript der Vorlesung Datenverarbeitung)

Prof. Dr. F. Belli Universität Paderborn,

Fakultät EIM, Fachbereich Elektrotechnik und Informationstechnik

Angewandte Datentechnik (Softwaretechnik)

(2)

I. Einfache Konstrukte von Programmiersprachen

1. Einleitung

2. Algorithmus und Programm

3. Syntax, Semantik und Pragmatik

4. Einstieg: Einfache Sprachkonstrukte und allgemeiner Programmaufbau 5. Programmierumgebung

6. Weitere Steuerungskonstrukte

7. Exkurs: Einheitliche Darstellung von Daten und Operationen 8. Elementare Datentypen und Operationen in C

9. Strukturierte Datentypen 10. Zeiger-Datentyp

(3)

II. Fortgeschrittene Elemente der Programmierung

12. Unterprogrammtechniken 13. Rekursion

14. Dynamische Datenstrukturen 15. Dateiverarbeitung

16. Komplexität von Algorithmen und ihre Bestimmung 17. Programmprüfung

(4)

4. Einstieg: Sprachkonstrukte und allgemeiner Programmaufbau

Ziele dieser Einheit:

- Kennen lernen elementarer Bestandteile konventioneller Programmiersprachen,

- Zusammensetzung dieser Bestandteile zur Bildung einfacher Programme,

- Berücksichtigung potentieller Fehlerquellen in

Programmen.

(5)

Datenverarbeitung 4. Sprachkonstrukte und allg. Programmaufbau

4.1 Programmstruktur

Programm

Programm

include-Anweisung Variablendefinition

Main-Funktion

(6)

4.2 Include-Anweisung, Variablendefinition (Deklaration)

Datentyp (DT)

int float

Bezeichner Datentyp

; ,

Variablendefinition

Include-Anweisung (Preprocessor-Anweisung)

#include <stdio.h>

Bemerkung: Die eckigen Klammern werden üblicherweise zur

Kennzeichnung von Nicht-Terminalen benutzt; hier allerdings nicht!

(7)

Datenverarbeitung 4. Sprachkonstrukte und allg. Programmaufbau

- Variablen identifizieren Speicherstellen.

- bestehen aus einem Namen (bzw. Bezeichner), Stelle/Adresse im Speicher und Inhalt

- Sie treten definierend bzw. angewandt im Programm auf:

ƒ definierend: Typ VarName;

ƒ angewandt: VarName = ...

Beispiele: int zahl;

int zahl1, zahl2;

double geldbetrag;

zahl1=10; zahl2=20;

zahl=0;

(8)

Unser erstes C-Programm

#include <stdio.h> /*Standard Ein-/Ausgabe*/

/* Hauptprogramm */

void main() /* void: kein Ergebnis-DT*/

{ /* Beginn */

/* Ausgabe von Hallo, Welt! */

printf("Hallo, Welt! \n");

/* „printf“ : Funktion „print

formatted

“ */

(9)

Datenverarbeitung 4. Sprachkonstrukte und allg. Programmaufbau

Beispiel: void main ( int argc, char* argv[] ) {

int zhl;

int quadrat = zhl*zhl;

printf ("%d",quadrat);

}

Main-Funktion

Parameterliste

( )

Zusammengesetzte Anweisung int main

void

Anweisung ;

Zusammengesetzte Anweisung (compound statement)

{ }

(10)

4.3 Blockstruktur der Programme

void main () {

{ /* Hier rechne ich sinus */

. }

.. } .

.

{ /*... cosinus ...*/

.. } .

{

{ ...

} { ...

} } .

(11)

Datenverarbeitung 4. Sprachkonstrukte und allg. Programmaufbau

4.4 Allgemeine Darstellung der Anweisungen

Anweisung

Schreibanweisung

Vergleich (Bedingte Anweisung) Leseanweisung

Zuweisung

Zusammengesetzte Anweisung

...

;

(12)

Beispiele:

Schreibanweisung:

Leseanweisung:

Zuweisung:

Zusammengesetze Anweisung:

Vergleich (Bedingte

printf("Hallo, Welt! \n");

scanf("%d", &zhl1);

zhl = 100;

{

int zhl;

int quadrat = zhl*zhl;

printf ("%d",quadrat);

}

if ( ... )

(13)

Datenverarbeitung 4. Sprachkonstrukte und allg. Programmaufbau

Schreib- und Leseanweisung näher betrachtet

Schreibanweisungen

printf("Zahl eingeben \n");

/* druckt die konstante Zeichenkette (Literal) „Zahl …“ aus */

printf("%s", "hey");

/* druckt die Zeichenkette (string) „hey“ aus */

printf("%c%c%c",‘h‘,‘e‘,‘y‘);

/* druckt sukzessiv die Einzelzeichen (character) „h“,„e“,„y“ aus */

int zhl;

printf(“Die Zahl \n%d ist positiv“, zhl);

/* Ausgb: „Die Zahl“, neue Zeile, Ausgb: der aktuelle Wert von zhl */

/* (decimal integer), letzte Ausgb: „ ist positiv.“ */

Leseanweisungen

int zhl, zhl1,zhl2; char ch;

scanf("%d", &zhl);

/* liest die ganze Zahl (decimal integer) „zhl“ ein */

scanf(" %c%d%d", &ch, &zhl1, &zhl2);

/* liest das Zeichen ch und ganze Zahlen „zhl1“ und „zhl2“ ein */

(14)

Ausdrücke

(nach George Boole) Boolescher Ausdruck

Einfacher Ausdruck

Einfacher Ausdruck

>

==

<=

<

(15)

Datenverarbeitung 4. Sprachkonstrukte und allg. Programmaufbau

einfacher (arithmetischer) Ausdruck

Präfix-Operation

Term +

- + -

Infix-Operation

Kontextsensitive (umgebungsabhängige) Interpretation der Operationen + und -.

(16)

Term

Faktor

% / Faktor *

(17)

Datenverarbeitung 4. Sprachkonstrukte und allg. Programmaufbau

Faktor

vorzeichenlose Konstante

Bezeichner einfacher Ausdruck

( )

indirekt rekursive Definition „einfacher Ausdruck“

(18)

Bezeichner für eine Konstante

INTEGER-Zahl

REAL-Zahl

Vorzeichenlose Konstante

(19)

Datenverarbeitung 4. Sprachkonstrukte und allg. Programmaufbau

Beispiele für Ausdrücke:

2, 2 * 3, 2 * 1, 50 % 2 a, 2 + a, 7 * b

(a + b) * (c / d) % (e * 2 + f) arithmetische

Ausdrücke

a<5, a+b >= -10,

!(((a > b) || (c >= 10)) && ((a + 2) > 5)) boolescher

Ausdruck

(20)

4.5 Vergleich

Bedingung

Anweisung 1 if

;

( )

Bedingte Anweisung (Binäre Entscheidung)

(21)

Datenverarbeitung 4. Sprachkonstrukte und allg. Programmaufbau

Bedingung

Ausdruck < Ausdruck

!=

>=

>

==

<=

Zusammengesetzte Bedingung

Bedingung

||

(

!

&&

)

(22)

4.6 (Wert-)Zuweisung („Ergibt-sich-Anweisung“)

Variable = Ausdruck

(Bezeichner)

ergibt sich aus

guthaben = 50; /* Geschenk G´mutter */

gesch_tante = 100;

Beispiele:

guthaben + gesch_tante;

/*altes*/

guthaben = /*neues*/

zhl1 = 3;

zhl2 = 4;

zhl1 = zhl1 + zhl2;

...

zhl2 = zhl1 + zhl2;

(23)

Datenverarbeitung 4. Sprachkonstrukte und allg. Programmaufbau

C-spezifische Syntax gängiger Zuweisungsoperatoren

- viele binäre Operatoren haben entsprechenden Zuweisungsoperator:

+=, -=, *=, /= usw.

- <Ausdruck1> <Operator>= <Ausdruck2>

- ist äquivalent zu

- <Ausdruck1> = (<Ausdruck1>) <Operator> (<Ausdruck2>)

- Beispiele:

x += 2; => x = x + 2;

x *= y + 1; => x = x * (y + 1);

/* Klammerung beachten! */

(24)

4.7 Selektion der nächsten Anweisung durch Vergleich

...

int zhl;

scanf(“%d“, &zhl);

Aufgabe: Schreibe ein C-Programm, das eine Zahl zhl einliest und ausgibt, ob sie positiv oder negativ ist.

else printf(“negative Zahl“);

if (zhl > 0)

printf(“positive Zahl“);

(25)

Datenverarbeitung 4. Sprachkonstrukte und allg. Programmaufbau

Programmablaufplan

: BEGIN

zhl

zhl > 0

?

zhl positiv

zhl negativ

END

lies zhl ein

Ausgabe

J N

Selektion

(26)

Der korrigierte Programmablaufplan:

J N

N

zhl = 0?

zhl negativ J

lies zhl ein BEGIN

zhl

zhl > 0?

zhl

positiv zhl = 0

Vergleiche

(27)

Datenverarbeitung 4. Sprachkonstrukte und allg. Programmaufbau

Das korrigierte Programm:

#include <stdio.h>

void main() {

int zhl;

scanf("%d", &zhl);

if (zhl > 0)

printf("positive Zahl");

else {

if (zhl == 0)

printf("Zahl 0");

else printf("negative Zahl");

}

(28)

5. Programmierumgebung

Ziele dieser Einheit:

- Schritte von der Erstellung des Programms zu seiner Ausführung.

- Debuggen bzw. Verifikation des Programms

und Validation der Ergebnisse.

(29)

Datenverarbeitung 5. Programmierumgebung Editor

(„edieren“)

meinprogramm.c

N

(„verifizieren/validieren“) N

(„debuggen“) Korrigieren

meinprogramm.exe („compilieren“)

C-Compiler Quell-

Code Fehler-

frei?

J

J

ausführen Erfolg-

reich

?

Ergebnisse

Binder/Lader

(30)

Ausführung unseres ersten C-Programms

#include <stdio.h> /*Standard Ein-/Ausgabe*/

/* Hauptprogramm */

void main() /* void: kein Ergebnis-DT*/

{ /* Beginn */

/* Ausgabe von Hallo, Welt! */

printf("Hallo, Welt! \n");

/* „printf“ : Funktion „formatted print“ */

(31)

Datenverarbeitung 5. Programmierumgebung

Pre- processor

Modifizierter Quell-Code Compiler

(Übersetzer) Verschieb-

barer Ob- jekt-Code

Lader

Ein- gaben

Quell- Code (Source)

Ergeb- nisse Binder

(Linker)

Ausführba- rer (Absolut-)

Objekt-Code andere

Objekt-Codes;

Bibl.-funkt- ionen;

Startcode

(32)

Der Präprozessor

kann wie folgt benutzt werden:

1. Einfügen von Quelltextdateien und Bibliotheken. Zweierlei Bedeutung:

#include <<Dateiname>> , z.B. #include <myFile.h>, bedeutet Ansprechen von Standardfunktionen, welche meist in den Verzeichnissen

/usr/include oder /usr/local/include/ stehen.

oder

#include "<Dateiname>", z.B. #include "myFile.h",

bedeutet Einfügen von benutzerdefinierten Dateien. Die Suche erfolgt in der lokalen Umgebung (aktuelles Verzeichnis).

Bemerkung: Achten Sie auf die Benutzung von „<...>“ bei Nicht-Terminalen.

2. Makrodefinition und -ersetzung.

#define <Makroname> <Ersatztext>

Abkürzung häufig benutzter Zeichenfolgen.

(33)

Datenverarbeitung 5. Programmierumgebung

Vorsicht:

Makrodefinition: #define SQUARE(X) X*X Makroaufruf (Bsp.): b=SQUARE(a+1)

erzeugter Code: b=a+1*a+1 Richtig: #define SQUARE(X) ((X)*(X))

3. Zur Steuerung der bedingten Übersetzung.

Präprozessor-Direktiven zur Festlegung zu übersetzender Programmteile:

#if def_1

Programm_A

#elif def_2

Programm_B

#else def_9

Programm_Z

Übersetzung, wenn der Makroname bekannt ist:

#ifdef Makroname

(34)

Gehen Sie bitte diese Schritte am folgenden Programm durch:

#include <stdio.h>

void main() {

int zahl;

scanf("%d", &zahl);

if (zahl > 0)

printf("positive Zahl");

else {

if (zahl == 0)

(35)

Datenverarbeitung 6. Steuerkonstrukte

6. Weitere Steuerungskonstrukte

Ziele dieser Einheit:

- Konstrukte, welche eine nicht-lineare Ausführung von Programmen ermöglichen. Dazu gehören:

ƒ Wiederholte Ausführung logisch/strukturell zusammenhängender Programmteile

(Schleifen/Iterationen/Loops).

ƒ Erweiterung einfacher (einseitiger/zweiseitiger) Entscheidungen auf mehrseitige Entscheidungen (Mehrfachauswahl/Schalter/Switch).

- Erkennung/Berücksichtigung der Fehlerquellen bei

Verwendung dieser Konstrukte.

(36)

6.1 Abweisende Schleife (while-Anweisung)

int idx = 1;

int sum = 0;

while (idx <= 100)

{/*idx: Laufvariable*/

...

. . .

Beispiel:

Bed.?

Anweisung

N J

(Terminierungs)Bedingung

Anweisung

while ( )

Ausführung des Schleifenrumpfs so lange eine Bedingung erfüllt ist.

Schleifen- kopf

„kopfgesteuert“

/* initialisieren */

(37)

Datenverarbeitung 6. Steuerkonstrukte

6.2 Nichtabweisende Schleife (do-while-Anweisung)

Ausführung des Schleifenrumpfs bis eine Bedingung erfüllt ist.

Beispiel: ...

...

...

Anweisung

N J

...

int zahl;

zahl = 30000;

do {

printf ("Zahl: %d", zahl);

zahl = zahl - 1;

}

while (zahl > 0);

...

(38)

Nichtabweisende Schleife (do-while-Anweisung)

Anweisung

(Terminierungs)Bedingung do

while ( ) ;

(39)

Datenverarbeitung 6. Steuerkonstrukte

int sum = 0;

int idx;

for (idx=1; idx<=100; idx++) sum = sum + idx;

_____________

int sum = 0;

int idx;

for (idx=100; idx>=1; idx--) sum = sum + idx;

...

6.3 Zählschleifen (for-Anweisung)

Ausführung des Schleifenrumpfs von einem Anfangs- bis zu einem Endwert der Laufvariable

/* inkrementieren */

/* dekrementieren */

Beispiel:

Bed.?

Anweisung

Anweisung N J

(40)

Zählschleifen (for-Anweisung)

for ( Ausdruck1 ;

(Terminierungs) Bedingung

;

Ausdruck2 )

Anweisung Ausdruck1: wird einmal vor

Beginn der Schleife ausgeführt/ausgewertet

Bedingung: wird vor jedem Schleifendurchlauf geprüft Ausdruck2: wird nach

(41)

Datenverarbeitung 6. Steuerkonstrukte

6.4 Auswahlkriterien für verschiedene Schleifenformen und ihre Darstellung

Eckwerte

– Anfangs- und Endwerte der Laufvariable von vorne bekannt:

Zählschleife (for (idx=0;... ))

– Schleife bei Nicht-Erfüllung einer Bedingung abbrechen:

while ... do ... : sofortiger Abbruch möglich

do ... while ... : mindestens eine Durchführung vor dem Abbruch.

– Bemerkung: Die Anweisungen

break

bzw.

continue

bewirken sofortigen Abbruch der Schleife bzw. Übergehen eines Schleifenschrittes.

(42)

Abweisende

(kopfgesteuerte) Schleife

SOLANGE Dünstzeit unter 30 Min.

wiederhole

Dünste um eine Minute weiter!

Nicht-abweisende

(fußgesteuerte) Schleife

BIS Dünstzeit über 30 min.

Dünste um eine min weiter!

wiederhole

Zählschleife

VON Dünstzeit = 0 Min.

wiederhole

Dünste um eine Minute weiter!

(43)

Datenverarbeitung 6. Steuerkonstrukte

6.5 Tücken der Schleifen und anderer Sprachkonstrukte

N

J Anfangswerte idx 1;sum 0

idx<=100

sum sum+idx idx idx+1

...

idx = 1;

sum = 0;

while (idx <= 100) {

sum = sum + idx;

idx = idx + 1;

}...

(44)

...

idx = 0;

sum = 0;

while (idx < 100) idx = idx + 1;

sum = sum + idx;

...

Fehler 1:

N

J

Anfangswerte idx 0;sum 0

idx<100

idx idx+1 sum sum+idx

Schleifenrumpf nicht als Verbundanweisung

(45)

Datenverarbeitung 6. Steuerkonstrukte

...

idx = 0;

sum = 0;

while (idx < 101) {

idx = idx + 1;

sum = sum + idx;

}

...

Fehler 2:

N

J Anfangswerte idx 0;sum 0

idx<101

idx idx+1 sum sum+idx Fehlerhafte Bedingung

Ein Schleifendurchlauf zuviel

sum ergibt den Wert für Summe 1 bis 101

(46)

Fehler 3:

...

idx = 0;

while (idx < 100) {

sum = 0;

idx = idx + 1;

sum = sum + idx;

}...

N

J Anfangswerte

idx 0

idx<100

sum 0 idx idx+1 sum sum+idx sum wird im Schleifenrumpf initialisiert

(47)

Datenverarbeitung 6. Steuerkonstrukte

...

idx = 1;

sum = 0;

while (idx <= 100) {

sum = sum + idx;

idx = idx + 1;

}...

Fehler 4:

N

J Anfangswerte idx 1;sum 0

idx<=100

sum sum+idx idx idx+1

Anfangswerte nicht definiert!

sum <- irgendein Wert, bloß nicht die Summe, die erwünscht wird!

/* vergessen */

(48)

Noch mehr Fehler, Fortsetzung (Zählschleifen)

idx = 1;

sum = 0;

for (idx=1; idx<=100; idx++) {

sum = sum + idx;

idx = idx + 1;

}

.. . ..

. ...

J

N Anfangswert

sum 0, idx 1

i > 100

sum sum + idx

(49)

Datenverarbeitung 6. Steuerkonstrukte

Zusammenfassung:

„Fehler in do-while und while-do-Schleifen“:

– Die Bedingung muss auswertbar sein. Die Variablen müssen initialisiert (auf Anfangswerte gesetzt) sein.

– Schleifenrumpf muss eine Aktion enthalten, die die Schleifenbedingung berührt und irgendwann falsch werden lässt.

– Keine „Blindgänger“ im Schleifenrumpf (Aktionen für „draußen“).

(50)

6.6 Allgemeine Fallunterscheidung (Mehrfach-auswahl /Schalter) durch switch

falls heute

mo di mi don fr sonst

Kino

Disco

Pizza saure

Bingo Bohnen Gurken

(51)

Datenverarbeitung 6. Steuerkonstrukte

Schalter bei C:

Ausdruck

Anweisung

switch ( ) {

case default

Konstante : }

int x = ...

switch (x) {

case 1: printf(“eins\n“); break;

case 2: printf(“zwei\n“); break;

...

case 12: printf(“zwo“); /* kein break */

case 11: printf(“elf\n“); break;

case ‘F‘: printf(“siebzig\n“); break;

default : printf(“nanu?\n“); break;

Beispiel:

(52)

Bemerkungen zum switch:

- Konstante (case-Marken) und break:

ƒ müssen konstanter Integer-Ausdruck sein

ƒ Reihenfolge der Marken ist beliebig

ƒ Ausführung startet ab einer Marke, falls der Ausdruck der Konstante entspricht

ƒ Abbruch mit break ! - default

ƒ wird ausgeführt, falls keine Marke vorhanden

ƒ ist optional, d.h kann weggelassen werden - Beispiele:

ƒ : 1, 2, 3,..., ´J´,´F´,

nicht A + B, x + monat > 12 , ...

(53)

Datenverarbeitung 6. Steuerkonstrukte

if (monat == 1) tage = 31;

else if (monat == 2) {

if (jahr % 4 != 0) tage = 28;

else if ((jahr % 100 == 0)

&& (jahr % 400 != 0)) tage = 28;

else

tage = 29;

}

else if (monat == 3) tage = 31;

else if (monat == 4) .

. .

/* bis man schwarz wird! */

Beispiel

: Schreibe ein Programm, das für ein gegebenes Jahr für die verschiedenen Monate die Anzahl der Monatstage solange ausgibt, bis als Monat eine 0 eingeben wird.

switch (monat) {

case 1: tage=31;break; case 3: tage=31;break;

case 5: tage=31;break; case 7: tage=31;break;

case 8: tage=31;break; case 10: tage=31;break;

case 12: tage=31;break;

case 4: tage=30; break; case 6: tage=30;break;

case 9: tage=30; break; case 11: tage=30;break;

case 2:

if (jahr % 4 != 0) tage = 28;

... /* wie vorhin */

break;

/* optional */

default: printf("Fehler"); break;

}

besser

switch-Anweisung:

(54)

noch besser:

switch (monat) {

case 1: case 3: case 5:

case 7: case 8: case 10:

case 12: tage = 31; break;

case 4: case 6: case 9:

case 11: tage = 30; break;

case 2:

if (jahr % 4 != 0) tage = 28;

... /* wie vorhin */

break;

/* optional */

default: printf("Fehler"); break;

(55)

Datenverarbeitung 8. Datentypen und Operationen

8. Elementare Datentypen und Operationen

Ziele dieser Einheit:

- Sinn und Zweck der Typisierung von Variablen - Eigenschaften einfacher, skalarer Datentypen,

Operationen

- Typumwandlung

- Präzedenzrelation von Operatoren

- C-spezifische Syntax von Operatoren

(56)

8.1.1 Numerische, ganzzahlige Datentypen

-short int (short): kurzer Ganzzahl-Typ (Minimum: 16 Bit) Wertebereich: -32768 .. 32767

Deklaration, Beispiele: short zhl1, zhl2; short int zhl1=1,zhl2=3;

Operationen: Ein-/Ausgabe, arithmetische Operationen, Verwendung in arithmetischen/booleschen Ausdrücken

Arithmetische + (Addition), - (Subtraktion), * (Multiplikation), Operationen: / (ganzzahlige Division),

8.1 Einfache, skalare Datentypen

Bemerkung: Wertebereiche der behandelten Datentypen können je nach Compiler/Prozessor von den hier angegebenen Werten abweichen!

(57)

Datenverarbeitung 8. Datentypen und Operationen

-int: typische Ganzzahl (Minimum: 16 Bit, hier: 32 Bit);

Wertebereich: -2147483648 .. 2147483647

Deklaration, Beispiele: int zhl1, zhl2; int zhl1=1, zhl2=3;

Operationen: analog zu short Arithm. Operationen: analog zu short

-long int (long): langer Ganzzahl-Typ (Minimum: 32 Bit, hier: 32 Bit) Wertebereich: -2147483648 .. 2147483647

Deklaration, Beispiele: long zahl; long zahl2 = 1213;

Operationen: analog zu short/int Arithm. Operationen: analog zu short/int

- Zahlen können oktal, dezimal und hexadezimal dargestellt werden:

37 dezimal

037 oktal (führende 0), entspricht 31 (dezimal)

0x37 hexadezimal (führende 0x), entspricht 55 (dezimal)

(58)

#include <stdio.h>

void main( ) {

/* Umwandlung von zahl in seine Binärdarstellung */

/* Ausgabe fängt mit der letzten Stelle an */

int zahl = 253366;

short rest;

while (zahl > 0) {

rest = zahl % 2; /* Modulo */

printf("%d\n", rest);

zahl = zahl / 2; /* ganzzahlige Division */

}

Beispiel:

(59)

Datenverarbeitung 8. Datentypen und Operationen

- float Gleitpunktzahl einfacher Genauigkeit (32 Bit)

Wertebereich: -3.4*10^38 .. 3.4*10^38, 6 Stellen Genauigkeit Deklaration, Beispiele: float zhl1, zhl2;

Operationen: Ein-/Ausgabe, arithmetische Operationen, Verwendung in arithmetischen/booleschen Ausdrücken

Arithmetische

Operationen: + (Addition), - (Subtraktion), * (Multiplikation), / (Division)

- double Gleitpunktzahl mittlerer Genauigkeit (64 Bit)

Wertebereich: -1.7*10^308 .. 1.7*10^308, 15 Stellen Genauigkeit Deklaration, Beispiele: double pi = 3.1415; double zahl;

8.1.2 Gleitpunktzahlen

(60)

- long double Gleitpunktzahl hoher Genauigkeit (80 Bit)

Wertebereich: -3.4*10^4932 .. 3.4*10^4932, 17 Stellen Genauigkeit Deklaration, Beispiele: long double zahl; long double e = 2.718;

- Schreibweisen für Gleitpunktzahlen:

ƒ Dezimalpunkt 1.234 .5 -16.

-- Suffix f/F für float, double 234.f (nicht 234f) -- Suffix l/L für long double 13.L 14.l

ƒ mit Exponent e/E zur Basis 10 .314e2 ( = 0.314*10^2 = 31.4)

.314e-2 ( = 0.314*10^-2 = 0.00314)

(61)

Datenverarbeitung 8. Datentypen und Operationen

#include <stdio.h>

int main( ) {

float flaeche, radius;

float pi = 3.14159;

scanf("%f", &radius);

flaeche = pi * radius * radius;

printf("Radius %f, Flaeche: %f \n", radius, flaeche);

}

Beispiel:

(62)

- char

- 1 Zeichen – Größe: 1 Byte (nicht zwingend acht Bit)

- numerische Interpretation möglich, Wertebereich -128 .. 127 - Beispiele:

char ch1=‘Q‘, ch2=‘\n‘;

char char3=65; /* (hexadez.: 41) entspricht ‘A‘ – s. ASCII-Code */

- signed/unsigned

- Typen mit/ohne Vorzeichen (anwendbar auf Integer- und Character-Typen) - unsigned short: 0 .. 65535 (16 Bit)

- unsigned int: 0 .. 4294967295 (32 Bit) - unsigned long: 0 .. 4294967295 (32 Bit)

8.1.3 Alphanumerische und sonstige Datentypen

(63)

Datenverarbeitung 8. Datentypen und Operationen

- Problem: Anwendung eines Operators auf verschiedene Typen.

Beispiel: int anzahl = 4;

float preis = 10.34;

float gesamtPreis = anzahl * preis;

- Bei einer Berechnung (rechte Seite der Zuweisung) mit verschiedenen Datentypen findet eine automatische Typumwandlung an den stärkeren Typen statt.

- Dabei gilt folgende Hierarchie (a<b : b dominiert a):

char < int < long < float < double < long double

- Bei einer Wertzuweisung erfolgt automatisch eine Anpassung an den Typ der linken Seite der Zuweisung.

Beispiel: float fl1 = 2.34; float fl2 = 4.56;

int zahl;

zahl = fl1 * fl2; /* zahl enthält den Wert 10 */

/* und nicht 10.6704. Das bedeutet: */

8.2 Typumwandlung

(64)

- Mit einem cast-Ausdruck ist es möglich, den Typ eines Operanden zu ändern.

- Beispiel:

/* Deklaration und Initialisierung */

int zhl1=1, zhl2=4;

double dbl;

/* Anweisung1: */

dbl = (double)zhl1 /zhl2; /* dbl erhaelt den Wert 0.25 */

/* zhl1 explizit, zhl2 automatisch nach double umgewandelt und */

/* eine Fließkomma-Division durchgeführt. */

Explizite Typumwandlung (cast)

(65)

Datenverarbeitung 8. Datentypen und Operationen

#include <stdio.h>

void main() {

float radius, inhalt, umfang;

scanf("%f", &radius);

inhalt = radius * radius * 3.14159;

umfang = 2 * radius * 3.14159;

printf("Radius: %f \n", radius);

printf("Kreisinhalt: %f \n", inhalt);

printf("Kreisumfang: %f \n", umfang);

}

8.3 Konstanten ( const )

float pi = 3.14159;

Pi

pi const float pi = 3.14159;

(66)

- In C ist kein spezieller Datentyp für Wahrheitswerte (true/false) verfügbar, wie in anderen Sprachen: z.B. bool (C++) oder boolean (Pascal, Java).

- Jeder der Grundtypen kann dafür (als boolean) verwendet werden.

- Jeder Ausdruck ist logisch interpretierbar.

- Interpretation:

Falsch: Ausdruck hat den Wert 0.

Wahr: Ausdruck hat anderen Wert als 0.

- Logische Operatoren liefern immer 0 oder 1.

- n sei ganzzahlige Variable: Dann kann !(!(n))sich von (n) unterscheiden!

- Short-circuit Auswertung logischer Ausdrücke, d.h. Auswertung nur solange bis Ergebnis des Ausdrucks feststeht:

8.4 Boolesche Ausdrücke

(67)

Datenverarbeitung 8. Datentypen und Operationen

#include <stdio.h>

void main( ) {

int zahl1, zahl2;

int istKleiner;

scanf("%d %d", &zahl1, &zahl2);

istKleiner = (zahl1 < zahl2);

if (istKleiner)

printf("Zahl1 ist kleiner als Zahl2\n");

else

printf("Zahl1 ist nicht kleiner als Zahl2\n");

}

Beispiel:

(68)

-enum

Aufzählungstyp, der es ermöglicht, Konstanten einen Integer-Wert zuzuweisen und diese im Programm über Bezeichner anzusprechen.

8.5 Selbstdefinierter Aufzählungs-Datentyp

/* Deklaration der Variablen stuermig mit dem Typ Jahreszeiten */

enum Jahreszeiten stuermig; Beispiele:

/* Definition des Aufzaehlungstyps Jahreszeiten */

enum Jahreszeiten {Fruehjahr, Sommer, Herbst, Winter, Karneval};

/* Zuweisung eines Wertes an die Variable */

stuermig = Herbst;

(69)

Datenverarbeitung 8. Datentypen und Operationen

#include <stdio.h>

int main( ) {

enum ampel {rot, gelb, gruen, rotgelb};

enum ampel ampelPhase = rot;

...

switch (ampelPhase) {

case rot:

case gelb:

printf("Anhalten\n");

break;

case rotgelb:

case gruen:

printf("Gas geben\n");

}

Beispiel:

(70)

- Erstmaliger Zugriff im Programm auf Variablen sollte schreibend sein.

- Lebensdauer: Variablen existieren nur eine bestimmte Zeit im Speicher.

- Sichtbarkeit: innerhalb desselben Programms unterschiedliche Verfügbarkeit.

8.6 Variablen und ihre Sichtbarkeit

Sichtbarkeitsregeln:

- Globale Variablen

ƒ außerhalb aller Blöcke definiert

ƒ in allen Blöcken sichtbar - Lokale Variablen

ƒ innerhalb eines Blocks definiert, gültig ab Definitionsstelle

ƒ in tieferliegenden Blöcken sichtbar

ƒ Verdeckung durch Definitionen gleichnamiger Variablen in

(71)

Datenverarbeitung 8. Datentypen und Operationen

Beispiel: ...

int zhl = 10;

if (zhl != 0)

{ /* neuer Block */

printf("%d \n", zhl); /* Ausgabe: 10 */

int zhl = 20;

printf("%d \n", zhl); /* Ausgabe: 20 */

}

printf("%d \n", zhl);

...

} {

{...

} {...

} {...

}

Verdeckung der äußeren zhl Sichtbarkeit/Gültigkeit

/* Ausgabe: 10 */

(72)

- +=, -=, *=, /= usw.

Zuweisungsoperatoren - ++, --

Inkrement- und Dekrementoperatoren (als Prefix- und Postfix- Operatoren möglich)

- &&, ||, !

Logische Verknüpfungen AND, OR, NOT - ?

Fragezeichen-Operator - &, ^, |, ~

Bit-Operatoren AND, XOR, OR, Komplement

8.7 C- spezifische Syntax gängiger Operatoren ( Übersicht )

(73)

Datenverarbeitung 8. Datentypen und Operationen

- Vergleich: >, <, >=, <=

- Un-/Gleichheit: !=, ==

- logisches AND, OR, NOT: &&, ||, !

- Fragezeichen-Operator: abkürzende Schreibweise - Beispiel:

if (m > n) res = m;

else

res = n;

8.7.1 Logische Operatoren und Fragezeichen-Operator

ist gleichwertig zu

res = (m > n) ? m : n;

(74)

- Operatoren zum In-/Dekrementieren von Variablen:

ƒ ++ : Inkrementieren, d.h. Addition von 1 zum Operanden

ƒ -- : Dekrementieren, d.h. Subtraktion von 1 vom Operanden - als Präfix- und Postfix-Operatoren möglich.

- Beispiel:

ƒ ++idx inkrementiert idx bevor der Wert genutzt wird. Die Wirkung ist:

idx = idx+1; res = idx; ...

ƒ idx++ inkrementiert idx nachdem der Wert genutzt wurde. Die Wirkung ist:

res = idx; idx = idx+1; ...

8.7.2 Verkürztes In- und Dekrementieren, Zuweisen

- Beispiel: int res;

int idx = 5;

int res;

int idx = 5;

(75)

Datenverarbeitung 8. Datentypen und Operationen

8.8 Exkurs: Bitweise Operatoren

& Bitweises AND

| Bitweises OR

^ Bitweises XOR

<< Links-Shift

>> Rechts-Shift

~ Bitweises Komplement

a b a AND b a OR b a XOR b NOT a

false false false false false true

false true false true true true

true false false true true false

true true true true false false

- <<, >> Bitweise Shiftoperatoren (Verdoppeln/Halbieren) dienen zur bitweisen Manipulation auf den Typen char, short, int , long

(76)

- Beispiel 2:

int idx = 57;

idx = idx << 3; /* Shift um 3 Stellen nach links */

/* idx hat Wert 456 = 57*2^3 bzw. binär 111001000 */

- Beispiel 1:

int idx = 12345;

idx = idx & 127;

/* idx ist 57 */

(77)

Datenverarbeitung 8. Datentypen und Operationen

( ) [ ] -> . Linksassoziativ

! ~ ++ + - * & (type) sizeof Rechtsassoziativ

* / % Linksassoziativ

+ - Linksassoziativ

<< >> Linksassoziativ

< <= > => Linksassoziativ

== != Linksassoziativ

& Linksassoziativ

^ Linksassoziativ

| Linksassoziativ

&& Linksassoziativ

|| Linksassoziativ

? : Rechtsassoziativ

= += -= *= /= %= usw. Rechtsassoziativ

, Linksassoziativ

… oder kurz:

8.9 Vorrang-Regeln (Präzedenz) der Operatoren (Übersicht)

abnehmend

(78)

9. Strukturierte Datentypen

Ziele dieser Einheit:

- Realisierung strukturierter Datentypen array (Feld), structure , union.

- Problemangepasste, selbst definierte Datenstrukturen.

- Schaffung geeigneter Operationen darauf.

- Damit: Erster Schritt in Richtung Datenabstraktion bzw.

Abstrakte Datentypen.

(79)

Datenverarbeitung 9. Strukturierte Datentypen

9.1 Felder (arrays)

Beispiel: Identifizierung der Kleiderhaken in einer Garderobe int haken0,haken1,....,haken12345;

...schreiben, schreiben!

oder durch den Aufzählungstyp

enum garderobe {haken1, haken2, ..., haken12345};

zu umständlich!

besser:

int garderobe [12346];

(80)

Syntaxdiagramm (nicht vollständig)

]

[ Größe

Bezeichner Datentyp

= Initialisierung ;

Beispiele:

int zahl[10];

(81)

Datenverarbeitung 9. Strukturierte Datentypen

- Felder aller Datentypen sind möglich.

- Bei der Definition genügt die Größenangabe (Inhalt der Einträge ist dann aber undefiniert).

float feld[10];

int vector[4];

- Schreib-/Lesezugriffe auf die Einträge erfolgen über einen Index.

Beispiel: for (idx=0; idx<4; idx++) vektor[idx] = 0;

vektor[2] = 3;

printf(“%d \n“, vektor[0]);

- Der Index läuft von 0 bis (Größe -1).

Bemerkungen (1)

(82)

Bemerkungen (2)

- Zugriffe auf Indizes, die nicht zwischen 0 bis (Größe -1) liegen, sind undefiniert!

Beispiel: int a [10];

a[10] = 3; /* falsch! */

a[10]

Überlauf (overflow)!

a[9]

a[1] ...

a:

a[0] ...

- Fehler dieser Art können zu undefinierten Verhalten/Abstürzen des

(83)

Datenverarbeitung 9. Strukturierte Datentypen

- Mehrdimensionale Felder durch Hinzunahmen weiterer Indizes.

matrix:

[0][0] [0][1]

[1][0] [1][1]

[2][0] [2][1]

[3][0] [3][1]

2 3 9 2 3 5 6 8

Beispiel:

int matrix [4][2] = {{2,3},{9,2},{3,5},{6,8}};

int zl, sp;

for (zl=0; zl<4; zl++) {

for (sp=0; sp<2; sp++)

printf("%d ", matrix[zl][sp]);

printf("\n");

}

Ausgabe:

2 3 9 2 3 5 6 8

(84)

Beispiel: Lies eine Serie von Roulette-Ergebnissen und schreib die Häufigkeit der einzelnen Zahlen.

#include <stdio.h>

const int kleinstzahl = 0;

const int groesstzahl = 36;

void main() {

int gruentisch [37];

int zahl, idx; /*Als Nächstes: Initialisierung */

for (idx=kleinstzahl; idx <= groesstzahl; idx++) { gruentisch[idx] = 0; } do /* Eingabe bis ...(s. while ...) */

{

scanf("%d", &zahl);

if ((kleinstzahl <= zahl) && (zahl <= groesstzahl)) gruentisch[zahl] = gruentisch[zahl] + 1;

}

while (zahl >= 0); /* Abbruch durch Eingabe einer negativen Zahl*/

(85)

Datenverarbeitung 9. Strukturierte Datentypen

9.2 Zeichenketten (strings) als Felder von Zeichen

H a l l o \0

-char-Felder sind als Zeichenketten (strings) interpretierbar.

- Strings werden durch \0 terminiert:

Beispiel: “Hallo“ entspricht:

- Spezielle Bibliotheken in C zur Stringverarbeitung stehen zur Verfügung.

Beispiel:

int idx;

char gruss[6] = “Hallo“; /* mindest. 6 Einträge nötig */

char fluch[6] = “Mist“; /* mindest. 5 Einträge nötig */

for(idx=0; idx<6; idx++)

fluch[idx]=gruss[idx]; /* Kopie */

printf(“%s %s \n“, gruss, fluch);

/*Ausgabe: Hallo Hallo */

(86)

9.3 Strukturen mit struct

- Zusammenfassen/Gruppieren unterschiedlicher Datentypen

/* oder auch */

struct complex Beispiel: struct complex

struct Strukturname { Datentyp Bezeichner ,

}

Bezeichner ,

;

;

(87)

Datenverarbeitung 9. Strukturierte Datentypen

Definition von Strukturen, Variablen

Vier (4) Möglichkeiten:

- Nur Angabe des Strukturnamens:

struct complex {float re, im;};

Variablendefinition später: struct complex cmpl_zhl;

- Angabe von Strukturname + Variable(n)

struct complex {float re, im;} cmpl_zhl;

- Angabe keines Strukturnamens, nur Variable(n) (es können dann keine weiteren Variablen des Typs definiert werden)

struct {float re, im;} cmpl_zhl;

- Angabe keines Strukturnamens, keiner Variable (sinnlos, aber möglich)

struct {float re, im;};

(88)

- Die Komponente einer Struktur wird mit dem Punktoperator „

.

angesprochen.

- Dabei ist der linke Operator die Strukturvariable und der rechte Operator der Komponentenname.

Beispiel: cmpl_zhl.re cmpl_zhl.im

- Wird der Name des Strukturtyps im weiteren Programm nicht benötigt, kann er auch entfallen.

Beispiel: struct {

double re, im;

} cmpl_zhl1, cmpl_zhl2;

- Verschachtelung von Strukturen möglich

Bemerkungen zu struct

(89)

Datenverarbeitung 9. Strukturierte Datentypen

Beispiel:

#include <stdio.h>

void main( ) {

struct {

unsigned short tag;

unsigned short monat;

unsigned int jahr;

} datum;

datum.tag = datum.monat = datum.jahr = 0;

scanf(" %d %d %d", &datum.tag, &datum.monat, &datum.jahr);

printf("Tag: %d Monat: %d Jahr: %d \n",datum.tag, datum.monat, datum.jahr);

(90)

Beispiel:

Eine Kunden-Kartei, bestehend aus Kunden-Daten mit folgender Struktur

KUNDE_n KUNDE_1

NAME VORNAME KONTO-

NR. KONTO- STAND

KUNDE_2

NAME VORNAME KONTO-

NR. KONTO- STAND

KUNDE_3

NAME VORNAME KONTO-

NR. KONTO-

STAND ...

Man kann sich die Kartei auch wie einen Karteikasten vorstellen, der mit Informationen gleicher Struktur (Karteikarten) gefüllt ist.

KUNDE n

KUNDE_3

struct Kunde {

char Vorname [20];

char Name [20];

(91)

Datenverarbeitung 9. Strukturierte Datentypen

9.4 Strukturen mit union

- Vereinigungstyp, in dem zur Laufzeit nur eine Komponente sinnvolle Werte besitzt.

union Strukturname { Datentyp Bezeichner ,

}

Bezeichner ,

;

;

Beispiel: union wert {

float gleitpunkt;

int ganzZahl;

char zeichen;

(92)

Bemerkungen zu union:

- Benutzung entspricht syntaktisch dem Konstrukt struct.

- Die Größe (=Speicherplatzverbrauch/-aufwand) eines Vereinigungstyps entspricht der Größe der aufwendigsten Komponente.

- Der Programmierer trägt die Verantwortung, dass jeweils der „richtige Typ“ benutzt wird.

Beispiel: union wert zahl;

zahl.ganzZahl = 7;

...

float zahl1 = zahl.gleitPunkt;

/* nicht gut… */

(93)

Datenverarbeitung 9. Strukturierte Datentypen

9.5 Einfache selbstdefinierte Datentypen

Definition von Variablen:

bisher:

Bezeichner Datentyp

; ,

Alias auch möglich:

Datentyp

typedef ;

typedef int Length;

Length laenge;

Beispiel:

(94)

Bemerkungen zu typedef:

- typedef erlaubt die Erzeugung eines Alias für existierende Typen.

Beispiel: typedef int ganzzahl;

ganzzahl zahl = 4;

- mittels typedef werden keine neuen Datentypen erzeugt.

- Sinn:

ƒ Portabilität: Maschinenabhängige Datentypen müssen unter

Benutzung von typedef bei einer Portierung nur einmal geändert werden.

ƒ Erhöhung der Verständlichkeit des Quellcodes.

(95)

Datenverarbeitung 10. Zeiger-Datentyp

10. Zeiger-Datentyp

Ziele dieser Einheit:

- Einführung dynamischer Datentypen und deren

Anwendung (in erster Näherung, als Vorbereitung auf verkettete Listen).

- Einblick in C-spezifischen Umgang mit Zeiger-Datentypen.

Referenzen

ÄHNLICHE DOKUMENTE

2 Microcomputer VU 4 3 Für die in diesen Microcomputer-Lehrveranstaltungen abgelegten (Teil-)Prüfungen gelten die folgenden Bestimmungen:. Name der alten

Einige Messwerte (für etwa 150 Sekunden) werden im Vorhinein in einer Excel Tabelle per Zufallszahl aus einem plausiblen Bereich erzeugt und mit passenden Spaltenüberschriften

Die Forschungsarbeit wird von zwei Prüfern [durchgängig m/w] von der Universität Stuttgart benotet, wobei mindestens einer der Fakultät Informatik, Elektrotechnik

Gesamtzahl der Leistungspunkte = 120 (Die Zahlen bedeuten Leistungspunkte eines Moduls pro Semester) 15 LP.

Zur Verbesserung der Effizienz der individuellen Auswahl nicht individueller AO ¨ UFs kann die Anzahl der AO ¨ UFs in einer Datenbank durch Clustering-Methode reduziert werden.

Ein Leistungsstipendium kann Studie- renden für hervorragende Studienleistungen zuerkannt werden und beträgt zwischen ATS 10000.- und ATS 20000.-.. Dem Ansuchen ist eine Bestätigung

Hier lernst du andere dual Studierende des Fachbereichs Elektrotechnik und Informationstechnik kennen und ihr könnt eure Erfahrungen aus dem Studium und den Praxisphasen im

Der Arbeitsaufwand ergibt sich wie folgt: 14 Wochen zu je 3 SWS entsprechen in Summe 42 Stunden Anwesenheit.. F¨ ur die Nachbereitung der Vorlesung und die Vor- und Nachbereitung der