sscanf schreibt falsche Werte nach int



  • Ich wollte eigentlich nur einen Datenstring in 2 Teile zerlegen und sie in Integer konvertieren. Alles läuft sauber durch, keine Fehler. Allerdings scheint sscanf fehlerhaft ausgeführt zu werden.

    Der Debugger liefert folgendes:

    foo1 = 666
    foo2 = 5666
    

    Gewünscht ist aber, dass foo2 den Wert 5 hat. Wie die 666 aus foo1 dahinter kommt, verstehe ich nicht. atoi liefert ebenfalls fehlerhafte Ergebnisse.

    Als Ursache vermute ich die Leerzeichen im Datenstring, denn ohne sie funktioniert es. Aber ich kann mir da echt keinen Reim draus machen momentan.

    Jemand eine Ahnung, wie das zustande kommt?

    // Der Code wurde aufs Wesentliche reduziert
    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
       //struct FooInteger foo_int = {0,0};
       int foo1, foo2;
       // Der zu zerlegende String
       const char data_string[7] = {"666   5"};
       char* buffer = (char*)(&data_string);
    
       // Speicher belegen, um den Datenstring zu zerlegen
       char foo1_string[3]; // 3 Bytes reservieren
       char foo2_string[4]; // 4 Bytes reservieren
    
       /*****   DATEN STRING ZERLEGEN   *****/
       // 1. Teilstring als char abspeichern (3 Byte)
       strncpy (foo1_string, buffer, 3);
       buffer += 3; // und ausschneiden
    
       // 2. Teilstring als char abspeichern (4 Byte)
       strncpy (foo2_string, buffer, 4);
    
       buffer = NULL; // Für den Debugger
    
       /*****   WERTE ZU INT KONVERTIEREN   *****/
       sscanf(foo1_string, "%d", &foo1);
       sscanf(foo2_string, "%d", &foo2);
    
       return 0;
    }
    


  • lustigerweise funktioniert es bei mir 😃
    aber kann mir schon nen reim drauf machen.
    du terminierst die strings nicht.. sscanf such bis '\0' gefunden wurde.
    evtl legt der compiler die strings bei dir direkt hintereinander (also im speicher ist erst foo2_string danach foo1_string abgelegt), woraus 5666 entstehen könnte.



  • EDIT: Ah, habe vergessen die einzelnen Teilstrings mit 0 zu terminieren. Danke 😉


  • Mod

    ppohlmann schrieb:

    du terminierst die strings nicht.. sscanf such bis '\0' gefunden wurde.

    Halbrichtig. Es liegt schon an der fehlenden Terminierung der Zeichenketten, aber (s)scanf gibt sich mit jeder Art von Whitespace zufrieden.



  • SeppJ schrieb:

    ..., aber (s)scanf gibt sich mit jeder Art von Whitespace zufrieden.

    bzw. in diesem Fall alles was nicht zu "%d" passt.
    Und das sind alle Zeichen außer den Ziffern und evtl. '+' und '-' am Anfang



  • Äh...

    sscanf(data_string, "%d %d", &foo1, &foo2);
    

    ? Dann kannst du dir den ganzen Stringkopierkram sparen.



  • @ seldon: Du hast da eventuell einen kleinen Denkfehler. In diesem Beispiel mag das zwar stimmen, aber es gibt Probleme, sobald 'data_string' einen Inhalt wie beispielsweise "6664444" hat. sscanf kann das meines Wissens nach nicht so trennen, wie es hier gewollt ist und wie es in meinem momentanen Code gewünscht ist. Nur als Hinweis für künftige Leser. Ansonsten natürlich guter Tipp. 😉



  • s1ckn3ss schrieb:

    [...] sscanf kann das meines Wissens nach nicht so trennen, wie es hier gewollt ist [...]

    "Kein Schwein" kann ohne weitere Angabe wissen, wie es "6664444" trennen soll...

    Vielleicht feste Breiten?

    #include <stdio>
    
    int main( void )
    {
    	const char * const foo = "6664444";
    
    	int a, b;
    
    	sscanf( foo, "%3d%4d", &a, &b );
    
    	printf("a = %d\nb = %d\n", a, b );
    }
    


  • s1ckn3ss schrieb:

    const char data_string[7] = {"666   5"};
    

    Das ist natürlich ein (klassischer) Anfängerfehler.
    Jede String-Funktionalität auf dieser Variable produziert undefiniertes Verhalten, da auf einen Speicherbereich außerhalb des definierten Arrays zugegriffen wird.



  • Swordfish schrieb:

    s1ckn3ss schrieb:

    [...] sscanf kann das meines Wissens nach nicht so trennen, wie es hier gewollt ist [...]

    "Kein Schwein" kann ohne weitere Angabe wissen, wie es "6664444" trennen soll...

    Vielleicht feste Breiten?

    #include <stdio>
    
    int main( void )
    {
    	const char * const foo = "6664444";
    
    	int a, b;
    
    	sscanf( foo, "%3d%4d", &a, &b );
    
    	printf("a = %d\nb = %d\n", a, b );
    }
    

    Auch das hatte ich schon lange ausprobiert gehabt. Führt bei mir zu Abstürzen!



  • Dann hast du irgendwas anderes falsch gemacht. Vermutlich war einer deiner Buffer ein Zeichen zu kurz; in deinem Code waren sie das nämlich alle.



  • Hab die Leerzeichen jetzt durch 0en ersetzt, damit sscanf sie auch vernünftig einlesen kann. Jetzt funktionierts auch in meinem Code. 😉 Danke.

    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
        const char foo[8] = "6660044\0";
        int a, b;
    
        sscanf( foo, "%3d%4d", &a, &b );
        printf("a = %d\nb = %d\n", a, b );
    
        return 0;
    }
    


  • Warum denn

    const char foo[8] = "6660044\0";
    

    und nicht

    const char foo[] = "6660044\0";
    

    ?

    Spar dir das Zählen, dabei machst du nur Fehler. 😉

    EDIT: Äh, und warum packst du jetzt selbst die \0 in den String? Das geht bei Stringliteralen sowieso automatisch. Kann es sein, dass du jetzt 2 Nullen im String hast (wofür die 8 Zeichen wieder nicht ausreichen würden 😃 )?



  • Weil ich das Array einer Funktion übergebe, die dieses immer mit der gleichen Anzahl an Bytes befüllt.

    Dass die 0 Terminierung bei Stringliteralen automatisch hinzugefügt wird, ist eine Information, die mir noch fehlte. 😉


Anmelden zum Antworten