Formatstrings

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Formatstrings

    Hallo zusammen,
    Ich hab eine kleine Verständnisfrage.

    Quellcode

    1. int i = 5;char string[4];
    2. strcopy(string, "lala");
    3. printf("address of int: %08x", &i);printf("address of string:%08x", string);



    Beides sollte meinem Wissen nach die Adresse ausspucken. Jedoch frag ich mich, wieso es beim integer ein & braucht, was es beim string nicht braucht?
  • Manfred Kreß schrieb:

    Das & bedeutet, das du auf die Adresse zugreifst (Pointer). Ein Array ist eigentlich ein Pointer. d.h. Deine Variable string speichert die Adresse des ersten Elements. Daher brauchst du die eben nicht auf den Pointer zuzugreifen - es ist schon ein Pointer.

    Gruß
    Manfred
    Gibt dann printf("address of string:%08x", string); nur die Adresse vom ersten bit aus? Was würde dann printf("address of string:%08x", &string); für eine Adresse ausgeben?
  • Manfred Kreß schrieb:

    Ja, das erste BYTE.

    Mit einem &string bekommst du natürlich einen Pointer auf den Pointer. Willkommen in C ;)

    Quellcode

    1. char * s1 = "hallo";
    2. char ** p2 = &s1;
    3. printf("addr %p addraddr %p\n", s1 , p2);
    4. char * s2 = *(p2);
    5. printf("addr %p derefaddr %p\n", s1 , s2);
    Wieso Byte und nicht Bit? Ist pro Adresse immer nur ein Byte oder wie ist das?
  • junky94 schrieb:

    Manfred Kreß schrieb:

    Ja, das erste BYTE.

    Mit einem &string bekommst du natürlich einen Pointer auf den Pointer. Willkommen in C ;)

    Quellcode

    1. char * s1 = "hallo";
    2. char ** p2 = &s1;
    3. printf("addr %p addraddr %p\n", s1 , p2);
    4. char * s2 = *(p2);
    5. printf("addr %p derefaddr %p\n", s1 , s2);
    Wieso Byte und nicht Bit? Ist pro Adresse immer nur ein Byte oder wie ist das?


    char ist ein byte.
    aber es ist ja egal denn es wird ja auf einen punkt gezeigt. wie viel dahinter nutzdaten kommen ist eine andere geschichte!
  • junky94 schrieb:

    Manfred Kreß schrieb:

    Das & bedeutet, das du auf die Adresse zugreifst (Pointer). Ein Array ist eigentlich ein Pointer. d.h. Deine Variable string speichert die Adresse des ersten Elements. Daher brauchst du die eben nicht auf den Pointer zuzugreifen - es ist schon ein Pointer.

    Gruß
    Manfred
    Gibt dann printf("address of string:%08x", string); nur die Adresse vom ersten bit aus? Was würde dann printf("address of string:%08x", &string); für eine Adresse ausgeben?

    Du bist hier wegen der offenen Partamterliste von printf() an einer etwas besonderen Stelle. Lass dich davon also nicht verrückt machen. Aber es wird weder ein Byte noch ein Bit ausgegeben:

    Beides gibt keine Adresse als Typ aus. Was (welcher Typ, nicht welcher Wert) ausgegeben wird, bestimmt nicht der Parametertyp, sondern das Zeichen im Formatstring. Dies ist x. Also wird das ausgegeben, wofür x steht. Das ist ein Integer. Du übergibst aber einen Char. Ein Char ist kein Integer. Das kann sogar gut gehen, weil es Calling-Conventions gibt, die Typumwandlungen vornehmen, weil Chat und INteger ausnahmsweise gleich groß sein können, weil zufällig der Rest mit 0 aufgefüllt wird. Aber es is vom Konzept her nicht richtig.

    Im zweiten Fall wird wieder ein Integer ausgegeben. Du übergibst diesmal eine Adresse. Also wird die Adresse als Integer genommen. Eine Adresse ist kein Integer. Das kann in diesme Falle gut gehen, wenn INteger und Adresse dieselbe Größe haben. Das hängt davon ab, welches Speichermodell du gewählt hast. Hast du das falsche, so wird nur die Hälfte der Adresse ausgegeben, weil dann der Integer nur die halbe Größe hat.

    Langer Rede kurzer Sinn: Das Zeichen im Formatstring muss immer zum übergebenen Parameter passen. Das tut es bei dir in keinem Falle.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Amin Negm-Awad ()

  • Ich weiß nicht, wie lange du dich schon mit C-Programmierung bzw. mit Programmierung im Allgemeinen beschäftigst, aber manche Dinge sind da wirklich grundlegend. Zudem sollte der Unterschied von Bit und Byte auch bekannt sein und auch Dinge wie Stack sollten einem etwas sagen. Das ist nicht böse gemeint und soll dich nicht davon abhalten uns weiterhin zu fragen, aber manchmal ist es auch hilfreich, mal ein Buch darüber in die Hand zu nehmen. Was man sich selbst erarbeitet, sitzt besser, weil man es sich selbst erklären kann. Nochmals - ist nicht böse gemeint, ich habe auch klein angefangen, das liegt nur schon sehr lange zurück. Ich hatte mir damals den Kernighan-Ritchie und den Thomas Plum geschnappt - sind nicht unbedingt die besten Bücher aber der KR ist noch immer als Referenz geeignet.

    In deinem Code ist mir dabei eine Lücke aufgefallen, über die man auch nach Jahren gerne stolpert, die aber sehr gefährlich ist. Dein Code erzeugt unter Umständen eine Stack-Corruption oder einen Buffer-Overflow. Erklärung:

    In C werden Strings immer mit einem NULL-Byte abgeschlossen, welches der Compiler bei Stringkonstanten automatisch anfügt. Das ist eine Konvention. Daher besteht der String "lala" im Speicher aus 5 Bytes. Der Aufruf von strcpy(...) [ohne "o"] kopiert auch dieses NULL-Byte mit, da es ja zum String dazugehört. Die Variable string hat aber nur 4 Bytes reserviert, das fünfte Byte wird also "hinter" die 4 reservierten Bytes geschrieben und dort kann sich ja etwas anderes befinden. Im Allgemeinen werden lokale Variablen (also welche, die in der Funktion definiert werden und nach Ende der Funktion auch wieder verschwinden) auf dem Stack angelegt. Wie die Variablen auf dem Stack verteilt werden, entscheidet der Compiler. In deinem Fall kann es sein, dass beim strcpy() das fünfte Byte eigentlich das erste Byte von i ist, wodurch sich der Wert von i ändert. Bei Little-Endian-Systemen (wie Intel) könnte i dann 0 sein statt 5. Es kann aber auch alles mögliche an sonstigen Dingen passieren, bis zum Crash, wenn auch nicht in dem kurzen Code. So etwas zu finden, kann einen wahnsinnig machen, zumal so etwas oft funktioniert, wenn man mit DEBUG kompiliert, aber abstürzt, wenn man als Release mit Optimierung übersetzt. Im Release-Build kann man aber viel schlechter debuggen um den Fehler zu finden und auf den ersten Blick in den Code sieht es ja nicht soooo falsch aus.

    Das Arbeiten mit Pointern ist in C eine prima Sache, die aber auch sehr gefährlich werden kann. Da muss man immer vorsichtig sein. Daher gibt es einige Programmiersprachen, bei denen Pointer verboten sind.