Mit "Sscanf" String auf Int durchsuchen



  • Hallo Leute,

    frohes neues noch allerseits!

    Eine Frage, ich baste ein bisschen mit sscanf rum( auch um evtl. fflsuh(stdin) zu vermeiden).

    Meine Frage nun, ich hab mir die Referenz zu sscanf , bzw. scanf schon angesehen , komm aber nicht wirklich weiter, ->kann ich mit sscanf einen mit fgets eingelesenen String auf ne Zahl "durchscuchen" ?

    Hatte mir das etwa so gedacht:

    char buffer[max];
    int i;
    
    fgets(buffer, 50, stdin);
    // Es wird z.B.: "Das ist ein 123 Test"  eingegeben
    
    sscanf(buffer, "%d", &i);
    printf("Die Zahl war : %d", i),
    

    Ok, geht so nicht, in I steht Müll drinn.
    Kann man das Fromat -> "%d" spezifizieren bzw ala "Lies alles ein und verwirf alles ausser einen INT - Wert" definieren? oder ist dies generell nicht möglich?



  • Schau dir mal den Specifier %[ an.
    mit (ungetestet)

    sscanf(buffer, "%*[^-+0123456789]%d%", &i);// lese alles bis auf Ziffern und Vorzeichen, nicht speichern  (wegen *)
    

    könnte es gehen.

    Warum brauchst du fflsuh(stdin) ?



  • DirkB schrieb:

    sscanf(buffer, "%*[^-+0123456789]%d%", &i);// lese alles bis auf Ziffern und Vorzeichen, nicht speichern  (wegen *)
    

    Diese Suche würde allerdings '+' und '-' ohne folgende Zahl akzeptieren. Das Problem is ja einfach, dass die Zeichen vor der Zahl bzw. dem Vorzeichen übersprungen werden müssen, wenn denn überhaupt eine Zahl vorhanden ist. Die Rückgabe 0 von sscanf schließt leider mit ein, dass auch eine 0 im String gefunden wurde.

    #include <ctype.h>  // isdigit
    #include <stdio.h>  // printf, sscanf
    
    // Find first integer in string
    const char* find_int(const char* s){
        for(; *s; ++s)
            if(isdigit(*s) || *s == '-' && isdigit(*(s+1)))
                return s;
        return 0;
    }
    
    main(){
        const char* num = find_int("Das ist ein -123 Test");
        if(num){
            int i;
            sscanf(num, "%d", &i);
            printf("%d", i);
        }
    }
    


  • @DirkB:

    sscanf(buffer, "%*[^-+0123456789]d%", &i)
    

    ...funktioniert wunderbar für meine Zwecke! Besten Dank

    ->nutze fflush(stdin) nur noch "selten", meist wenn es schnell gehen soll weil was probiert wird.



  • fflush(stdin) wird ja meist gemacht um Falscheingaben abzufangen, oder weil der Programmierer nicht weiß, wie man scanf nutzt.

    scanf ist allerdings auch eine Monsterfunktion, die auch Zeit zur Auswertung benötigt.
    In dem Beispiel von Youka hätte ich darum strtol statt sscanf genommen. 😉



  • Gehört jetzt nicht zum Thema, wollte nur keinen neuen Thread anfangen, weil nicht soo wichtig:

    Gibt es eine möglichkeit Zahlen binär darstellen zu lassen?

    Quasi Input: 25 Dezimal
    Output(32Bit Breite) : 11001 Binär

    ??
    Also "fertige" Funktion wäre toll. Wenn nicht..... ich hab grad nicht wirklich eine Idee wie ich das am einfachsten Umsetzen könnte....



  • beginner_offl schrieb:

    Gibt es eine möglichkeit Zahlen binär darstellen zu lassen?

    Klar 🙂

    beginner_offl schrieb:

    Also "fertige" Funktion wäre toll.

    In der Standardbibliothek gibt es keine Funktion.
    Du kannst ja mal nach der Funktion itoa suchen. Bei deinem Compiler oder den Quellcode der Funktion.
    Es gibt allerdings auch eine Version mit fester Basis 10.

    beginner_offl schrieb:

    Wenn nicht..... ich hab grad nicht wirklich eine Idee wie ich das am einfachsten Umsetzen könnte....

    Kennst du dich mit den binären Operatoren (& | >> <<) aus?
    Es geht auch mit % und /

    Wo soll die Darstellung hin? In einen String oder Bildschirm/Datei?



  • Kennst du dich mit den binären Operatoren (& | >> <<) aus?

    Jein... Also ich bekomms meistens schon hin ... mit etwas einlesen und so, aber ich werd nicht wirklich warm mit UND Wort Verknüpfungen.

    Es geht auch mit % und /

    ... Das wäre mein Favorit gewesen. So wie man es hald "händisch" ausrechnet.
    Durch 2 teilen, Rest, usw usw.

    Wo soll die Darstellung hin? In einen String oder Bildschirm/Datei?

    Wie kann ich die Darstellung überhaupt realisieren? Also Bildschirm evtl. mit printf("%x", ...)
    Als String wäre natürlich auch nicht schlecht.

    Also ich bin ein bisschen "geschockt", das es in C keine Stan-Funktion gibt für sowas... Bin da evtl. berufl. etwas verwöhnt, aber da kann ich in jeder Sprache egal welchen Speicherbereich, bzw. Wert mit einen Klick in Binär darstellen lassen. (Steuerworte, Zustandsworte->einzlne Bits auswerten....).



  • Richtige Programmierer, für die ist C gemacht, können die Bits auch in Oktal- und Hex-Darstellung sehen. 😃

    Bei der Ausgabe auf den Bildschirm/Datei wäre putchar('0'); bzw putchar('1'); angebracht.
    Mit printf ist da nix.

    Es sei denn du baust dein eigenes itoa. Da wird das ergebniss als String abgelegt.
    Da kannst du dann printf("%s", itoa(x,str,2)); machen. (oder ein itoa2, das nur in Dualzahlen wandelt)

    Eine Möglichkeit:
    Du hast eine Bitmaske, in der nur ein Bit gesetzt ist. Am Besten das MSB, da dies ja zuerst ausgegeben werden soll.

    Diese Maske verundest du mit deinem Wert. An der Stelle, wo beide Zahlen das geliche Bit gesetzt haben, bleibt diese Bit auch gesetzt.

    10100101 Wert
    10000000 Maske
    -------- &
    10000000 Ergebnis ist ungleich 0 -> Bit ist 1. '1' ausgeben oder im String speichern

    Dann wird die Maske um eine Stelle nach rechts verschoben und der Vorgang wiederholt
    10100101 Wert
    01000000 Maske
    -------- &
    00000000 Ergebnis ist 0 -> Bit ist 0. '0' ausgeben oder im String speichern

    Wieder eine Stelle verschiebn, verunden, ... usw, bis die Maske 0 ist.

    Das ganze bitte mit unsigned Werten, denn nur da ist garantiert, das beim rechtsschieben auch eine 0 vorne eingschoben wird.



  • 10100101 Wert
    10000000 Maske
    -------- &
    10000000 Ergebnis ist ungleich 0 -> Bit ist 1. '1' ausgeben oder im String speichern

    Dann wird die Maske um eine Stelle nach rechts verschoben und der Vorgang wiederholt
    10100101 Wert
    01000000 Maske
    -------- &
    00000000 Ergebnis ist 0 -> Bit ist 0. '0' ausgeben oder im String speichern

    Das werd ich mal ausprobieren.
    Dann sehen wir weiter. Evtl. lass ich dann die %=2 bzw. /=2 Sache bleiben...... 🙄 ➡ 🕶



  • Nachtrag... Mir ist noch was eingefallen. Für meinen Ursprünlichen Gedanken, also mit % und / ... da wollte ich auch gleich mit putchar ausgeben...
    Geht ja nicht, müsste das "Ergbnis" ja erst drehen...
    Gibt´s nen ROL befehl?

    5%2 != 0 ? putchar("1") : putchar("0")
    ....
    Weißt du wie ich meine?



  • Habs jetzt mal "my-Way" gemacht...also die "Teilen" Variante.

    Ist noch nicht ganz fertig, funktioniert aber erstmal.

    #include <stdio.h>
    #include <stdlib.h>
    #define _MEM  (sizeof(int)*8)
    #define LSB (sizeof(int)*8-1)
    #define HIGH '1'
    #define LOW '0'
    
    void tobin(void){
    
    char bin[_MEM], *show;
    int init, i,j, erg;
    
    bin[_MEM]='\0';
    for(init=0; init<_MEM; init++)
                bin[init]='0';
    
    i=2569;
    j=0;
    do{
       if ((i%2)!=0){
                    puts("Rest");
                    printf("i : %d\n", i);
                    bin[LSB-j]=HIGH;
                    j++;
                    i/=2;
                    printf("i : %d\n", i);
    
           }
           else{
                puts("kein Rest");
                bin[LSB-j]=LOW;
                    j++;
                    i/=2;
                }
        system("pause");
    
    }while (i!=0); 
    j--; 
    show=&bin[LSB-j];   
    
    puts(show);     
    }
    

    Die Puts("rest")... und system("Pause") sind / waren nur zum Beobachten.
    Jetzt muss ich dann noch das Ergebnis zurückgeben und uint verwenden.
    Kann man den Rest so lassen?

    Die Variante mit >> << & | ist glaub ich eleganter, mit der setzte ich mich noch auseinander :p



  • Wie war das bei Arrays?

    // Wenn du ein Array hast
    char bin[_MEM]; // dann hat das _MEM Elemente.
                    // bezeichnet von 0 bis _MEM-1
    bin[_MEM]='\0'; // Das Element mit dem Index _MEM gibt es nicht !!!
    

    Alles was im if- und else-Zweig gleich ist, kannst du raus ziehen

    do {
        if ((i%2)!=0) {  // kann nur 1 sein
            bin[LSB-j]=HIGH;
        } else {
            bin[LSB-j]=LOW;
        }    
        j++;
        i/=2;
    
    } while (i!=0);
    

    Was bleibt ist dann

    do {
        bin[LSB-j]=(i%2)+'0';
        j++;  // Das könnte sogar noch bei bin[LSB-j++] stehen
        i/=2;
    } while (i!=0);
    


  • Und wenn du die 2 durch eine Variable ersetzt, kannst du so schon mal Zahlen bis zur Basis 10 anzeigen.

    Für andere Basen (bis 36) geht das so:

    static const char ziffern = "01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
    do {
        bin[LSB-j]=ziffern[i%basis]
        j++;  
        i/=basis;
    } while (i!=0);
    


  • Wie war das bei Arrays?

    ...Shit, ich sollte nichts tippen oder veröffentlichen, wenn ich schon ein paar Bier getrunken habe.
    Mann ist das peinlich. Das sollte eigentlich nicht passieren 😡 😡 😡

    DIe verkürzungen, bzw. was raus kann /muss hab ich jetzt noch gemacht.
    Auch die String Rückgabe. (Dazu noch die Frage : Ist gängig so oder? Also nen String zurück geben, wird schon meist so gemacht oder? Der Aufrufer kümmert sich um den Speicher, nicht die Funition?)

    Hier der Code:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define _MEM  ((sizeof(int)*8)+1)      
    #define LSB ((sizeof(int)*8)-1)            
    #define HIGH '1'
    #define LOW '0'
    
    char* tobin(char *str, unsigned int value){
    
    char bin[_MEM], *show;
    int init, j=0, erg;
    
    bin[_MEM-1]='\0';   
    for(init=0; init<_MEM-1; init++)     // ich hab inits gern :-)
                bin[init]='0';
    
    do{
       if ((value%2)!=0){
                    bin[LSB-j]=HIGH;                
           }
           else{
                    bin[LSB-j]=LOW;
                }
        j++;
        value/=2;
    
    }while (value!=0); 
    
    show=&bin[LSB-(--j)];   
    
    strcpy(str, show);
    
    return (str);
    }
    

    Ich habe jetzt bewusst nicht weiter verkürzt, mir ist :

    do {
        bin[LSB-j]=(i%2)+'0';
        j++;  // Das könnte sogar noch bei bin[LSB-j++] stehen
        i/=2;
    } while (i!=0);
    

    klar, aber ich kann den obrigen Code in 2 Jahren auch noch ohne "nachdenken" lesen. Generell... mich persönlich stören ein paar Zeilen mehr nicht sooo, wenn ich mich später mal leichter mit lesen tu.



  • beginner88888 schrieb:

    Auch die String Rückgabe. (Dazu noch die Frage : Ist gängig so oder? Also nen String zurück geben, wird schon meist so gemacht oder? Der Aufrufer kümmert sich um den Speicher, nicht die Funition?)

    Ja.

    Einfacher wäre

    #define _MEM  ((sizeof(int)*8)    
    
    char bin[_MEM+1]; // und nur bei der Definition Einen mehr.
    

    Du kannst auch gleich auf str arbeiten, dann brauchst du bin nicht. (evtl musst du den String zum Schluss umdrehen)

    return ist keine Funktion, daher braucst du die Klammern nicht.

    beginner88888 schrieb:

    aber ich kann den obrigen Code in 2 Jahren auch noch ohne "nachdenken" lesen.

    Da ist show=&bin[LSB-(--j)]; aber schwieriger zu verstehen als bin[LSB-j]=(i%2)+'0';
    Wobei das größte Problem dabei das LSB-j ist.



  • evtl musst du den String zum Schluss umdrehen

    hmm... gibt´s da was fertiges oder muss ich das selbst basteln?



  • beginner_oofl schrieb:

    hmm... gibt´s da was fertiges oder muss ich das selbst basteln?

    Schau mal in der string.h

    Ich würde die Funktion strrev nennen.

    Wenn du nichts findest, musst du es selber machen. Ist aber nicht schwer, da du das Ende vom String schon hast.
    Da hast du ja eine '0' oder '1' abgelegt.



  • Werde morgen die "Shift" Variante probieren.

    Frage vorab, passt die "Maske" so?

    #include <stdio.h>
    #include <stdlib.h>
    #define _MEM sizeof(int)*8
    
    void shift(void){
    
    int mask;
    unsigned int value;
    
    mask= 0x1;
    mask<<=_MEM-1;
    

    Wenn ich das MSB "setzen" will , wäre das ja 0x80000000
    Also müsste das mit sizeof(int) ja passen?

    OFF Topic: eine potenzier funktion für INT hab ich auch nicht wirklich gefunden. Hab schon mal eine selber gemacht, aber etwas wie value= 2^5 geht nicht oder?



  • mask sollte auch unsigned sein.
    Deine Variante geht. Oder als Einzeiler mask = 1 << _MEM-1;

    beginner88888 schrieb:

    aber etwas wie value= 2^5 geht nicht oder?

    Doch, klar.
    Aber dafür braucht es keine Funktion. Du machst das da oben doch schon.
    Überleg mal, was ein links-Shift bedeutet. (Fang mit der 1 an und schiebe um eine Stelle)


Anmelden zum Antworten