String verwirrung



  • Hallo Zusammen,

    ich bin Neueinsteiger und gerade etwas verwirrt. Wenn ich das richtig verstanden habe, besteht ein String nicht nur aus den Chars selbst sondern auch noch aus dem Char \0 am Ende. Zum Beispiel: Besteht "Hallo" eigentlich aus: "HALLO\0".

    Wenn das stimmt, dann verstehe ich folgendes nicht:

    #include "stdio.h"
    
    int main()
    {
    char arr[5];
    
    arr[0]='H';
    arr[1]='A';
    arr[2]='L';
    arr[3]='L';
    arr[4]='0';
    
    printf("%s",arr);
    
    return 0;
    }
    

    Mir wird hier "Hallo!" ausgegeben. Müsste der String nicht eigentlich nach dem 2ten 'L' abgeschnitten werden da ich nur für 5 Chars speicher angefordert habe, jedoch 5 Chars mit Buchstaben belege?

    Hoffe ihr könnt mir grad aushelfen.



  • printf gibt bei %s solange aus, bis eine '\0' (bzw, 0) kommt.

    Du hast als letztes Zeichen das Zeichen für die Ziffer Null. '0' ist ewtas anders als '\0'

    In C gibt es keine Überprüfung auf die Einhaltung bzw. Verletzung von Arraygrenzen.



  • 'o'! = '\0' ist mir klar..
    Das ist ein o und keine Null.

    Also wird hier Speicher beschrieben den ich in Zeile 5 gar nicht angefordert hab?



  • Dass Strings bei '\0' enden ist nur eine Konvention. Du kannst auch eine Zeichenkette haben die nicht mit '\0' endet, das ist dann halt kein C-String.

    Du forderst hier Speicher für 5 Zeichen an, und schreibst 5 Zeichen. Da prinft allerdings bis zum abschließenden '\0' ausgibt, gibt es viel zu viel aus. Auch Speicher den du eigentlich nicht lesen darfst. 😉
    Und doch, das ist eine Null und kein o.
    Und wenn dir "Hallo!" ausgegeben wird, hast du den falschen Code gepostet.


  • Mod

    NewGuy schrieb:

    Also wird hier Speicher beschrieben den ich in Zeile 5 gar nicht angefordert hab?

    Nein, im Gegenteil. Es wird durch das printf lesend auf Speicher zugegriffen, der zufällig hinter deinem Array steht. printf für %s ist nicht groß anders als:

    printf_s(const char* string)
    {
      while(*string != '\0') // Solange kein Nullzeichen
      {
        putchar(*string);   // Gib aktuelles Zeichen aus
        ++string;           // Gehe zum nächsten Zeichen
      }
    }
    

    Hier endet dein char-Array aber nicht auf einem Nullzeichen, sondern auf dem Buchstaben 'O'. printf geht danach einfach weiter, bis eventuell irgendwann mal zufällig ein Nullzeichen im Speicher steht. Falls du keine komischen Zeichen in deiner Ausgabe hattest, dann stand zufällig ein Nullzeichen direkt hinter deinem Array. Das muss aber nicht so sein und darauf darfst du dich nie verlassen (abgesehen davon, dass es sowieso falsch ist, hinter das Array zuzugreifen).

    Das Array selber ist nicht von alleine mit einem Nullzeichen beendet. Das musst du da schon selber reinschreiben, wenn du damit wie mit einer Zeichenkette arbeiten möchtest.



  • DarkShadow44 schrieb:

    Und doch, das ist eine Null und kein o.

    Denke er hat sich verschrieben. O == 0 in dem Fall.

    Wenn ich das laufen lass bekomm ich "HALLO0". Ist denke ich kompletter Zufall was nach dem Wort kommt, je nachdem was dahinter im Speicher liegt.



  • Ja das ist es und vor allem UB, weil auf undefinierten Speicher zugegriffen wird, ob nun lesend oder auch schreibend ist irrelevant.



  • Frohes Neues Jahr Leute!

    Die String-Terminierung mit '\0` stellt nichts anderes als den Wert 0 dar.
    Würde man

    arr[4] = '\0';
    

    schreiben und den Wert des chars mit

    printf(" %d ", arr[4]
    

    aufrufen, würde man als Ergebnis die Zahl 0 erhalten.
    Da hat DirkB Recht.
    Es gibt auch Strings, wo der String mit
    dem Carridge-Return-Zeichen terminiert wird. Da würdes du am
    Ende die Zeichen 10 und 13(dezimal) finden.
    Dein Compiler wird anscheinend automatisch das char-Array mit
    Null initialisieren. Verlassen würde ich mich in der Praxis
    aber darauf nicht!
    Würdest du

    arr[4]= 0;
    

    oder wie oben initialisieren, würde printf nur "HALL" ausgeben.
    Ansonsten kann dir passieren, das wie DarkShadow44 schrieb,
    Zeichen aus dem Speicher verwurstet werden, die nicht
    ausgegeben werden sollten.



  • Ein Stringliteral (Text zwischen "") ist (bei einem C-Compiler) immer Nullterminiert.



  • Es gibt auch Strings, wo der String mit
    dem Carridge-Return-Zeichen terminiert wird.
    Meinst du "auch Sprachen"? In C ist immer \0 am Ende.

    Dein Compiler wird anscheinend automatisch das char-Array mit
    Null initialisieren. Verlassen würde ich mich in der Praxis
    aber darauf nicht!
    Wenn der Compiler das nicht tut ist er kaputt.

    K&R, 2nd ed, S.86 §4.9 sagt eindeutig zu Arrays:

    If there a fewer initializers for an array than the number specified, the missing elements will be zero for external, static and automatic variables.



  • besserwisser schrieb:

    Es gibt auch Strings, wo der String mit
    dem Carridge-Return-Zeichen terminiert wird.
    Meinst du "auch Sprachen"? In C ist immer \0 am Ende.

    Dein Compiler wird anscheinend automatisch das char-Array mit
    Null initialisieren. Verlassen würde ich mich in der Praxis
    aber darauf nicht!
    Wenn der Compiler das nicht tut ist er kaputt.

    K&R, 2nd ed, S.86 §4.9 sagt eindeutig zu Arrays:

    If there a fewer initializers for an array than the number specified, the missing elements will be zero for external, static and automatic variables.

    Bringt dir leider nichts, wenn du gar nicht initialisierst...



  • Also ich hab eben mal probeweise folgendes compiliert und "Müll" bekommen:

    int main()
    {
        char array[5];
        int i;
    
        for(i=0;i<5;i++)
        {
            printf("%d ",array[i]);
        }
    
    }
    

    von daher immer schön mittels

    for(i=0;i<5;i++)
    {
    array[i]=0;
    }
    

    initialisieren oder mittels calloc() speicher anfordern. 😉



  • char array[5] = {0}
    geht auch



  • Oder mit memset



  • Da hab ich wohl was falsch verstanden. 😞 doofe Formulierung...



  • roflo schrieb:

    char array[5] = {0}
    geht auch

    char a[5]={ /* hier steht nichts! */ }; scheint schon zu reichen (jedenfalls bei meinem Test, keine Ahnung was der Standard sagt), aber es muss ein {} her.



  • Der Standard sagt dazu: Syntaxfehler.

    Wenn du selber zugibst, keine Ahnung zu haben, halt einfach die Klappe.



  • Wutz schrieb:

    Der Standard sagt dazu: Syntaxfehler.

    Der gcc frisst es.

    Wenn du selber zugibst, keine Ahnung zu haben, halt einfach die Klappe.

    Irren ist menschlich Herr Professor! 👎



  • Du hast keine Ahnung wovon du redest.
    Also trolle dich dahin woher du kamst und verschone die Welt mit deinen dümmlich-naiven Weisheiten.


  • Mod

    besserwisser schrieb:

    Wutz schrieb:

    Der Standard sagt dazu: Syntaxfehler.

    Der gcc frisst es.

    Das ist nicht das Kriterium für (oder auch gegen) die Korrektheit eines Sprachkonstrukts. Das was du beschreibst ist ein Feature des GCC. Wenn du mit der pedantic-Einstellung compilierst, wird dir der GCC bei den leeren Klammern einen Fehler schmeißen.

    Wer Wutz nicht glaubt (egal wie unhöflich er ist, er weiß wovon er redet), der möge den Standard zu den Themen Initialization (6.7.8 in C99) und Assignment Operators (6.5.16 in C99) lesen.

    PS: Ich sollte noch erwähnen, dass die leeren Klammern in C++ erlaubt sind. Das ist vermutlich auch der Grund, wieso der GCC diese versteht.


Anmelden zum Antworten