Der Martin: [ C ] Problem mit dem Schlüsselwort char

Beitrag lesen

Hi,

// Darf die Variable "wort1" nur 5 Zeichenwerte haben?
char wort1[5];

ja - so wie du sie deklarierst, hast du Platz für 5 Zeichen vorgesehen. Also 4 Zeichen Nutzdaten und die abschließende 0 als Endekennzeichen.

printf(" Erwarte eingabe: \n");
erg=scanf("%s %s %d",&wort1,wort2, &zahl);

Das kann heikel sein, wie du weiter unten selbst andeutest.

for(a=0;a < lang;a++)
{
  printf("%s",wort1[a]);
   //Sollten hier nicht die Buchstaben des eingegebenen Wortes kommen?? Bekomme aber die Meldung: Speicherzugriffsfehler!

Das ist für den Insider auch logisch. Betrachten wir mal dein Beispiel:

wort1[0] = "S" = 0x53
wort1[2] = "e" = 0x65
wort1[3] = "l" = 0x6C
wort1[4] = "f" = 0x66
wort1[5] = 0

Im ersten Schleifendurchlauf hat der printf()-Aufruf also die Werte:

printf("%s", 0x53);

Das bedeutet: Gib den String aus, der im Speicher ab Adresse 0x53 steht. Nur "gehört" diese Speicheradresse höchstwahrscheinlich gar nicht deinem Programm, sondern einem anderen Programm oder gar dem Betriebssystem selbst. Also greifen hier die Schutzmechanismen, die verschiedene Prozesse gegeneinander abgrenzen sollen.

Was du vorhast, nämlich die Zeichen eines Strings einzeln auszugeben, ist eigentlich ganz einfach - du musst die printf-Funktion nur anweisen, das Argument nicht als String (d.h. als Adresse eines char-Arrays) aufzufassen, sondern tatsächlich als Einzelzeichen. Dafür steht die Formatanweisung %c.

Ist die Variable die ich mit "char" deklariert habe kein Array?
Ich habe zwar:
char wort1[5];
eingegeben und verstehe das so das jetzt nur 5 Zeichen gültig sind, also so:

wort1[0] = "S"
wort1[2] = "e"
wort1[3] = "l"
wort1[4] = "f"
wort1[5] = "\0"

Absolut korrekt.

Gebe ich aber ein Wort mit nicht 5 sondern 10 Zeichen ein, wird das trotzdem angenommen, wieso wenn das doch auf 5 begrenzt ist?

Die Eingaberoutine, die von scanf() intern benutzt wird, kann nicht wissen, wieviel Speicherplatz du für die eingegebenen Werte vorgesehen hast. Sie speichert so viel, wie tatsächlich eingegeben wurde. In deinem Fall merkt man das bei geringfügigen Überschreitungen nicht, weil die nacheinander deklarierten Variablen auch im Speicher wahrscheinlich direkt hintereinander liegen:

[x +  0]  wort1
 [x +  5]  wort2
 [x + 10]  zahl
 [x + 14]  erg
   usw.

Das x vorne steht jetzt für eine beliebige Adresse, an der im Speicher dein Variablenbereich beginnt. Der Absolutwert muss uns nicht interessieren.

Aber pass auf: Wenn du bei der Eingabe von wort1 mehr Zeichen eingibst als vorgesehen, wird die überschüssige Länge bereits in wort2 hineingeschrieben. Bei der nachfolgenden Eingabe von wort2 werden diese überzähligen Zeichen wieder überschrieben.

Die Überprüfung der korrekten Länge von Eingaben, die von außerhalb kommen, ist ein *ganz* wichtiges Thema. Viele gravierende Bugs in bekannten Softwareprodukten kommen von einer Schlamperei in diesem Punkt - das führt dann zu den berüchtigten "buffer overflows": Eingegebene Daten laufen über den vorgesehenen Speicherbereich hinaus und überschreiben andere Daten im Speicher. Oft führt das zu einem Programmabsturz. Wenn man aber den Aufbau und die Funktionsweise eines Programms sehr genau kennt, kann man solche Effekte u.U. ausnutzen, um sogar ein vorhersehbares Fehlverhalten zu provozieren - und schon hat man einen Bug für eventuell bösartige Manipulationen ausgenutzt.

Deswegen -um zu deinem Beispiel zurückzukehren- ist es eine gute Idee, die scanf-Funktionsfamilie zunächst zu meiden und stattdessen z.B. gets() zu verwenden. Damit hat man auch eine Eingabe realisiert, aber man kann eine maximale Länge vorgeben, die dann nicht überschritten wird. Überzählige Zeichen bei der Eingabe werden einfach ignoriert.

So long,
 Martin

--
Lieber eine Fliege im Porzellanladen
als ein Elefant in der Suppe.