Eine Woche Wetterdaten
AFB I–IIDie Wetter-AG hat auf dem Schuldach eine Messstation aufgebaut. Jeden Mittag wird die Temperatur in Grad Celsius gespeichert. Mila schreibt ein C-Programm, das für eine Woche den Mittelwert und den wärmsten Tag ausgibt.
#include <stdio.h> int main(void) { double temp[7] = {14.5, 17.0, 12.5, 19.5, 21.0, 16.5, 18.0}; int n = sizeof(temp) / sizeof(temp[0]); int imax = 0; double summe = 0.0; for (int i = 0; i < n; i++) { summe = summe + temp[i]; if (temp[i] > temp[imax]) { imax = i; } } printf("Mittelwert: %.1f Grad\n", summe / n); printf("Maximum: %.1f Grad am Tag %d\n", temp[imax], imax + 1); return 0; }
Ihr Mitschüler Paul ändert die Schleifenbedingung zu i <= n, „damit auch der letzte Tag sicher dabei ist“. Das Programm lässt sich ohne Warnung übersetzen. Beim ersten Start erscheint als Mittelwert eine riesige negative Zahl mit über 80 Stellen, beim zweiten Start wieder 17.0.
- Geben Sie den Wert von
temp[2], den größten zulässigen Index sowie die Werte vonsizeof(temp)undnan (typische Größen). - Ermitteln Sie die Ausgabe des Programms. Halten Sie dabei fest, bei welchem Schleifendurchlauf sich
imaxändert. - Begründen Sie, warum der Compiler Pauls Fehler nicht meldet und warum sich das Programm bei jedem Start anders verhalten kann.
Hinweise
Hinweis zu Aufgabe a)
double belegt typisch 8 Byte.Hinweis zu Aufgabe b)
i, temp[i], summe und imax an. imax ändert sich nur, wenn ein Wert größer als das bisherige Maximum ist.Hinweis zu Aufgabe c)
i <= n benutzt? Prüft C beim Zugriff temp[i], ob der Index gültig ist?Erwartungshorizont
Erwartungshorizont zu Aufgabe a)
temp[2] = 12.5 (dritter Tag). Größter zulässiger Index: 6. sizeof(temp) = 7 · 8 Byte = 56 Byte (typisch), n = 56 / 8 = 7.
Erwartungshorizont zu Aufgabe b)
| i | temp[i] | summe | imax |
|---|---|---|---|
| 0 | 14.5 | 14.5 | 0 |
| 1 | 17.0 | 31.5 | 1 |
| 2 | 12.5 | 44.0 | 1 |
| 3 | 19.5 | 63.5 | 3 |
| 4 | 21.0 | 84.5 | 4 |
| 5 | 16.5 | 101.0 | 4 |
| 6 | 18.0 | 119.0 | 4 |
imax ändert sich bei i = 1, 3 und 4. Mittelwert: 119.0 / 7 = 17.0.
Mittelwert: 17.0 Grad Maximum: 21.0 Grad am Tag 5
Erwartungshorizont zu Aufgabe c)
Mit i <= n läuft die Schleife bis i = 7 und liest temp[7]. Dieses Element gibt es nicht: Das Array hat nur die Indizes 0 bis 6.
C prüft Array-Grenzen nicht. temp[7] ist für den Compiler nur „Anfangsadresse von temp plus 7 · 8 Byte“ — syntaktisch korrekt, also übersetzt er ohne Fehler. Zur Laufzeit wird gelesen, was zufällig hinter dem Array im Speicher liegt (undefiniertes Verhalten). Das kann bei jedem Start etwas anderes sein, daher einmal eine absurde Zahl in der Summe und einmal ein unauffälliges Ergebnis. Richtig ist i < n.
Neles Vokabeltrainer
AFB II–IIINele programmiert für ihre Schwester in Klasse 5 einen Vokabeltrainer. Ihr erster Test mit einem einzigen Wort funktioniert nicht: Auch wenn sie genau house eintippt, meldet das Programm „Leider falsch“.
#include <stdio.h> int main(void) { char loesung[] = "house"; char eingabe[20]; printf("Haus auf Englisch: "); scanf("%s", eingabe); if (eingabe == loesung) { printf("Richtig!\n"); } else { printf("Leider falsch, richtig ist %s.\n", loesung); } return 0; }
vokabel.c:9:17: warning: comparison between two arrays [-Warray-compare]
9 | if (eingabe == loesung) {
| ^~Später sollen drei Vokabeln abgefragt werden; bei einer falschen Antwort soll das Programm zusätzlich verraten, wie viele Buchstaben die Lösung hat. Nele ist sicher: „char eingabe[20] reicht immer, so lange englische Wörter tippt in Klasse 5 niemand.“
- Überprüfen Sie Neles Vergleich
eingabe == loesungmithilfe der Warnung und korrigieren Sie die Zeile. - Erweitern Sie das Programm um eine Funktion
int frage(char deutsch[], char englisch[]), die eine Vokabel abfragt und 1 (richtig) oder 0 (falsch) zurückgibt; bei falscher Antwort nennt sie die Lösung und deren Buchstabenzahl.mainfragt drei Vokabeln ab und gibt aus, wie viele richtig waren. - Nehmen Sie Stellung zu Neles Aussage über
char eingabe[20].
Hinweise
Hinweis zu Aufgabe a)
<string.h> vergleicht Zeichenketten, und was liefert sie bei Gleichheit?Hinweis zu Aufgabe b)
strlen (ohne '\0'); für %d können Sie das Ergebnis mit (int) umwandeln. In main genügt ein Zähler, zu dem die Rückgabewerte addiert werden.Hinweis zu Aufgabe c)
'\0' stehen muss? Was passiert bei einer längeren Eingabe, wenn C keine Grenzen prüft? Denken Sie auch an Eingaben, die gar keine Vokabeln sind.Erwartungshorizont
Erwartungshorizont zu Aufgabe a)
Ein Array-Name steht für die Adresse seines ersten Elements. eingabe == loesung vergleicht deshalb die Anfangsadressen zweier verschiedener Arrays — die sind nie gleich, egal was eingetippt wurde. Genau darauf weist die Warnung „comparison between two arrays“ hin.
Korrektur: #include <string.h> ergänzen und if (strcmp(eingabe, loesung) == 0) schreiben — strcmp vergleicht Zeichen für Zeichen und liefert 0 bei Gleichheit.
Übrigens steht auch in scanf("%s", eingabe) zu Recht kein &: eingabe ist schon eine Adresse.
Erwartungshorizont zu Aufgabe b)
#include <stdio.h> #include <string.h> int frage(char deutsch[], char englisch[]) { char eingabe[20]; printf("%s auf Englisch: ", deutsch); scanf("%19s", eingabe); if (strcmp(eingabe, englisch) == 0) { printf("Richtig!\n"); return 1; } printf("Falsch, richtig ist %s (%d Buchstaben).\n", englisch, (int) strlen(englisch)); return 0; } int main(void) { int richtig = 0; richtig = richtig + frage("Haus", "house"); richtig = richtig + frage("Baum", "tree"); richtig = richtig + frage("Schmetterling", "butterfly"); printf("%d von 3 richtig\n", richtig); return 0; }
Haus auf Englisch: house Richtig! Baum auf Englisch: tre Falsch, richtig ist tree (4 Buchstaben). Schmetterling auf Englisch: butterfly Richtig! 2 von 3 richtig
Bewertet werden: Vergleich mit strcmp, strlen für die Buchstabenzahl, Rückgabewert 1/0, Zählen in main. Die Breitenangabe in %19s gehört zu Teilaufgabe c).
Erwartungshorizont zu Aufgabe c)
In char eingabe[20] passen höchstens 19 Zeichen, denn das Endezeichen '\0' braucht ein eigenes Byte. Für echte Vokabeln reicht das meist (auch „butterfly“ hat nur 9 Buchstaben).
Aber: scanf("%s", …) schreibt ohne Prüfung weiter, wenn jemand länger tippt — aus Versehen, im Spaß („aaaaaaaaaaaaaaaaaaaaaaaaaaaa“) oder weil ein langes deutsches Wort wie „Donaudampfschifffahrt“ (21 Zeichen) eingegeben wird. Dann werden Bytes hinter dem Array überschrieben: undefiniertes Verhalten, im schlimmsten Fall Absturz oder eine Sicherheitslücke.
Stellungnahme: Die Aussage ist nur im Normalfall richtig. Ein Programm darf sich nicht auf brave Eingaben verlassen; mit scanf("%19s", eingabe) wird die Länge sicher begrenzt. Eine vollständige Antwort nennt die 19-Zeichen-Grenze, die Folge einer zu langen Eingabe und eine Absicherung.
