Struktur eines C

Werbung
1
III. Programmieren mit C
III.1 Struktur eines C-Programmes
1.1. Beispiel und Grobstruktur
/****************************************************************/
/*
Programm bsp1.c
*/
/* Berechnung der Fl. eines Dreicks aus den 3 Seiten nach der
*/
/* Heronischen Formel
*/
/* Autor: A.B.Zeh
Datum: 1.10.07
*/
/****************************************************************/
/* Anweisungen für den Präprozessor */
#include <stdio.h>
#include <math.h>
/* wegen Ein- und Ausgabefktn. */
/* wegen Quadratwurzel */
/* Jetzt folgt die Funktion main (Hauptfunktion) */
main( ) {
float a,b,c,s,rad,F;
/* Block beginnt mit { */
/* Variablenvereinbarungen, Bezeichner wie
beim Dreieck üblich */
/* Prompt für die Eingabe */
/* Eingabe von a */
/* dito für b */
printf("\nSeite a: ");
scanf("%f",&a);
printf("\nSeite b: ");
scanf("%f",&b);
printf("\nSeite c: ");
/* dito für c */
scanf("%f",&c);
s = 0.5*(a+b+c);
/* Berechnung von s */
rad = s*(s-a)*(s-b)*(s-c); /* Berechnung von rad */
F = sqrt(rad);
/* Quadratwurzel aus rad */
printf("\nFlächeninhalt = %8.2f",F);
/* Ausgabe des Flächeninhaltes */
}
/* schließende Klammer; Ende des Programmes */
• Kommandos für den Präprozessor des C-Compilers beginnen mit #
• #include veranlaßt den Präprozessor, das dahinter genannte File einzulesen. Dieses ist
Bestandteil der Standard-Bibliothek von C.
Das File stdio.h (standard-input-output-header) enthält u.a. die hier benutzten Funktionen
printf und scanf (zur Aus- bzw. Eingabe)
Das File math.h enthält mathematische Funktionen, u.a. sqrt für die Quadratwurzel.
• Jedes C-Programm enthält die „Funktion“ main, mit deren Ausführung die Abarbeitung des
Programmes gestartet wird.
• Alle Namen (Variable, Konstanten, ...) müssen in C vereinbart werden; im Beispiel werden
die Variablen a, b, c, s, rad, F als vom Typ float vereinbart (Gleitpunktzahlen)
• Dann folgen Aufrufe von printf und scanf, danach Wertzuweisungen (eigentlich Ausdrücke
mit „Seiteneffekt“) und schließlich die Ausgabe des Flächeninhaltes.
2
1.2. Einfache Standard-Datentypen
Ein Datentyp legt den Wertebereich fest, aus dem Variable dieses Typs Werte bekommen
können. Datentypen werden durch Namen bezeichnet. Man kann Typen definieren. Es gibt
aber einfache Datentypen, die standardmäßig zur Verfügung stehen:
A. Ganze Zahlen: Es gibt folgende Typen
Name
min. mögl. Wert
SCHAR_MIN ≤ -127
0
CHAR_MIN
SHRT_MIN ≤ -32767
0
INT_MIN ≤ -32767
0
LONG_MIN ≤ -2 147 438 647
0
signed char
unsignd char
char
[signed] short
unsigned short
[signed] int
unsigned int
[signed] long
unsigned long
max mögl. Wert
SCHAR_MAX ≥ 127
UCHAR_MAX ≥ 255
CHAR_MAX
SHRT_MAX ≥ 32767
USHRT_MAX ≥ 65535
INT_MAX ≥ 32767
UINT_MAX ≥ 65535
LONG_MAX ≥ 2 147 483 647
ULONG_MAX ≥ 4.294.967.295
Dabei ist char implementationsabhängig entweder signed char oder unsigned char.
Die Konstanten dieser Typen werden i.Allg. wie üblich dezimal geschrieben; es gibt aber auch
oktale Darstellung (Präfix 0 (Null)) oder hexadezimale Darstellung (Präfix 0X); auch kann
man den Typ festlegen durch einen Suffix, z.B. ist 3701L vom Typ long.
Der Typ char (Zeichen) ist also in C ein „integer“-Typ, weil intern (meist nach ASCII) so
(in 1 Byte) gespeichert. Bei Ein- und Ausgabe wird entsprechend Formatangabe konvertiert.
Konstanten vom Typ char werden in Hochkommas eingeschlossen, z.B. ‘a’ oder ‘B’.
Die oben angegebenen Konstanten SCHAR_MIN,... stehen in limits.h.
B. Gebrochene Zahlen (Gleitpunktzahlen)
Es gibt die Typen
float,
double,
long double
float garantiert 6 signifikante Dezimalziffern u. einen Zahlbereich zwischen 1E-37 und 1E+37
double garantiert 10 signifikante Dezimalziffern u. einen Zahlbereich wie bei float
Konstanten werden (wie üblich) mit einem Dezimalpunkt geschrieben oder mit einem E (e)
und nachfolgendem Exponenten, z.B.
3.078
-7.2E-10
1.0e25
Konstanten sind standardmäßig vom Typ double. 1.0f wäre eine Konstante vom Typ float.
3
Achtung! C hat keinen Typ Boolean.
Boolesche Ausdrücke, z.B. x < 1, erhalten einen integer-Wert; dabei steht der Wert 0
für false und jeder andere Wert für true.
1.3. Konstanten- und Variablenvereinbarung
a) Eine Konstantenvereinbarung beginnt mit dem Schlüsselwort const , z.B.
const float PI = 3.14;
const int MAXZAHL = 1000;
const char ANTWORT = ‘J’;
Die Konstante PI ist dann vom Typ float und hat den Wert 3,14 usw.
• Die Namen der Konstanten mit großen Buchstaben zu schreiben (und die der Variablen
mit kleinen), ist übliche Konvention.
• Die definierten Werte der Konstanten sind fest; sie können nicht vom Programm her (zur
Laufzeit) geändert werden!
• Vorteil: Bei einer notwendigen Änderung des Wertes einer Konstanten (bei Programmänderung) braucht die Änderung nur bei der Definition zu erfolgen.
b) Eine Variable wird vereinbart durch Voranstellung des Typs, z.B.
int anzahl;
float radius, umfang;
char antwort;
Man kann auch einen Wert zuweisen, z.B.:
int gesamt = 100;
char antwort = ’J’;
c) Namen
Dinge werden mit Namen (Bezeichner, identifier) bezeichnet. Im Beispiel sind a, b, c , ...
Namen. Namen werden nach folgender Syntax gebildet:
<letter> ::= a | b | c | ... z | A | B | C | ... | Z | _
<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<identifier> ::= <letter> {<letter> | <digit>}
(Unterstreichungsstrich!)
• C ist „case-sensitive“, d.h. z.B. ZAHL, zahl und Zahl sind verschiedene Bezeichner
• Die maximale Länge eines Bezeichners ist 31
• Namen sollten nicht möglichst kurz gewählt werden, sondern der Name soll die Bedeutung
des bezeichneten Dinges widerspiegeln, z.B.
anzahl_der_birnen
4
• Es gibt Schlüsselworte; diese können nicht als Namen benutzt werden:
char, const, double, enum, float, int, long, short, signed, sizeof, struct, typedef,
union, unsigned, void, break, case, continue, default, do, else, for, if, goto, return,
switch, while, auto, extern, register, static, volatile
d) Kommentare
Werden durch /*
Programmen
*/ eingeschlossen. Wichtiges Hilfsmittel zur Erhöhung der Lesbarkeit von
1.4. Elementare Ein- und Ausgabe
1.4.1. Elementare Ausgabe (auf dem Bildschirm)
Erfolgt durch Standardfunktion printf :
printf(steuerstring, ausdr1, ... , ausdrn);
Es wird der steuerstring ausgegeben!
Die Werte der anderen Argumente (Ausdrücke) werden sukzessive ausgegeben, wenn in
steuerstring Formatangaben eingebettet sind, z.B.
printf(“Die Zahl %d ist eine Unglückszahl\n“, 13);
erzeugt die Ausgabe
Die Zahl 13 ist eine Unglückszahl
Dabei ist \ (Backslash) das sog. Fluchtsymbol, das das nachfolgende Zeichen als
Sonderzeichen definiert: \n steht für Zeilenschaltung (new line). Anderes Beispiel:
printf(“\“Hallo!\“ sagte er.“);
erzeugt die Ausgabe
“Hallo!“ sagte er.
Das obige Beispiel benutzt die Formatangabe %d für den Datentyp int. Man hat allgemein
Format
Datentypen
%d
%c
%f, %e, %g
%ld
%s
signed char, int, short
char
float, double
long
string-Typ
5
Man kann weitere Formatangaben machen:
a) Die Weite des Ausgabefeldes - dies ist die Anzahl der mindestens ausgegebenen Zeichen Ausgabe erfolgt rechtsbündig, z.B.
printf(“;%4d;%3d;%2d;\n“, 187, 187, 187);
printf(“;%4s;%3s;%2s;\n“, “hi“, “hi“, “hi“);
liefert
; 187;187;187;
; hi; hi;hi;
Soll die Ausgabe linksbündig erfolgen, so ein - vor der Weite:
printf(“;%8s;%-8s;\n“, “rechts“, “links“);
liefert
;
rechts;links
;
b) Die Genauigkeit folgt einem Punkt. Z.B. ist %5.3s ein solches Format. Der Effekt
hängt vom Format-Spezifikator ab:
• bei %s ist die Genauigkeit die maximale Anzahl von zu druckenden Zeichen:
printf(“;%2.4s;%2.4s;%2.4s; %2.4s; %2.4s;\n“, “a“, “ab“, “abc“ ,“abcd“, “abcde“);
ergibt
; a;ab;abc;abcd;abcd;
• bei ganzen Zahlen ist die Genauigkeit die minimale Anzahl der zu druckenden Ziffern:
printf(“%.2d:%.2d\n“, 18, 6);
ergibt
18:06
• bei reellen Zahlen ist die Genauigkeit für %f und %e die Anzahl der Nachkommastellen;
für %g die Gesamtzahl der signifikanten Ziffern.
%f druckt Darstellung mit Dezimalpunkt
%e druckt Darstellung mit Exponent
%g druckt „optimale“ Darstellung
6
Beispiel:
radius = 1.116;
Avogadro = 6.02e23
printf(“%f %6.3f %8.2f\n“, radius, -12.81963, Avogadro/1e19);
printf(“%e %6.3e %8.2e\n“, radius, -12.81963, Avogadro/1e19);
printf(“%g %6.3g %8.2g\n“, radius, -12.81963, Avogadro/1e19);
liefert
1.116000 -12.820 60200.00
1.116000e+00 -1.282e+01 6.02e+04
1.116 -12.8
6e+04
(bei Borland C++)
1.4.2. Elementare Eingabe (über Tastatur)
• grundsätzlich: Alle eingetippten Zeichen werden nach dem Drücken von
in einem
Eingabepuffer abgelegt und dann von Eingabefunktionen verarbeitet.
• Zum Einlesen von Zahlen wird scanf benutzt:
scanf(steuerstring, adr1, ..., adrn);
scanf ist analog zu printf aufgebaut. In steuerstring sind Formatangaben enthalten, die
festlegen, wie die eingelesenen Zeichen interpretiert werden. Dabei ist
Datentyp
Format
int
long
float
double
char
%d
%ld
%e, %f, %g
%le,%lf,%lg
%c
Eingabe
Dez.-zahl mit Vorzeichen
Dez.-zahl mit Vorzeichen
Gleitpunktzahl oder ganze Zahl
Gleitpunktzahl oder ganze Zahl
ein Zeichen
adr1, ..., adrn sind Adressen von Variablen. Der Typ dieser Variablen muß entsprechend der Tabelle zur jeweiligen Formatangabe passen!
Dann werden die eingetippten Werte diesen Variablen zugewiesen (an die entsprechenden
Speicherstellen geschrieben).
Z.B. bei
int i, j;
float x;
char zei1;
scanf(“%d %d %f %c“, &i, &j, &x, &zei1);
Wird bei der Abarbeitung dann eingetippt:
10 20 3.145 abc
7
so erhalten die Variablen i, j, x, zei1 die Werte 10, 20, 3.145 bzw. ‘ ‘.
Die Zeichen abc bleiben im Puffer!
- & ist der Adreßoperator: &i ist die Adresse der Variablen i. & darf nicht vergessen
werden
- Zahleneingaben sind durch mindestens ein Leerzeichen zu trennen
- Anzahl der Formatangaben und Anzahl der Adressen sollte übereinstimmen.
• Die Funktion getchar() liest ein Zeichen und gibt es als Wert zurück.
• Beim Einlesen mittels scanf treten bei falsch eingetippten Werten - etwa Buchstaben statt
Ziffern - Fehler auf, die zum Absturz des Programmes führen können, z.B. wird bei
scanf(“%d %d %d“, &i, &j, &k);
mit Variablen i, j, k vom Typ int eingetippt
12 ABC 37
so erhält i den Wert 12. Dann soll ein Wert für j eingelesen werden. Da aber A nicht dazu
paßt, macht scanf hier Schluß! ABC 37
bleibt im Puffer! Beim nächsten Leseversuch
wird i.a. wieder ein Fehler auftreten usw.
Lösung:
Benutzung des von scanf zurückgegebenen Wertes um festzustellen, ob ein
Fehler aufgetreten ist! scanf gibt als Wert die Anzahl der korrekt eingelesenen
Werte zurück!
Beseitigung des falschen Pufferinhaltes durch sukzessiven Aufruf von getchar!
Im folgenden Beispiel wird das demonstriert, wobei schon while-Schleifen benutzt werden.
8
/***********************************************************************/
/*
Programm input_check
*/
/* Demonstration von Input-Checking
*/
/***********************************************************************/
#include <stdio.h>
main() {
int anzahl_input, i, j, k;
printf("Geben Sie 3 Werte ein: ");
anzahl_input = scanf("%d %d %d", &i, &j, &k);
while(anzahl_input < 3) {
/* Fehler ist aufgetreten */
/* Puffer wird geleert, indem jedes Zeichen
bis Zeilenende gelesen wird */
while(getchar() != '\n') { /* leerer Schleifenkörper */
}
/* Jetzt Nachricht ausgeben */
printf("Sie haben nur %d Werte richtig eingegeben\n", anzahl_input);
printf("Noch einmal: \n");
anzahl_input = scanf("%d %d %d", &i, &j, &k);
}
/* Jetzt war die Eingabe richtig */
printf("Ihre richtige Eingabe war %d, %d, %d\n", i, j, k);
return 0;
}
Bemerkung: Der Typ char ist ein „integer“-Typ; intern sind Zeichen nach ASCII-Code
gespeichert. Man kann die Umwandlung von Zeichen in ASCII-Code und
umgekehrt durch Formatangaben erreichen, wie das folgende Beispiel zeigt:
#include <stdio.h>
main() {
int i;
char ch;
printf("Ganze Zahl bitte: ");
scanf("%d", &i);
getchar();
printf("Zeichen bitte: ");
scanf("%c", &ch);
printf("Zu %d gehört das Zeichen %c \n", i, i);
printf("Zum Zeichen %c gehört der ASCII-Code %d\n", ch, ch);
}
Ein Beispiel für die Abarbeitung des Programmes wäre:
Ganze Zahl bitte: 65
Zeichen bitte: A
Zu 65 gehört das Zeichen A
Zum Zeichen A gehört der ASCII-Code 65
9
wobei die unterstrichenen Zeichen gerade die eingetippten Zeichen sind.
1.5. Ausdrücke
1.5.1 Arithmetische Ausdrücke
Die Werte der Operanden und die Werte der Ausdrücke sind von einem ganzzahligen oder
reellen Typ.
Werden gebildet aus
•
•
•
•
•
(paarweise) runden Klammern
Operatoren
Konstanten
Variablen
Funktionsaufrufen
Die wichtigsten Operatoren sind:
C - Operator
+
*
/
%
=
Zweck
Addition
Subtraktion und Negation
Multiplikation
Division
Restbildung
Zuweisung an Variable
% ergibt den Divisionsrest bei Division von 2 ganzen Zahlen; z.B. 22%5 ergibt 2
Beispiele für Ausdrücke sind
math. Schreibung
Ausdruck in C
5+2x
x(x-y+27)
x+y
4xy
5+2*x
x*(x-y+27)
(x+y)/(4*x*y)
Für die Auswertung (Berechnung) eines Ausdruckes sind entscheidend
a) Vorrangregeln (für die Operatoren)
b) Reihenfolge der Anwendung bei gleichem Rang; z.B. haben * , / und % den
gleichen Rang, und hier werden dann die Operationen von links nach rechts
ausgeführt - Linksassoziativität; z.B.
a/b/c bedeutet
(a/b)/c
Eine Gesamtübersicht über die Vorrangregeln folgt später.
10
• Die Division von integer - Werten liefert einen integer - Wert, z.B. 22/5 ergibt 4 (ganzzahlige Division)
• Der Zuweisungsoperator = ist tatsächlich ein Operator; eine Zuweisung, etwa x = 2.0
liefert den Wert 2.0 und als „Seiteneffekt“ wird der Variablen x der Wert 2.0 zugewiesen.
(Auf der linken Seite von = muß immer eine Variable stehen.)
Möglich ist zum Beispiel
x = 3 * (y = 5);
a = b = c = 1;
(= ist rechtsassoziativ!)
• (Zum Unglück) hat C Operatoren, die eine kurze Schreibweise ermöglichen:
Das sind: ++ , -- , += , -= , *= , /= , %=
Dabei sind ++ und -- postfix oder präfix.
++ erhöht den Wert einer (ganzzahligen oder reellen) Variablen um 1:
i++;
bedeutet
i = i+1;
-- erniedrigt den Wert einer solchen Variablen um 1:
i--;
bedeutet
i = i-1;
• k = ++i; bedeutet
k = i++; bedeutet
• x += 10;
diff -= 2;
prod *= 3;
quot /= 7;
rem %= 12;
bedeutet
„
„
„
„
i = i+1; k = i;
k = i; i = i+1;
x = x+10;
diff = diff - 2;
prod = prod * 3;
quot = quot/7;
rem = rem % 12;
Mathematische Standardfunktionen (in math.h )
Name
Bedeutung
Arg.-typ
Erg.-typ
cos(x)
sin(x)
tan(x)
cosh(x)
sinh(x)
tanh(x)
acos(x)
asin(x)
atan(x)
atan2(y, x)
log(x)
log10(x)
exp(x)
cos x
sin x
tan x
cosh x
sinh x
tanh x
arccos x
arcsin x
arctan x
arctan(y/x)
ln x
log10x
ex
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
double
11
pow(x,y)
sqrt(x)
fabs(x)
xy
x
|x|
double
double
double
double
double
double
Ferner noch in stdlib.h
abs(i)
labs(i)
rand()
|i|
int
int
|i|
long
long
ganze Zufallszahl zwischen 0 und RAND_MAX ≥ 32767
Eine Zufallszahl zwischen 1 und 6 erhält man durch 1+ rand()%6
Typumwandlung:
Man kann integer- und real-Typen in Ausdrücken mischen; es wird bei Bedarf eine
Typumwandlung vorgenommen; immer in den „höheren“ Typ:
1. Kein Ausdruck erhält den Typ char oder short; solche werden in int’s umgewandelt.
2. Wenn 2 Operanden den gleichen Typ haben, so hat das Ergebnis diesen Typ
3. Wenn Typen der Operanden verschieden sind, so wird (compilerabhängig):
• Wenn int’s einen kleineren Bereich als long’s haben, so
int → unsigned int → long → unsigned long → float → double →long double
Z.B.: int multipliziert mit long: int wird in long umgewandelt, dann multipliziert
• Wenn int’s gleich long’s sind, so
int → long oder unsigned int → unsigned long → float → double →
long double
Z.B.: ein Wert long, der andere unsigned int, so werden beide in unsigned long
umgewandelt.
1.5.2. Logische Ausdrücke
In C gibt es im strengen Sinne keine Booleschen Ausdrücke, da diese Zahlenwerte liefern;
0 für falsch und 1 für wahr.
Vergleichsoperatoren:
<
<=
>
>=
==
!=
kleiner
kleiner oder gleich
größer
größer oder gleich
gleich
ungleich
So liefert der Ausdruck 7 < 1 den Wert 0; dagegen liefert 7 != 1 den Wert 1
12
Die logischen Operatoren von C sind
&&
||
!
z.B.:
und (Konjunktion)
oder (Disjunktion)
not (Negation)
x > 0 && y < 0
!(x > 0) && y < 0
13
Vorrangregeln:
Operatoren
Assoziativität
( ) (Fkt.-aufruf) [ ] (Index) . (Feldauswahl)
-> (indir. Auswahl)
++
-+ (unär)
links
! (not) ∼ (bitweises Komplement) (cast) sizeof
- (unär)
* (Indirektion)
& (Adressse)
rechts
links
*
/
%
+
-
(additiv)
links
<<
>>
(shift)
links
<
<=
>
==
!=
(Gleichheit)
&
(bitweises und)
links
^
(bitweises entweder oder)
links
|
(bitweises oder)
links
&&
(und)
links
||
(oder)
links
?:
(konditional)
rechts
=
&=
+=
^=
,
(Kommaoperator)
-=
|=
(multiplikativ)
>=
(Vergleiche)
*=
/=
%=
(Zuweisungen)
links
links
<<=
>>=
rechts
links
Der Kommaoperator erlaubt die sukzessive Auswertung, z.B. i = 1, j = 2; ist ein
Ausdruck; sein Wert ist 2
Zugehörige Unterlagen
Herunterladen