Seltsamer Fehler



  • Vielen Dank!

    Ich dachte immer char *test und char test[] wären äquivalent, also in beiden Fällen ein Zeiger auf die Anfangsadresse?



  • ein zeiger ist nur ein zeiger
    ein array hingegen ist noch etwas mehr.
    wenn ich mit sizeof() die größe eines arrays abfrage, bekomme ich auch wirklich die größe raus und nicht nur die größe eines pointers.

    allerdings werden arrays bei jeder gelegenheit in pointer umgewandelt.

    dein "also in beiden Fällen ein Zeiger auf die Anfangsadresse" stimmt also in gewisser weise.



  • also

    char *test="Hallo";

    ist eine zeigerVARIABLE, die mit dem zeiger auf "Hallo" initialisiert wurde.

    char test[]="Hallo";

    ist eine zeigerKONSTANTE, die auf ein array zeigt, daß mit "Hallo" initialisiert wurde.

    ist ein bißchen verwirrend, da tut sich erstmal jeder C-anfänger schwer mit. soviel zum thema C/C++ sei auch nicht schwerer als Java 😃



  • konfuser, mach ihn nicht konfus 😛

    ich weiß nicht was ihr alle habt, aber bei mir compiliert und läuft der code einwandfrei:

    Hello World!
    Hxllo World!
    

    ich hab GCC und hab als ansi c compiliert.

    wieso soll das nicht gehen? nur weils ein stringliteral ist? das is doch auch nur speicher.



  • Konfusius schrieb:

    char *test="Hallo";

    ist eine zeigerVARIABLE, die mit dem zeiger auf "Hallo" initialisiert wurde.

    Ja. Da, wie bereits erwähnt, String Literale aber read-only sind, ist es sinnvoll, das, worauf der Zeiger verweist, const zu machen. Also

    const char *test="Hallo";
    

    Konfusius schrieb:

    char test[]="Hallo";

    ist eine zeigerKONSTANTE, die auf ein array zeigt

    Nein. test ist ein Array. Ein Array kann jedoch implizit in einen Zeiger auf das erste Element umgewandelt werden.

    char  test[]="Hallo";
    char* test_ptr = test;
    

    ist also völlig legal.

    Konfusius schrieb:

    daß mit "Hallo" initialisiert wurde.

    Ja, der Inhalt des Arrays entspricht "Hallo". Ist jedoch eine Kopie und verweist nicht auf das ursprüngliche Literal.

    c.rackwitz schrieb:

    wieso soll das nicht gehen? nur weils ein stringliteral ist? das is doch auch nur speicher

    Dann besorg dir mal 'ne aktuelle Ausgabe des Standards.

    C99 6.4.5-6 schrieb:

    [...]If the program attempts to modify such an array, the behavior is undefined.



  • ok, das verhalten mag nicht definiert sein...
    was passiert denn, wenn ich es versuche? ich seh keinen grund, wieso es nicht funktionieren sollte oder das programm abstürzen sollte.
    undefiniertes verhalten heißt nur, dass vom standard kein verhalten vorgeschrieben ist. es heißt nicht, dass ich es nicht machen darf oder dass es fehler gibt.

    kann ich mir den standard irgendwo beschaffen? (ohne was zu zahlen, versteht sich)
    welcher compiler hält sich an den standard?



  • c.rackwitz schrieb:

    ok, das verhalten mag nicht definiert sein...
    was passiert denn, wenn ich es versuche? ich seh keinen grund, wieso es nicht funktionieren sollte oder das programm abstürzen sollte.

    Ich schon. Was verstehst du denn an undefiniertem Verhalten nicht? Das bedeutet einfach, es kann alles passieren. Und nicht unbedingt das, was du willst. Natürlich kann es auch sein, dass alles genau wie beabsichtigt funktioniert. Dann kannst du aber genauso gut Lotto spielen. Wenn du Pech hast, machst du aber auch dein System kaputt oder noch Schlimmeres.

    c.rackwitz schrieb:

    undefiniertes verhalten heißt nur, dass vom standard kein verhalten vorgeschrieben ist. es heißt nicht, dass ich es nicht machen darf oder dass es fehler gibt.

    Nein, das nennt sich implementation-defined.

    c.rackwitz schrieb:

    kann ich mir den standard irgendwo beschaffen? (ohne was zu zahlen, versteht sich)

    AFAIK nicht legal.

    c.rackwitz schrieb:

    welcher compiler hält sich an den standard?

    Kommt drauf an, bis zu 'nem gewissen Grad sicherlich viele (wie zB GCC). Ob es einen Compiler gibt, der zu 100% standardkonform ist, bezweifle ich.



  • lässt sich irgendwie rausfinden, was da richtig passiert, wenn es denn schon vom standard undefiniert ist? ich setz mich gerne auf gcc fest.
    du musst wissen, der standard ist mir sowas von egal, wenn ich nur programmieren will und mich so ein "undefiniertes verhalten" von irgendwas abhalten will. wir sind hier ja nicht bei den bürokraten.



  • c.rackwitz schrieb:

    lässt sich irgendwie rausfinden, was da richtig passiert, wenn es denn schon vom standard undefiniert ist? ich setz mich gerne auf gcc fest.

    Nein. Undefiniert ist nunmal undefiniert. Du kannst zwar schauen was GCC macht, das ist aber noch lange keine Garantie, dass beim nächsten mal das gleiche passiert bzw auf einem anderen System sich das Programm genau so verhält wie bei dir.

    btw:
    Ich hab das Programm ebenfalls mit GCC (3.4.2) kompiliert und bei mir kommt folgende Ausgabe

    Hello World!
    

    Wie du siehst, siehst du keine zweite Zeile. Was ist nun passiert? Da kann ich nur raten. Vermutlich ist das Programm beim Schreiben des Literals abgestürzt. Lässt sich ohne Exception Handling nur schwer sagen. Fakt ist, es handelt sich um undefiniertes Verhalten. Und im Sinne des Standards heisst das, dein Programm ist kaputt.

    c.rackwitz schrieb:

    du musst wissen, der standard ist mir sowas von egal, wenn ich nur programmieren will und mich so ein "undefiniertes verhalten" von irgendwas abhalten will. wir sind hier ja nicht bei den bürokraten.

    Da solltest du deine Einstellung nochmal überdenken. Ein Standard hat nichts mit Bürokratie zu tun. Er ist dafür da, um Programmierern grösstmögliche Kompatibilität von Anwendungen auf den unterschiedlichsten Systemen zu garantieren.
    Und String Literale read-only zu machen, hat wie die meisten Sachen einen Sinn. Damit kann ein Compiler String Literale, die im Programm mehrfach vorkommen, aber identisch sind, an eine einzige Speicherstelle legen. Gerade bei Embedded Systemen kann man so wichtigen Speicher sparen. Könntest du nun das String Literal ändern, hättest du an allen verwendeten Stellen diese Veränderung. Nicht wirklich toll, oder?



  • Diese Stringliterale werden ja wahrscheinlich auch meistens einfach in den Codebereich der EXE an eine Konstante stelle mit reingelegt. Selbst wenn es dir dann noch erlaub wäre, in diesem Bereich rumzupfuschen dann könnte sowas passieren:

    void Func()
    {
      char* pText = "Konstant";
      printf(Func);
      pText[0] = '?';
    }
    
    Func(); // Ausgabe: Konstant
    Func(); // 2. Ausgabe: ?onstant
    

    ich meine, was sollte den der Compiler auch da machen, damit es sicherer wird?

    1. Möglichkeit: Das zugewiesene Stringliteral wird lokal auf den Stack kopiert und der Zeiger verweist auf die Kopie (vom endergebnis her recht ähnlich zu char pText[]).
    2. Möglichkeit: Es wird platz auf dem Heap für das Stringliteral angefordert und dorthin kopiert. Nun müsstest du dich aber darum kümmern, das das ganze wieder freigegeben wird.

    Der Standard schreibt halt einfach nicht vor, wo und wie dieses Stringliteral im Speicher zu liegen hat.

    Und der Standard ist sehr wichtig. Ich würde ihn als eine Dokumentation ansehen. Du musst ja auch nicht zwangsweise die "Dokumentation" ANSI Standard verwenden sondern kannst auch die von deinem Compiler benutzen, wenn es dir reicht das dein Programm nur dort läuft. Aber an diese Dokumentation solltest du dich dann wirklich halten, den diese garantiert dir das es so funktioniert wie von dir vorgesehen.



  • kann es sein, dass...

    char *string = "Hello World!";
    

    ein stringliteral ist und

    char string[] = "Hello World!";
    

    ein initialisiertes array ist?

    im ersten fall hab ich einen fehler produzieren können beim schreibzugriff, beim zweiten nicht.
    ich glaub, das war meine einzige verwunderung.



  • c.rackwitz schrieb:

    kann es sein, dass...

    char *string = "Hello World!";
    

    ein stringliteral ist und

    char string[] = "Hello World!";
    

    ein initialisiertes array ist?

    Yep, so könnte man das sagen.
    Im ersten Fall verweist der Zeiger direkt auf das Literal. Im zweiten Fall wird ein unsized Array erstellt, welches mit dem Wert des Literals initialisiert wird, also eine Kopie darstellt.



  • dann bin ich ja zu frieden 🙂
    ich würd normal auch nicht auf die idee kommen, einen pointer mit nem stringliteral zu initialisieren.


Anmelden zum Antworten