Denn Kommentare mit /*und */beziehungsweise mit //ignorieren sich gegenseitig.
Abbildung 3.2: Die Tücken verschachtelter Kommentare
Verschachtelte Kommentare sind nervig, aber Sie müssen sich jetzt noch keine Gedanken darüber machen.
Die printf- und die scanf-Funktion sind natürlich nicht der einzige Weg, um Text aus- oder einzugeben. Dreimal Nein. Die Sprache C ist voll mit Tricks, um dieses Ziel zu erreichen. Und wenn Sie herausfinden, wie begrenzt und lahm diese sind, dann werden Sie Ihre eigenen Funktionen zum Lesen von Tastatureingaben und zur Ausgabe von Informationen schreiben wollen. Aber bis dahin müssen Sie mit den Bordmitteln leben.
Ein weiterer simpler Weg zur Ein- und Ausgabe ist die Verwendung der Funktionen fgetsund putsaus der s-Familie.
Und tschüss scanf, willkommen fgets
fgetsist nett und einfach. scanfist im Vergleich dazu undurchsichtig. Dennoch machen beide Ähnliches: Zeichen von der Tastatur einlesen und in einer Variablen speichern. fgetsliest allerdings nur Text ein, scanfkann auch numerische Werte und verschiedene Stringarten einlesen.
Das Format von fgetskönnen Sie im Kasten »Die Funktion fgets« sehen.
Ein unfreundliches Programmbeispiel
Es folgt nun das Programm Insult1.c. Das Programm ist praktisch identisch mit dem Programm Whoru.c.
#include int main() { char idiot[21]; printf("Name eines Idioten: "); scanf("%s", idiot); printf("Yep, ich denke auch, dass %s ein Idiot ist.\n", idiot); return 0; }
Listing 3.7:Name: Insult1.c
Geben Sie Insult1.cin Ihrem Editor ein, kompilieren und starten Sie das Programm. Bei Fehlern vergleichen Sie die genaue Schreibweise, Anführungszeichen und Semikolons.
Die Ausgabe sieht dann so aus:
Name eines Idioten: Karl Klammer Yep, ich denke auch, dass Karl Klammer ein Idiot ist.
Mit scanfwird die Eingabe gelesen. Egal, was eingelesen wird, die printf-Anweisung kann es ausgeben.
Das finstere Geheimnis der Sprache C
Eine dramatische Überschrift – aber was hat scanfdamit zu tun? Sicherlich haben Sie schon oft in Artikeln von Speicherüberläufen oder sogenannten Buffer-Overflows gehört.
Nun, daran ist scanfnicht immer unbeteiligt. Aber was hat es dazu beigetragen? In der Sprache C muss sich der Programmierer um alles selbst kümmern. Starten Sie wieder Insult1.c, aber geben Sie einen wirklich langen Namen ein – so wie Donaudampfschifffahrtsgesellschaftseignergattinskindeskinder.
Bei mir stürzt dann das Programm ab.
Sollte sich der Effekt bei Ihnen nicht gleich einstellen, tippen Sie einfach einen noch längeren Namen ein. Wann es genau passiert, ist vom Betriebssystem und vom Compiler abhängig.
Was ist passiert? Erinnern Sie sich: Mit idiot[21]haben wir Speicher für 20 Zeichen (und Nullbyte) reserviert. Und nun füttern Sie aber scanfmit viel mehr Zeichen. Wohin soll er das alles packen? Und genau das ist das Problem. scanfbekommt den Hals nicht voll genug, und liest immer weiter Zeichen ein. Diese werden einfach immer weiter in den Speicher geschrieben, bis irgendwann etwas kaputtgeht – der Programmabsturz ist unausweichlich.
Das klingt zwar harmlos, ist aber eine der großen Sicherheitslücken im Zeitalter des Internets geworden und hat auch den Ruf der Sprache C erheblich beschädigt, denn C ist sehr anfällig dafür.
Durch clevere Eingaben gelingt es Hackern hiermit sogar, Maschinencode in den Speicher zu schmuggeln, der dann ausgeführt wird. Auf diese Weise kann man den Computer fernsteuern oder eigene Programme starten.
Was jetzt? Müssen wir deshalb aufhören, die Sprache C zu benutzen? Nein, Sie müssen einfach nur damit aufhören, Funktionen wie scanfzu verwenden. Es gibt eine sichere Alternative dazu: den großen Bruder fgets. Da ist auch das fwieder. Schauen Sie sich zunächst das Programm InsultSicher.can.
#include int main() { char idiot[20]; printf("Name eines Idioten: "); fgets(idiot, 20, stdin); printf("Yep, ich denke auch, dass %s ein Idiot ist.\n", idiot); return 0; }
Listing 3.8:Name: InsultSicher.c
Es fällt sofort auf, dass fgetsals zweiten Parameter die Zahl 20verwendet. Die kennen wir schon – es ist die Maximallänge von unserem String idiotmitsamt diesem famosen Nullbyte. Damit verhindert fgets, dass mehr Zeichen eingelesen werden können, als Platz vorhanden ist, und Speicherüberläufe wie bei scanfsind damit ausgeschlossen.
Die Funktion fgetsliest über die Tastatur eingegebene Zeichen ein und speichert diese in einer Stringvariablen, die bereits zuvor über das Schlüsselwort charerzeugt worden sein muss. Die Funktion hört mit dem Lesen von Zeichen auf, sobald die
-Taste gedrückt wird. Es werden nur maximal lengthZeichen in den String gelesen. War der String kürzer als lengthund wurde die
-Taste gedrückt, so ist das Zeichen \nebenfalls im String enthalten.
Der String wird von einem Nullbyte beendet.
fgets(var, length, stdin);
fgetsfolgt ein Paar runde Klammern, dahinter ein Semikolon, dazwischen der Name einer Stringvariablen, die Anzahl der Zeichen, die Sie lesen wollen – und eine Variable mit dem Namen stdin.
stdinheißt St an d ard In put und bezeichnet den Zeichenstrom, der von der Tastatur in das Programm fließt (sehr poetisch).
Die fgets-Funktion ist eine vollständige Anweisung in C. Sie endet daher auch immer mit einem Semikolon.
Verwenden Sie für die Arbeit mit Zeichenketten immer nur Funktionen, bei denen die Länge des Strings angegeben werden kann, denn so kann die Funktion prüfen, dass nicht über das Ziel hinausgeschrieben wird. Im Klartext: Wir verwenden scanfab jetzt nie mehr. Ich habe es erwähnt, weil Sie es in vielen Lehrbüchern (noch) finden.
Der dritte Parameter von fgetsheißt stdinund bezeichnet die Standardeingabe ( stan dard input ). Damit ist die Tastatur gemeint. Bei scanfkann man sich diese Angabe sparen, weil diese Funktionen immer automatisch stdinbenutzen. Lassen Sie sich davon zunächst nicht weiter beeindrucken.
Читать дальше