1 Theorie | |
→ | 1.1 Die Programmiersprache C |
Das bereits bekannte Beispiel ex001.c zeigt eine sequentielle Abarbeitung, d.h. alle Anweisungen werden der Reihe nach abgearbeitet.
/* Testprogramm zur Quadratflaechenberechnung */
/* Copyright (C) 2014-2017 - HS Schmalkalden. All rights reserved. */
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
/** Hauptprogramm.
@return 0 bei Erfolg, alle anderen Werte bedeuten Fehler.
*/
int
main(void)
{
double slaenge; /* Seitenlaenge */
double flaeche; /* Flaeche */
printf("Bitte Seitenlaenge angeben: ");
scanf("%lg", &slaenge);
flaeche = slaenge * slaenge;
printf("Flaecheninhalt: %lg\n", flaeche);
return 0;
}
/* vim: set ai sw=4 ts=4 expandtab : */
Wir erweitern jetzt das Programm so, dass
die Flächenberechnung nur durchgeführt wird, wenn die eingegebene
Seitenlänge nicht negativ ist.
Andernfalls wird eine Fehlermeldung ausgegeben.
Die if-Anweisung hat zwei Formen:
if (Bedingung) { if-Block }
und
if (Bedingung) { if-Block } else { else-Block }
Ist die Bedingung erfüllt, werden die Anweisungen im if-Block ausgeführt.
Andernfalls werden die Bedingungen im else-Block ausgeführt, falls dieser vorhanden ist.
Beispiel:
/* Testprogramm zur Quadratflaechenberechnung
Die Eingabe wird getestet, es sind nur nichtnegative Seitenlaengen erlaubt.
*/
/* Copyright (C) 2014-2017 - HS Schmalkalden. All rights reserved. */
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
/** Hauptprogramm.
@return 0 bei Erfolg, alle anderen Werte bedeuten Fehler.
*/
int
main(void)
{
double slaenge; /* Seitenlaenge */
double flaeche; /* Flaecheninhalt */
printf("Bitte Seitenlaenge fuer Quadrat angeben: ");
scanf("%lg", &slaenge);
if (0.0 <= slaenge) {
flaeche = slaenge * slaenge;
printf("Flaecheninhalt: %lg\n", flaeche);
}
else {
printf("FEHLER: Seitenlaenge darf nicht negativ sein!\n");
}
return 0;
}
/* vim: set ai sw=4 ts=4 expandtab : */
Die Einrückungen werden so vorgenommen, dass sie die Programmstruktur widerspiegeln. Im Beispiel ex002.c ist sofort ersichtlich, dass die Anweisungen
flaeche = slaenge * slaenge; printf("Flaecheninhalt: %lg\n", flaeche);
in den Zeilen 22 und 23 nur ausgeführt werden, wenn die Seitenlänge slaenge größer oder gleich 0 ist.
Im funktional gleichen Quelltext
#include <stdio.h>
int
main(void)
{
double slaenge;/* Seitenlaenge */
double
flaeche; /* Flaecheninhalt */
printf("Bitte Seitenlaenge fuer Quadrat angeben: ");
scanf("%lg", &slaenge);
if (0.0 <= slaenge)
{
flaeche = slaenge * slaenge;
printf("Flaecheninhalt: %lg\n", flaeche); }
else {
printf("FEHLER: Seitenlaenge darf nicht negativ sein!\n"); }
return 0; }
ist dies nicht sichtbar. Hier ist die Fehlersuche sowohl bei
Compilerfehlern als auch bei Programmfehlern stark erschwert,
eigentlich ist gar keine Bearbeitung möglich.
Achten Sie deshalb auf sinnvolle Einrückungen und eine vernünftige
Struktur Ihres Quelltextes.
Wir wollen nun mehrere Quadratflächen
nacheinander berechnen lassen. Der Einfachheit halber verzichten
wir auf den Test, ob die Seitenlänge nichtnegativ ist.
Am Programmbeginn wird abgefragt, wieviele Quadrate zu berechnen
sind. Die Eingabe des Nutzers wird in der Variable dlauf
abgespeichert.
Anschließend wird eine for-Schleife
for (Starteinstellungen; Fortsetzungsbedingung; Änderung) { Anweisungsblock }
benutzt, um einen Anweisungsblock mehrfach zu durchlaufen.
Die for-Schleife wird vorzugsweise dann eingesetzt, wenn die Anzahl der notwendigen Schleifendurchläufe bereits zu Beginn der Schleife bekannt ist.
/* Testprogramm zur Quadratflaechenberechnung fuer mehrere Quadrate
Dieses Programm demonstriert die for-Schleife
*/
/* Copyright (C) 2014-2017 - HS Schmalkalden. All rights reserved. */
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
/** Hauptprogramm.
@return 0 bei Erfolg, alle anderen Werte bedeuten Fehler.
*/
int
main(void)
{
double slaenge; /* Seitenlaenge */
double flaeche; /* Flaeche */
int dlauf; /* Anzahl Durchlaeufe */
int aktdl; /* Aktueller Durchlauf */
printf("Wieviele Quadratflaechen sollen berechnet werden: ");
scanf("%d", &dlauf);
for(aktdl = 0; aktdl < dlauf; aktdl++) {
printf("Bitte Seitenlaenge fuer Quadrat %d angeben: ", (aktdl + 1));
scanf("%lg", &slaenge);
flaeche = slaenge * slaenge;
printf("Flaecheninhalt: %lg\n", flaeche);
}
return 0;
}
/* vim: set ai sw=4 ts=4 expandtab : */
Ein Mensa-Esser will abnehmen und
beschließt, nur noch Salat-Teller zu essen, bis er sein
Wunschgewicht erreicht hat.
Das Programm ex004.c lässt den Nutzer zunächst das vorgegebene
Anfangsgewicht, das gewünschte Endgewicht und die wöchentliche
Gewichtsabnahme eingeben. Wenn die Eingaben sinnvoll sind, wird
tabellarisch dargestellt, welches Gewicht am Ende einer jeden Woche
erreicht wurde.
Andernfalls wird eine Fehlermeldung ausgegeben.
Zur Ablaufsteuerung wird die while-Schleife
while (Bedingung) { Anweisungsblock }
benutzt.
Bei Abarbeitung einer while-Schleife wird zunächst getestet, ob die
Bedingung erfüllt ist. Falls ja, wird der Anweisungsblock
abgearbeitet und anschließend erneut getestet, ob die Bedingung
erfüllt ist...
Schlägt der Test der Bedingung fehl, wird die Abarbeitung mit der
ersten Anweisung nach der while-Schleife fortgesetzt.
Da bereits der erste Test fehlschlagen kann, wird möglicherweise
der Anweisungsblock gar nicht ausgeführt. Daher heißt diese
Schleife auch abweisende Schleife.
Beispiel:
/* Testprogramm zur Demonstration der while-Schleife */
/* Copyright (C) 2014-2017 - HS Schmalkalden. All rights reserved. */
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
/** Hauptprogramm.
@return 0 bei Erfolg, alle anderen Werte bedeuten Fehler.
*/
int
main(void)
{
double anfgew; /* Anfangsgewicht in kg */
double endgew; /* Endgewicht in kg */
double aprowo; /* Gewichtsabnahme pro Woche in kg */
double jetztg; /* Jetziges Gewicht */
int wochen; /* Anzahl abgelaufener Wochen */
printf("Anfangsgewicht in kg: ");
scanf("%lg", &anfgew);
printf("Endgewicht in kg: ");
scanf("%lg", &endgew);
printf("Gewichtsabnahme pro Woche in kg: ");
scanf("%lg", &aprowo);
if ((0.0 < anfgew) && (0.0 < endgew) && (anfgew >= endgew) && (0.0 < aprowo))
{
wochen = 0;
jetztg = anfgew;
while (jetztg > endgew) {
wochen++;
jetztg = jetztg - aprowo;
printf("Gewicht nach %d Woche(n): %lg kg\n", wochen, jetztg);
}
printf("Es waren %d Salat-Wochen erforderlich.\n", wochen);
}
else
{
printf("FEHLER: Mindestens eine Eingabe ist nicht verwendbar!\n");
}
return 0;
}
/* vim: set ai sw=4 ts=4 expandtab : */
Ein anderer Mensa-Esser ist ebenfalls
gesundheitsbewusst. Er beschließt, mindestens eine Woche lang
Salat-Teller zu essen.
Falls er dann noch über dem gewünschten Endgewicht liegt, will er
die Diät fortsetzen. Nach jeder Woche wird geprüft, ob das
gewünschte Endgewicht erreicht ist. Falls das jeweils aktuelle
Gewicht noch immer größer als das gewünschte Endgewicht ist, wird
die Diät fortgesetzt.
Zur Ablaufsteuerung wird die do-while-Schleife
do { Anweisungsblock } while (Bedingung);
benutzt.
Bei Abarbeitung einer do-while-Schleife wird zunächst der
Anweisungsblock abgearbeitet und anschließend getestet, ob die
Bedingung erfüllt ist. Ist die Bedingung erfüllt, wird nochmals der
Anweisungsblock ausgeführt und die Bedingung getestet...
Ist die Bedingung nicht erfüllt, wird die Abarbeitung mit der
ersten Anweisung nach der Schleife fortgesetzt.
Der Anweisungsblock wird in jedem Fall mindestens einmal
ausgeführt, da der Test der Bedingung nach der Ausführung des
Anweisungsblockes erfolgt. Daher heißt diese Schleife auch
nichtabweisende Schleife.
Beispiel:
/* Testprogramm zur Demonstration der do-while-Schleife */
/* Copyright (C) 2014-2017 - HS Schmalkalden. All rights reserved. */
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
/** Hauptprogramm.
@return 0 bei Erfolg, alle anderen Werte bedeuten Fehler.
*/
int
main(void)
{
double anfgew; /* Anfangsgewicht in kg */
double endgew; /* Endgewicht in kg */
double aprowo; /* Gewichtsabnahme pro Woche in kg */
double jetztg; /* Jetziges Gewicht */
int wochen; /* Anzahl abgelaufener Wochen */
printf("Anfangsgewicht in kg: ");
scanf("%lg", &anfgew);
printf("Endgewicht in kg: ");
scanf("%lg", &endgew);
printf("Gewichtsabnahme pro Woche in kg: ");
scanf("%lg", &aprowo);
if ((0.0 < anfgew) && (0.0 < endgew) && (anfgew >= endgew) && (0.0 < aprowo)) {
wochen = 0;
jetztg = anfgew;
do {
wochen++;
jetztg = jetztg - aprowo;
printf("Gewicht nach %d Woche(n): %lg kg\n", wochen, jetztg);
} while (jetztg > endgew);
printf("Es wurden %d Salat-Wochen eingelendgewt.\n", wochen);
}
else {
if (0.0 >= anfgew) {
printf("FEHLER: Das Anfangsgewicht muss groesser als 0 sein!\n");
}
if (0.0 >= endgew) {
printf("FEHLER: Das Endgewicht muss groesser als 0 sein!\n");
}
if (endgew > anfgew) {
printf(
"FEHLER: Das Endgewicht muss kleiner als das Anfangsgewicht sein!\n"
);
}
if (0.0 >= aprowo) {
printf(
"FEHLER: Die Gewichtsabnahme pro Woche muss groesser als 0 sein!\n"
);
}
}
return 0;
}
/* vim: set ai sw=4 ts=4 expandtab : */
Ein ausländischer Student kennt die Bedeutung unseres Notensystems nicht und möchte die Zahlenwerte durch ein Programm gern in verständliche Worte übersetzt haben.
Das Programm benutzt die switch-Anweisung:
switch (int-Ausdruck) { case Wert1: { Anweisungsblock1 } break; case Wert2: { Anweisungsblock2 } break; ... default: { Standard-Anweisungsblock } break; }
Je nachdem, welchen Wert der int-Ausdruck hat, wird einer
der Anweisungsblöcke ausgeführt. Hat der Ausdruck den Wert
Wert1, wird Anweisungsblock1 ausgeführt. Hat der
Ausdruck den Wert Wert2, wird Anweisungsblock2
ausgeführt...
Entspricht der Wert des Ausdruckes keiner der aufgeführten
Konstanten, wird der Standard-Anweisungsblock aus dem
default-Zweig ausgeführt, falls der default-Zweig vorhanden
ist.
Beispiel:
/* Testprogramm zur Demonstration der switch-Anweisung */
/* Copyright (C) 2014-2017 - HS Schmalkalden. All rights reserved. */
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
/** Hauptprogramm.
@return 0 bei Erfolg, alle anderen Werte bedeuten Fehler.
*/
int
main(void)
{
int note; /* Note als Zahlenwert */
printf("Geben Sie die Note ein (Zahlenwert 1...5): ");
scanf("%d", ¬e);
switch (note) {
case 1: {
printf("Sehr gut.\n");
} break;
case 2: {
printf("Gut.\n");
} break;
case 3: {
printf("Befriedigend.\n");
} break;
case 4: {
printf("Genuegend.\n");
} break;
case 5: {
printf("Ungenuegend. Pruefung nicht bestanden.\n");
} break;
case 6: {
printf("Diese Note gibt es beim Studium nicht.\n");
printf("In der Schule bedeutet diese Note: Besonders schlecht.\n");
} break;
default: {
printf("Eine solche Note gibt es nicht!\n");
} break;
}
return 0;
}
/* vim: set ai sw=4 ts=4 expandtab : */
Quelle: CERT C Coding Standard 〈1〉
int broetchen_im_schrank; broetchen_im_schrank = /* ... Nachzaehlen ... */ if (broetchen_im_schrank) { abend_essen(); } else { einkaufen_gehen(); }schreiben, sondern stattdessen
int broetchen_im_schrank; broetchen_im_schrank = /* ... Nachzaehlen ... */ if (0 < broetchen_im_schrank) { abend_essen(); } else { einkaufen_gehen(); }also immer Vergleichsoperationen vornehmen, die als Resultat ein logisches "wahr" oder "falsch" haben.
if (5 = note) { printf("Durchgefallen.\n"); }zu einer Fehlermeldung des Compilers. Damit wird der Fehler schnell gefunden und berichtigt.
if (note = 5) { printf("Durchgefallen.\n"); }dazu, dass die Variable note nicht mit 5 verglichen wird sondern auf 5 gesetzt. Die Bedingung ist immer positiv, weil der Wert von "note = 5" 5 ist und somit ungleich 0.
if (5 > (note = finde_note_fuer_studenten(name))) { printf("Bestanden.\n"); }zulässt und diese auch häufig in älteren Quelltexten zu finden sind, sollten diese nicht verwendet werden.
note = finde_note_fuer_studenten(name); if (5 > note) { printf("Bestanden.\n"); }geschrieben werden.
if (a < b < c) { ... }Richtig ist stattdessen:
if ((a < b) && (b < c)) { ... }
Quelle: GNU Coding Standards 〈2〉
if ((EINE_GANZ_GANZ_LANGE_KONSTANTE == eine_ganz_ganz_lange_variable) || (EINE_ANDERE_GANZ_LANGE_KONSTANTE == eine_andere_variable)) { ... }Der trennende Operator (hier ||) steht in derselben Spalte wie der Beginn des ersten Operanden.
wert = eine_ganz_ganz_lange_variable * eine_andere_lange_variable + noch_eine_variable * langsam_wird_es_langweilig;Der trennende Operator (hier +) steht in derselben Spalte wie der Beginn des Terms.
if (Bedingung) { }
for (Starteinstellungen; Bedingung; Änderung) { }
while (Bedingung) { }
do { } while (Bedingung);
switch (int-Term) { case Wert1: { } break; case Wert2: { } break; default: { } break; }Fügen Sie erst danach die Anweisungsblöcke ein, verwenden Sie mehrere Leerzeichen oder einen Tabulator zur Einrückung.
/* Testprogramm mit verbesserter Fehlerbehandlung
Bei fehlerhafter Eingabe wird sofort eine Fehlermeldung ausgegeben,
Abfrage weiterer Eingaben und Berechnung werden nicht vorgenommen.
*/
/* Copyright (C) 2014-2017 - HS Schmalkalden. All rights reserved. */
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
/** Hauptprogramm.
@return 0 bei Erfolg, alle anderen Werte bedeuten Fehler.
*/
int
main(void)
{
double anfgew; /* Anfangsgewicht in kg */
double endgew; /* Endgewicht in kg */
double aprowo; /* Gewichtsabnahme pro Woche in kg */
double jetztg; /* Jetziges Gewicht */
int wochen; /* Anzahl abgelaufener Wochen */
printf("Anfangsgewicht in kg: ");
scanf("%lg", &anfgew);
if (0.0 < anfgew) {
printf("Endgewicht in kg: ");
scanf("%lg", &endgew);
if (0.0 < endgew) {
if (anfgew >= endgew) {
printf("Gewichtsabnahme pro Woche in kg: ");
scanf("%lg", &aprowo);
if (0.0 < aprowo) {
wochen = 0;
jetztg = anfgew;
do {
wochen++;
jetztg = jetztg - aprowo;
printf(
"Gewicht nach %d Woche(n): %lg kg\n", wochen, jetztg
);
} while (jetztg > endgew);
}
else {
printf(
"FEHLER: Gewichtsabnahme/Woche muss groesser als 0 sein!\n"
);
}
}
else {
printf(
"FEHLER: Endgewicht muss kleiner als Anfangsgewicht sein!\n"
);
}
}
else {
printf("FEHLER: Das Endgewicht muss groesser als 0 sein!\n");
}
}
else {
printf("FEHLER: Das Anfangsgewicht muss groesser als 0 sein!\n");
}
return 0;
}
/* vim: set ai sw=4 ts=4 expandtab : */
1 | http://www.securecoding.cert.org |
2 | http://www.gnu.org/prep/standards/standards.html |