1. Grundlegende Programmelemente

Werbung
C und C++ (CPP)
1. Grundlegende
Programmelemente
Prof. Dr. Marc Rennhard
Institut für angewandte Informationstechnologie InIT
ZHAW Zürcher Hochschule für Angewandte Wissenschaften
[email protected]
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 1
1
Ablauf
• Hello World in Java und C
• Sprachelemente, Kommentare, Variablen, einfache Datentypen,
Literale
• Deklarationen, Operatoren, Ausdrücke
• Kontrollstrukturen
• Input/Output Funktionen der Standard Library
• Komplexe Datentypen: Aufzählungstyp, Strukturen
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 2
2
Ziele
• Sie erkennen, dass die grundlegende Syntax von C sehr viele
Ähnlichkeiten mit der von Java aufweist
• Sie sehen auch, dass C gewisse Eigenheiten aufweist, welche in Java
nicht zu finden sind
• Sie kennen und verstehen die grundlegenden Programmelemente, die
in C verwendet werden (Kommentare, Variablen, einfache und
komplexe Datentypen, Literale, Deklarationen, Operatoren, Ausdrücke,
Kontrollstrukturen)
• Sie kennen die wichtigsten Input/Output Funktionen der Standard
Library und können diese einsetzen
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 3
3
Hello World (1)
• Java:
/* HelloWorld.java */
public class HelloWorld {
// Hauptprogramm
public static void main(String[] args) {
System.out.println("Hello World in Java");
}
}
• C:
/* helloworld.c */
#include <stdio.h>
/* Hauptprogramm */
int main(void) {
printf("Hello World in C\n");
}
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 4
4
Übung zu Hello World
• Welche Unterschiede und Gemeinsamkeiten erkennen Sie zwischen
den Hello World Programmen in Java und C?
• Ähnlichkeiten:
• Funktion/Methode main als Einstiegspunkt
• Ausgabe des Strings mit "Hello World"
• Geschweifte Klammern (Blöcke), Abschluss eines Befehls mit Semikolon (;)
• Einrücken des Codes
• Unterschiede:
• #include <stdio.h> in C
• Klasse in Java
• Kommentar mit // in Java und /*…*/ in C
• Parameterliste von main in Java mit Argument args[ ] und in C mit void
• Rückgabewert von main in Java void und in C int
• Ausgabe in Java mit System.out.println und mit printf in C
• \n in printf bei C
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 5
5
Überblick über C
• C ist eine prozedurale Programmiersprache (≠ objektorientiert)
• Keine Klassen
• Funktionen statt Methoden
• Ein C Programm besteht im Wesentlichen aus Funktionen
• Jedes C-Programm hat eine main-Funktion Einstiegspunkt ins
Programm
• Es kann beliebig in weitere Funktionen verzweigt werden
• Wird die main-Funktion verlassen, so terminiert das Programm
• Ein C-Programm soll die Endung .c haben (Java: .java)
• Mit einem C-Compiler (zB gcc) wird ein ausführbares Programm erzeugt
(–o spezifiziert den Namen des Programms, default a.out / a.exe)
• $> gcc –o helloworld helloworld.c
• Dieses Programm kann „direkt“ (ohne virtual machine) gestartet werden
• $> helloworld
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 6
Der Java-Compiler (javac) generiert .class-Files. Diese sind nicht direkt, sondern nur via die Java
Virtual Machine (JVM) mit dem Befehl java ausführbar. Dafür sind die class-Files portable, sofern
eine JVM vorhanden ist. Ein C-Programm muss für jedes System neu kompiliert werden, und
manchmal müssen sogar Teile des Source-Codes angepasst werden.
Das mit gcc kompilierte C-Programm erhält nicht den Manen des Quellcodedatei (hier:
helloworld.c). Mit der –o Option kann der Name angegeben werden, den das ausführbare
Programm erhalten muss. Geben Sie nichts an, so erhält das ausführbare Programm je nach
Plattform per Default den Namen a.out oder a.exe.
6
Sprachelemente
• C Programme bestehen aus Schlüsselwörtern, Namen, Konstanten,
Strings, Operatoren und anderen Trenn- und Sonderzeichen
• Trennzeichen sind Space, Tab und Zeilenende
• Ein C-Programm darf die folgenden Zeichen beinhalten
• Klein-und Großbuchstaben: a-z, A-Z
• Ziffern: 0-9
• Sonderzeichen: + - * / \ = , . ; ? " # % & _ ' < > ( ) [ ] { } | ^ ~ @ :
• Schlüsselwörter:
auto
break
do
double
goto
if
signed sizeof
unsigned void
case
else
int
static
while
char
enum
long
struct
volatile
continue
extern
register
switch
const
float
return
typedef
default
for
short
union
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 7
Schlüsselwörter sind reserviert und dürfen nicht als Namen für zB Variablen verwendet werden.
7
Kommentare, Variablen- und Funktionsnamen
• Kommentare können wie folgt in den Code eingefügt werden:
• /* Dieser Kommentar kann sich
über mehrere Zeilen erstrecken */
• /* Natürlich kann er auch nur eine Zeile lang sein */
• // Dieser Kommentar existiert in Java und in C++, nicht aber in C
• // Die Begrenzung erfolgt hier durch das Zeilenende
• Variablen- und Funktionsnamen haben folgende Restriktionen:
• Enthalten Zahlen 0…9; Buchstaben a…z und A…Z, und das Zeichen _
• Gross-/Kleinschreibung wird beachtet; d.h. Hallo und hallo ist nicht
dasselbe
• Das erste Zeichen muss ein Buchstabe oder _ sein
• Darf keines der durch die Sprache reservierten Wörter sein (int, while,
return etc.)
• Beispiele: i, count, MAX_LENGTH, maxValue, getMax(...)
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 8
Konvention: Einfache Variablennamen sollen prinzipiell aus Kleinbuchstaben bestehen (i, count,
limit...).
Für zusammengesetzte Namen verwendet man _ (max_value) oder einzelne Grossbuchstaben
(maxValue).
8
Einfache (primitive) Datentypen
• C kennt nur 4 elementare Datentypen:
char
int
float
double
1
4
4
8
byte
bytes
bytes
bytes
-128 bis 127
-231 bis 231-1
-3.4·1038 bis 3.4·1038
-1.79·10308 bis 1.79·10308
• Zusätzlich gibt es Qualifier (Attribute):
unsigned char
unsigned int
short [int]
unsigned short [int]
long [int]
unsigned long [int]
long double
1 byte
4 bytes
2 bytes
2 bytes
8 bytes
8 bytes
12 bytes
0 bis 255
0 bis 232-1
-32768 bis 32767
0 bis 65535
-263 bis 263-1
0 bis 264-1
-1.2·104932 bis 1.2·104932
• Die Wertebereiche sind hardwareabhängig, die obigen Werte sind
typisch für eine heute übliche 32-Bit Architektur
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 9
Je nach unterliegender Hardware werden verschiedene Anzahl Bytes für ein int verwendet. Die
oben angegeben Grössen bezeichnen die heute auf 32-Bit Rechnerarchitekturen typischen
Grössen für die Datentypen. Auf solchen Rechnern wird ein int also meist durch 4 Bytes dargestellt,
ein short ist meist 2 Bytes und ein long meist 8 Bytes. Die einzige Bedingung, welche C macht, ist
dass ein short sicher nicht länger als ein int und ein long sicher nicht kürzer als ein int sein darf. In
Java ist ein int immer 4 Bytes, ein short immer 2 Bytes und ein long immer 8 Bytes. Die C Standard
Library bietet die Möglichkeit, die Grösse eines bestimmten Datentyps auf dem gegebenen System
zu erhalten (via Headerdateien float.h und limits.h).
Unsigned bedeutet nur positive Zahlen (beginnend mit 0). Default ist immer nicht unsigned. In Java
ist immer alles implizit signed.
Im Zusammenhang mit short und long kann das int weggelassen werden, d.h. short int ≡ short, long
int ≡ long etc.
Allgemeine Regel in C: Aus Präzisionsgründen immer mit double statt float arbeiten.
9
Literale (1)
• Literale sind im Code eingefügte, unveränderliche Werte
• Ganze Zahlen (short, int, long)
• Zahlen, die mit 1…9 beginnen, werden dezimal interpretiert; zB 3987
• Zahlen, die mit 0 (Zahl Null) beginnen, werden oktal interpretiert: zB 037
• Zahlen, die mit 0X oder 0x beginnen, werden hexadezimal interpretiert;
zB 0x23
• Per Default wird eine Dezimalzahl als int interpretiert, eine
oktale/hexadezimale Zahl als unsigned int
• Ist die Zahl für einen int zu gross, wird sie als long interpretiert
• Soll eine Zahl explizit als long interpretiert werden, so wird l oder L
angehängt:
35000l (oder 35000L)
0104270l
0x8868l
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 10
Die explizite Angabe von L oder l bei einer ganzen Zahl kann Sinn machen. Wenn Sie z.B. mehrere
int-Literale addieren und irgendwann das Zwischenresultat grösser wird als was mit einem int
dargestellt werden kann, dann wird das Resultat falsch sein. Wenn Sie die Zahlen aber explizit als
long definieren, dann wird diese Problem nicht auftauchen, ausser Sie überschreiten auch den
Wertebereich eines long.
10
Literale (2)
• Gleitkommazahlen (float, double)
• Weisen einen Dezimalpunkt (zB 3.1415) oder einen Exponenten (zB 1e-2)
auf
• Per Default vom Typ double, kann mit f oder F explizit als float bezeichnet
werden
3.1415f (oder 3.1415F)
• Einzelne Zeichen (char)
• Werden durch ' ' eingeschlossen; zB 'A'
• Gespeichert wird der entsprechende ASCII-Wert (1 Byte) des Zeichens
(A = 65)
• Spezielle Zeichen werden mit \ gebildet; zB \n (new line), \t (horizontal
tab), \\ (backslash), \' (single quote), \" (double quote), \0 (NUL)
• Ein einzelnes Zeichen kann auch durch den ASCII-Wert (dezimal, oktal
oder hexadezimal) ausgedrückt werden:
65, \101, \x41 entsprechen alle dem ASCII Zeichen mit dem Wert 65 (= A)
• Java: Ein char hat die Länge 2 Bytes, Unicode-Codierung
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 11
11
ASCII-Table
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 12
Dies sind die originalen ASCII-Zeichen (0 – 127); dargestellt mit 1 Byte, wobei das führende Bit
immer = 0 ist. Es gibt auch Erweiterungen von 128 – 255 (führendes Bit = 1), die zB die Umlaute
beinhalten.
12
Literale (3), Symbolische Kostanten
• Strings
• Durch Anführungszeichen eingeschlossene Zeichenfolgen; zB "ZHAW"
• Es existiert kein Datentyp String; ein String wird intern als ein Array von
Characters (char) repräsentiert (also die ASCII-Werte der einzelnen
Zeichen)
• Strings werden automatisch durch das ASCII Zeichen NUL abgeschlossen
"ZHAW" entspricht den fünf ASCII Zeichen 'Z' 'H' 'A' 'W' '\0'
Der Speicherplatz in Bytes, den ein String benötigt, ist deshalb immer die Anzahl
Zeichen + 1
Welchen numerischen Wert haben die ASCII Zeichen, mit welchen der String
"ZHAW" intern abgespeichert wird? 90 – 72 – 65 – 87 – 0
• Symbolische Konstanten
•
•
•
•
Machen dann Sinn, wenn die gleiche Konstante mehrfach gebraucht wird
Werden mit #define am Anfang des Programms gesetzt
#define MAX_LENGTH 1000
(kein ; am Ende!)
Während des Kompilierens wird jedes Auftreten von MAX_LENGTH im Code
mit dem entsprechenden Wert (1000) ersetzt
• Also: int length = MAX_LENGTH; int length = 1000;
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 13
Das ASCII-Zeichen NUL ist das erste ASCII-Zeichen der ASCII-Tabelle und besteht aus dem
numerischen Wert 0 (Byte: 00000000).
Sämtliche Befehle, die mit einem # beginnen (also zB #define), sind Präprozessorbefehle (siehe
Kapitel über Modulare Programmierung).
Auch wenn dies sie Sprache nicht verlangt, ist es guter Programmierstil, mit #define definierte
Konstanten mit Grossbuchstaben zu bezeichnen (zB MAX_LENGTH).
13
Deklarationen (1)
• Variablendeklaration (es gibt in C/C++ keine Default-Werte bei der
Initialisierung, ausser bei statischen Variablen!)
double hoehe;
int laenge, breite;
double r, radius = 15.0;
• Konstantendeklaration
const double pi = 3.14159;
• Der Wert von pi kann einmal initialisiert, dann aber nicht mehr verändert
werden
• Typdeklaration
typedef int Index;
• Erlaubt die Definition von neuen Namen für Datentypen;
hier ist zB Index ein anderer Name (Synonym) für int, deshalb sind die folgenden Variablendeklarationen äquivalent:
int i;
Index i;
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 14
Im Gegensatz zu Java erhält eine Variable bei der Initialisierung keinen Default-Wert. Die
Ausnahme sind statische Variablen, siehe dazu das nachfolgende Kapitel. hoehe, laenge und bretet
im Beispiel oben erhalten bei der Deklaration diejenigen Werte, die gerade in den entsprechenden
Speicherzellen, die alloziert werden, stehen. Will man bewusst einen initialen Wert 0 (wie bei Java),
so muss man dies selbst tun mit double hoehe = 0.
Konvention: Mit typedef definierte Typen haben einen Grossbuchstaben am Anfang (zB Index).
Unterschied const und #define: Mit const wird eine „richtige“ Variable alloziert, die einfach nicht
mehr verändert werden kann. Entsprechend stehen auch alle Typen (auch benutzerdefinierte
Typen, z.B. Strukturen in C oder Klassen in C++) zur Verfügung und der Compiler kann ein
sauberes Type-Checking durchführen. Ausserdem gelten die Sichtbarkeitsregeln wie bei normalen
Variablen (siehe späteres Kapitel); eine mit #define generierte Konstante ist immer überall sichtbar.
Der programmiertechnisch saubere Ansatz ist deshalb der, für Konstanten nach Möglichkeit den
obigen Ansatz mit const zu verwenden (insbesondere wenn die Konstante nur innerhalb z.B. einer
Funktion vorhanden sein sollten). Dennoch sieht man häufig auch den Ansatz mit #define,
insbesondere wenn die Konstante in mehreren Funktionen gebraucht wird.
14
Deklarationen (2)
• Variablen werden meist innerhalb von Funktionen deklariert
• Ausnahme: globale Variablen
• Beispiel: Funktion, die km/h und zugehörige m/s-Werte auf dem
Bildschirm ausgibt:
void kmhToMs(void) {
int kmh;
double ms;
const double ratio = 3.6;
/* int-Variable */
/* double-Variable */
/* Konstantes Verhaeltnis */
for (kmh = 0; kmh <= 300; kmh = kmh + 20) {
ms = kmh / ratio;
printf("%d -> %f\n", kmh, ms);
}
}
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 15
15
Operatoren
• Bis auf wenige Ausnahmen (>>> Operator in Java, Pointeroperatoren
in C) gleich wie in Java
•
•
•
•
•
•
•
Arithmetische Operatoren: + - * / % (modulo)
Relationale Operatoren: > >= < <=
Logische Operatoren: && ||
Gleichheitsoperatoren: == !=
Negationsoperator: !
Increment / Decrementoperator: ++ -Bitoperatoren: & (AND) | (OR) ^ (XOR) << (bit shift left)
>> (bit shift right) ~ (Einerkomplement)
• Zuweisung: = += -= *= /= %= &= ^= |= <<= >>=
• Conditional Expression: ? :
• Referenzoperator, Dereferenzoperator: & *
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 16
Sind die beiden Operanden bei der Division ( / ) int-Werte, so wird das Resultat auf einen
ganzzahligen Wert abgerundet. Hier wird konsequent abgerundet, 5/3 (= 1.667) wird also zB zu 1.
In Java bedeutet der >>> Operator einen „Bit-Shift nach rechts, wobei links eine 0 eingefüllt wird“.
Der normale „Bit-Shift right“ Operator füllt links entweder eine 0 oder eine 1 ein, und zwar immer so,
dass das Vorzeichen der Zahl nach dem Shift das gleiche wie vor dem Bit-Shift ist.
16
Order Precedence and Associativity
Symbol
Type of Operation
Associativity
() [] . –>
Expression
Left to right
! ~ ++ -- + - * & (type) sizeof
Unary
Right to left
*
/
Multiplicative
Left to right
+
–
Additive
Left to right
<< >>
Bitwise shift
Left to right
< <= > >=
Relational
Left to right
==
Equality
Left to right
&
Bitwise-AND
Left to right
^
Bitwise-exclusive-OR
Left to right
|
Bitwise-inclusive-OR
Left to right
&&
Logical-AND
Left to right
||
Logical-OR
Left to right
? :
Conditional-expression
Right to left
=
,
%
!=
+= -= *= /= %= &= ^= |= <<= >>= Simple and compound ass.
Sequential evaluation
Right to left
Left to right
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 17
Die Tabelle stammt aus B. Kernigham, D. Ritchie, The C Programming Language. Prentice Hall,
1988, 2nd Edition.
Left to right bedeutet, der Ausdruck wird von links nach rechts ausgewertet (zuerst die linke Seite,
dann die rechte Seite), zB 5 – 3 bedeutet „5 (left) minus 3 (right)“. Right to left ist das Umgekehrte,
zB a = 7 bedeutet „7 (right) wird a (left) zugewiesen“. Klarer wird das in einem
zusammengehängten Ausdruck, zB a = 5 – 3: = ist right to left, also wird zuerst 5 – 3 ausgewertet
und das Resultat erst dann a zugewiesen.
Oft ist es einfacher, mit Klammern ( ) Klarheit zu verschaffen, auch wenn dies nicht nötig ist. Die
wenigsten Programmierer haben die Tabelle oben genau im Kopf...
17
Ausdrücke
• Ein Ausdruck ist die Verbindung von Operanden mit Operatoren:
• 1 + 3, u = 7 * r etc.
• Ausdrücke müssen nicht zugewiesen werden
• (u * 100 + v); ist eine legale Anweisung, die nichts bewirkt
• In Ausdrücken werden alle numerischen Typen implizit in den
„grössten“ Typ gewandelt
• 3/2 int / int grösster Typ = int bleibt bei int / int (ganzzahlige
Division, Rest wird gestrichen) Resultat = 1 (Typ int)
• 3.0/2 double / int grösster Typ = double wird zu double / double
Resultat = 1.5 (Typ double)
• Der Zuweisungsoperator (=) bewirkt, dass der rechte Ausdruck in den
Typ der links stehenden Variablen gewandelt wird
• double r; r = 3/2;
• int i; i = 3.1415;
• int i; i = 2.99 + 3;
/* ergibt r = 1.0 */
/* ergibt i = 3 */
/* ergibt i = 5 */
• Keine Warnungen wie „loss of precision“ wie in Java (gilt generell)!
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 18
Werden int und double im gleichen Ausdruck verwendet, muss man immer aufpassen, dass keine
Rechenfehler passieren. Das Beispiel oben
double r;
r = 3/2;
ergibt als Resultat 1.0, weil durch die höhere „Presedence“ des Divisionsoperators zuerst der
Ausdruck 3/2 ausgewertet wird (= 1) und erst dann das Resultat der Variablen r zugewiesen wird.
Es spielt keine Rolle, ob r ein int oder ein double ist, denn die „Präzision“ ist bei der Division 3/2
unwiderrufbar verloren gegangen.
Um das korrekte Resultat zu erhalten, muss man also
r = 3.0/2;
schreiben (oder auch 3/2.0 oder 3.0/2.0), womit die Division als Division zweier double-Typen
behandelt wird.
18
Übung zu Ausdrücken
• Geben Sie jeweils die Werte der Variablen nach der Ausführung der
einzelnen Programmzeilen an
/* expression.c */
int main(void) {
double x, y = 3.0;
int i, j = 4;
i
x
x
i
i
i
x
= 2.5 + y;
= 5 * i / 3;
= 5.0 * i / 3;
+= j;
= ++j;
= j++;
= 3 + (y = i + 5.0);
/* x = ?
/* i = ?
/*
/*
/*
/*
/*
/*
/*
i
x
x
i
i
i
x
=
=
=
=
=
=
=
y = 3.0
j = 4
5
8.0
8.333333
9
5
j = 5
5
j = 6
13.0 y = 10.0
*/
*/
*/
*/
*/
*/
*/
*/
*/
}
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 19
19
Type Casts
• Ein type cast ist eine explizite Konvertierung von einem Typ in einen
anderen
• Es gibt verschiedene Gründe, eine solche Konvertierung durchzuführen:
• Wandeln einer Gleitkommazahl in einen Integer Wert und umgekehrt
• Wandeln eines void-Pointers in einen Pointer auf einen bestimmten
Datentyp
• Wandeln eines Zeigers auf eine Instanz der Basisklasse in einen Zeiger auf
eine abgeleitete Klasse (C++)
• Eine Art in C, zwei gleichwertige Arten in C++:
• var = (type) expression
• var = type(expression)
/* Operator, C/C++, Java */
/* Funktion, nur C++ */
• Beispiele:
• double d; int i = 5; d = i / 3;
• double d; int i = 5; d = (double) i / 3;
• double d; int i = 5; d = double(i) / 3;
/* d = 1.0 */
/* d = 1.6667 */
/* d = 1.6667
(nur C++) */
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 20
20
Kontrollstrukturen (1)
• Generell: wie in Java
• Kontrollstrukturen können verschachtelt werden
• Einfache Anweisung
• wird mit einem Semikolon (;)
abgeschlossen
c = a + b;
printf("Hello World\n");
• Block
• Zusammenfassung von Anweisungen mittels geschweiften Klammern
• Variablen müssen in C (nicht aber in
C++ oder Java) am Anfang eines
{
Blocks deklariert werden!
int a = 5, b, temp;
b = a;
temp = b;
}
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 21
Verschachtelung von Kontrollstrukturen bedeutet, dass innerhalb einer Kontrollstruktur eine weitere
aufgerufen werden kann, zum Beispiel:
int i, even = 0;
for (i = 0; i < 10; i++) {
if (i % 2 == 0) {
even++;
}
}
Mit sauberem Einrücken des Codes wird die Lesbarkeit signifikant erhöht!
21
Kontrollstrukturen (2)
• If-Else / Else-If
• Ermöglicht Verzweigungen
result = -1;
if (n >= 0) {
result = 1;
}
if (n >= 0) {
result = 1;
} else {
result = -1;
}
if (n > 0) {
result = 1;
} else if (n == 0) {
result = 0;
} else {
result = -1;
}
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 22
Bei einzelnen Anweisungen in einem if, else if oder else können die geschweiften Klammern auch
weggelassen werden. Dies gilt auch für die nachfolgenden Kontrollstrukturen. Oft ist die
konsequente Verwendung von Klammern jedoch übersichtlicher.
Im Zusammenhang mit if gibt es noch einen Operator, den man oft vergisst: Den Conditional
Operator (? :). Damit kann man ein if-Statement sehr kompakt schreiben:
result = ((booleanExpression) ? value1 : value2)
Beispiel:
int x, y, result;
...
If (x > y) {
result = 5;
} else {
result = 7;
}
ist identisch zu:
int x, y, result;
...
result = ((x > y) ? 5 : 7);
22
Kontrollstrukturen (3)
• For-Schleife
• Ermöglicht das wiederholte Durchlaufen eines Programmabschnitts
int sum = 0;
int max = 5;
int i;
for (i = 1; i <= max; i++) {
sum += i;
/* oder sum = sum + i */
}
/* Das geht nicht in C (erst ab C99):
for (int i = 1; i <= max; i++) {... */
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 23
Eine for-Schleife hat in der Klammer (...) drei Teile: Die Initialisierung (i = 1) wird einmal am Anfang
ausgeführt. Die Bedingung (i <= max) wird vor jedem Durchlauf getestet; ist sie false, so wird die
Schleife verlassen. Die Aufdatierung (i++) wird immer am Ende eines Durchlaufs ausgeführt.
23
Kontrollstrukturen (4)
• While- und Do-While-Schleifen
• Ermöglicht das wiederholte Durchlaufen eines Programmabschnitts
int sum = 0;
int max = 5;
int i = 1;
while (i <= max) {
sum += i;
i++;
}
/* oder */
do {
sum += i;
i++;
} while (i <= max);
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 24
Die Do-While Schleife wird immer mindestens einmal durchlaufen, da der Test erst nach einem
Durchlauf geschieht.
In allen drei Schleifen kann continue; verwendet werden, um einen Schleifendurchlauf abzubrechen
und direkt zum Ende der Schleife zu springen. Die Schleife wird aber nicht verlassen, sondern –
wenn die entsprechende Schleifenbedingung true ist - erneut durchlaufen.
24
Kontrollstrukturen (5)
• Switch-Anweisung
• Ermöglicht individuelles Reagieren auf verschiedene Werte einer Variable
switch (n) {
case 1:
result = 1;
break;
case 2: case 3: case 4:
result = 10;
break;
default:
result = 0;
break;
}
• break ist notwendig, da sonst weitere cases abgearbeitet werden!
• Was würde im Beispiel oben ohne alle breaks passieren?
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 25
break kann auch bei for, while und do-while Schleifen verwendet werden und bewirkt, dass die
Schleife direkt verlassen wird.
25
Wo ist denn der Datentyp boolean?
• In C gibt es keinen Datentyp boolean! (in C++ gibt es bool)
• Regel: ein Ausdruck gilt als false, wenn er = 0 ist; sonst gilt er als true
• In beiden Beispielen wird die while-Schlaufe ausgeführt, so lange
x > 0 ist:
int x = 10;
while (x > 0) {
x--;
}
int x = 10;
while (x) {
x--;
}
• Der Ausdruck muss dabei kein ganzzahliges Resultat produzieren
• while(1){...} while(1.5){...} while(-3.1415){...} etc. in
C...
• ...entsprechen alle while(true){...} in Java
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 26
Für eine Endlosschleife schreibt man in C üblicherweise while (1) {...
26
Input/Output (1)
• Die Sprache C enthält eine Standard Library; enthält unter anderem
Input/Output Funktionen
• Werden mit #include <stdio.h> am Anfang eines Programms
eingebunden
• Funktionen für einfachen Input/Output:
• puts("Hello");
• putchar('A');
• c = getchar(void);
/* Ausgabe des Strings Hello auf Standard Output */
/* Ausgabe des Zeichens A auf Standard Output */
/* Einlesen eines Zeichens von Standard Input */
• Funktionen für formatierte Ausgabe:
• Generell: printf(format-string, arg1, arg2,...);
• printf("Hello World\n"); /* Ohne weitere Argumente */
• printf("The sum of %d and %d is %d\n", a, b, a+b);
/* printf mit 3 Argumenten, wobei a+b innerhalb der Funktion ausgewertet
wird; %d bedeutet, dass a, b und a+b als int interpretiert werden */
• Die %d nennt man Konvertierungsoperatoren
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 27
#include in C/C++ ist vergleichbar mit import in Java. Mit #include werden generell Teile der C
Standard Library eingebunden; im Fall hier die Input/Output Funktionen.
Jedes laufende C Programm (auch Java oder ganz generell jedes Programm) kennt Standard
Input, Standard Output und Standard Error. Per default ist Standard Input die Tastatur; Standard
Output und Standard Error entspricht der Konsole auf dem Bildschirm. Beim Start eines
Programms kann Standard Input/Error/Output sehr einfach umgelenkt werden. Ein Programm mit
dem Namen helloworld kann seinen Standard Output zB in das File out umlenken: ./helloworld >
out
27
Input/Output (2)
• Konvertierungsoperatoren:
• %d, %i (int); %u (unsigned int)
• %c (char)
• %s (char *, Zeichen des Strings werden ausgegeben bis \0 gefunden
wird)
• %f (double, float)
• Bei Zahlen können zwischen dem % und dem Konvertierungszeichen
die minimale Länge m (Anzahl Zeichen) des Outputs und die Anzahl
Dezimalstellen d angegeben werden: %m.df
•
•
•
•
double d = 5.12345;
printf("%f", d);
printf("%.3f", d);
printf("%10.3f", d);
/* Output: 5.123450 (default d=6) */
/* Output: 5.123 */
/* Output:
5.123 */
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 28
Ein falsches Konvertierungszeichen wird meist wirren Output generieren, weil dann das Programm
versucht, zB ein int-Wert als double zu interpretieren.
28
Input/Output (3)
• Funktion für formatierte Eingabe:
• Generell: scanf(format-string, arg1, arg2,...);
• Beispiel: Einlesen von 3 Werten in die 3 int Variablen day, month und
year:
• scanf("%d%d%d", &day, &month, &year);
• Achtung: der Adressoperator & ist wichtig (siehe folgende Vorlesung über
Pointer)
• Einlesen auf der Kommandozeile: 24 12 2004<return>
• Oder auch 24<return>
12<return>
2004<return>
• Erst durch die Eingabe des letzten Return werden die Zeichen aus dem
Eingabebuffer gelesen
• Man beachte: auch das letzte Return-Zeichen (\n) wird in den Buffer
eingelesen und steckt nach dem Zurückkehren der scanf-Funktion noch im
Buffer gegebenenfalls mit einem einzelnen getchar() auslesen!
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 29
Wird mit scanf ein double eingelesen, muss der Konvertierungsoperator %lf (statt %f) verwendet
werden. Beim Schreiben mit printf funktioniert %f auch für double.
29
Übung zu Formatiertem Output
• Komplettieren Sie das vorgegebene Programm, welches die Fläche (= pi
* r2) eines Kreises für r = 5, 10, 15 und 20 berechnet und ausgibt
• Gewünschter Output:
Radius
Radius
Radius
Radius
= 5 -> Flaeche
= 10 -> Flaeche
= 15 -> Flaeche
= 20 -> Flaeche
=
78.56
= 314.26
= 707.08
= 1257.04
• Programm: /* outformat.c */
# include <stdio.h>
int main(void) {
const double pi = 3.1415926535;
int r;
for (r = 5; r <= 20; r += 5) {
printf("Radius = %2d -> Flaeche = %7.2f\n",
r, pi * r * r);
}
}
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 30
30
Komplexe Datentypen (1) - Aufzählungstyp
• Der Aufzählungstyp erlaubt die Definition einer Liste von konstanten intWerten
enum wochentage {Montag, Dienstag, Mittwoch,
Donnerstag, Freitag, Samstag, Sonntag};
• Dies weist den Tagen die Werte Montag = 0… Sonntag = 6 zu
• Werte können auch explizit gesetzt werden:
enum frucht {Apfel = 5, Birne = 10, Zitrone = 15};
enum frucht {Apfel = 5, Birne, Zitrone}; /* Birne = 6, Zitrone = 7 */
enum frucht {Apfel, Birne = -1, Zitrone};
/* Apfel = 0, Birne = -1, Zitrone = 0; Werte müssen nicht unterschiedlich sein! */
• Die konstanten Werte in der Liste können in Ausdrücken verwendet
werden
enum frucht {Apfel, Birne, Zitrone};
int essen = Apfel;
essen = Birne + Zitrone;
/* essen = 0 */
/* essen = 3 */
• Seit Java 1.5 gibt es enum auch in Java
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 31
Der erste Wert einer Aufzählung wird per Default zu 0; die weiteren Werte zu 1, 2, 3 etc. Wird
irgendeiner der Werte explizit auf n gesetzt, so werden die nachfolgenden Werte zu n+1, n+2 etc.
Der Name (zB wochentage oder frucht in den Beispielen oben) für einen Aufzählungstyp nach dem
enum ist optional, dennoch wird er häufig verwendet um anzuzeigen, wozu der Aufzählungstyp
überhaupt verwendet wird. Zusätzlich kann dieser Name auch dafür verwendet werden, Variablen
von diesem enum-Typ zu deklarieren, wie auf der nächsten Folie aufgezeigt wird.
31
Komplexe Datentypen (2) - Aufzählungstyp
• Man kann auch Variablen vom Typ eines Aufzählungstyp deklarieren
• Bei der Zuweisung von Werten wird aber nicht erzwungen, dass der
vorgegebene Wertebereich eingehalten wird
enum wochentage {Montag, Dienstag, Mittwoch, Donnerstag,
Freitag, Samstag, Sonntag};
int main(void) {
enum wochentage w1 = Mittwoch;
enum wochentage w2 = 77;
/* w1 hat den Wert 2 */
/* Funktioniert auch,
w2 hat den Wert 77 */
}
• Kombination mit typedef, um enum bei der Variablendeklaration nicht
schreiben zu müssen:
typedef enum {Montag, Dienstag,...} Wochentage;
int main(void) {
Wochentage w1 = Mittwoch;
}
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 32
Werden Variablen vom Typ eines Datentypes deklariert (wie oben gemacht), so handelt es sich
beim effektiven Datentyp dahinter immer um einen int. Sehr viel bringt diese Deklaration von
Variablen mit dem enum-Typ nicht, denn der Compiler prüft nicht, ob dieser Variable dann auch
wirklich nur Werte aus dem Bereich der Aufzählung zugewiesen werden, und entsprechend wird
dieses Feature auch nur selten verwendet.
Die Kombination von typedef und enum sieht man gelegentlich auch, wenn man sich einen
Datentyp bool „basteln“ will (wenn man z.B. nicht direkt mit den numerischen Werten und deren
Interpretation als true/false arbeiten will):
typedef enum {false, true} bool
/* false = 0, true = 1 */
bool flag = true
/* flag = 1 */
while (flag) {...}
32
Komplexe Datentypen (3) - Strukturen
• Erlaubt die Zusammenfassung von Elementen verschiedener Typen in
einen Datentyp
• Entspricht ~ einer Java Klasse bei welcher alle Variablen public sind und die
keine Methoden enthält
• Zuerst muss dieser neue Datentyp deklariert
werden (meist am Anfang eines Programms):
• Danach können Variablen dieses
Typs deklariert/initialisiert werden:
• Strukturen können auch
geschachtelt werden:
struct point3D {
int x;
int y;
int z;
};
struct point3D pt = {2, 4, 6};
struct line3D {
struct point3D start;
struct point3D end;
};
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 33
Während Java Klassen auf dem Heap abgelegt werden, sind Strukturen in C auf dem Stack
abgelegt. Wenn ein int 4 Bytes beansprucht, so benötigt die Struktur im obigen Beispiel 3 * 4 = 12
Bytes Speicherplatz.
33
Komplexe Datentypen (4) - Strukturen
• Der Zugriff auf einzelne Elemente (members) geschieht mit "." (wie
Zugriff auf Elemente einer Java Klasse)
• Wie alle Variablen können Variablen, die den Datentyp der gleichen
Struktur aufweisen, einander zugewiesen werden
/* point3d.c */
#include <stdio.h>
struct point3D { /* Deklaration der Struktur */
int x, y, z;
};
int main(void) {
struct point3D ptA = {2, 4, 6}, ptB;
ptB = ptA;
/* Kopiert die komplette Struktur */
ptA.x = 5;
/* Zugriff auf einzelne Elemente */
ptA.y += ptA.z;
/* Output: A = (5,10,6), B = (2,4,6) */
printf("A = (%d,%d,%d)\n", ptA.x, ptA.y, ptA.z);
printf("B = (%d,%d,%d)\n", ptB.x, ptB.y, ptB.z);
}
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 34
Bei der Zuweisung werden Strukturen komplett kopiert. In diesem Sinne sind Strukturen anders als
Java Klassen, wo bei der Zuweisung von Objekten nur Referenzen auf das Objekt kopiert werden,
das Objekt selbst aber nicht.
34
Komplexe Datentypen (5) - Strukturen
• Der Gebrauch mit struct point3D pt ist relativ mühsam, weil man
das struct-Keyword immer schreiben muss
• In der Praxis wird man die Struktur deshalb oft gleich auch als neuen
Datentyp definiert mit typedef möglich
typedef struct {
Mit
int x;
typedef:
int y;
int z;
} Point3D;
Vgl. ohne
typedef:
struct point3D {
int x;
int y;
int z;
};
• Anschliessend kann man Point3D wie einen Datentypen behandeln; die
Deklaration einer Variablen geschieht entsprechend wie folgt:
Point3D pt =...
/* statt struct point3D pt =... */
• Beachten Sie:
• Name des Typs folgt mit typedef nach der Strukturdefinition
• Konvention: Point3D beginnt mit einem grossen „P“ (mit typedef
definierte Typen sollten immer mit einem Grossbuchstaben beginnen)
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 35
35
Zusammenfassung
• Die Syntax von C hat grundsätzlich viele Ähnlichkeiten mit jener von
Java
• C kennt 4 grundsätzliche einfache Datentypen, wobei die Länge
(Anzahl der Bytes) dieser Datentypen Systemabhängig sind
• char, int, float, double
• Kein boolean in C, dafür Unterscheidung signed/unsigned
• Die Standard Library bietet grundlegende Input/Output Funktionen um
Daten zu lesen und schreiben
• C kennt typedef und struct, welche in Java nicht existieren
Marc Rennhard, 24.02.2010, CPP_Programmelemente.ppt 36
36
Herunterladen