sprintf in char* Funktion = datenmüll?



  • Hallo ich habe ein kleines Problem ich möchte in einer funktion einen float formatieren und diesen dann zurück geben.
    Mein Funktion:

    char *Test(float fZahl)
    {
    	char cBuffer[50];
    	sprintf(cBuffer, "  %.9f", fZahl);
    
    	return cBuffer;
    }
    

    und der Testaufruf:

    printf("Zahl: %s", Test(147.54877));
    

    Als Ausgabe erhalte ich aber totalen Datenmüll.



  • weil cBuffer eine in Test lokale Variable ist und wenn 'Test' verlassen wird, verliert cBuffer den Gültigkeitsbereich.

    1. Lösung (die unschöne)

    char *Test(float fZahl)
    {
        static char cBuffer[50];
        sprintf(cBuffer, "  %.9f", fZahl);
    
        return cBuffer;
    }
    

    2. Lösung (die bessere)

    char *Test(float fZahl, char *buffer)
    {
        sprintf(buffer, "  %.9f", fZahl);
    
        return buffer;
    }
    
    void foo()
    {
        char buff[50];
        printf("Zahl: %s", Test(147.54877));
    }
    

    edit: korrigiert



  • Aber müsste der Inhalt von cBuffer nicht zurück gegeben werden?



  • da hat er sich bestimmt nur vertan.

    #define FORMAT_1 "  %.9f"
    #define FORMAT_2 "%G"
    #define FORMAT_3 "%E"
    
    void Format( char* buf, const char* format, float number )
    {
    	sprintf( buf, format, number );
    }
    
    int main()
    {  
    	char buf[64];
    	float number = 1.234f;
    	Format( buf, FORMAT_1, number );
    	puts(buf);
    	Format( buf, FORMAT_2, number );
    	puts(buf);
    	Format( buf, FORMAT_3, number );
    	puts(buf);
    }
    


  • lord_fritte schrieb:

    Aber müsste der Inhalt von cBuffer nicht zurück gegeben werden?

    ja, hab mich wegen copy&paste vertan. Hab's aber korrigiert.



  • supertux schrieb:

    2. Lösung (die bessere)

    char *Test(float fZahl, char *buffer)
    {
        sprintf(buffer, "  %.9f", fZahl);
    
        return buffer;
    }
    
    void foo()
    {
        char buff[50];
        printf("Zahl: %s", Test(147.54877));
    }
    

    dritte lösung (ohne triviale zusatzfunktion)

    #define Test(fzahl,buffer) (sprintf(buffer,"  %.9f", fzahl),buffer)
    
    void main()
    {
        char buff[50];
        printf("Zahl: %s", Test(147.54877, buff));
    }
    

    🙂



  • Sorry, aber wenn mir jemand in einem Projekt, an dem ich mitarbeite, so einen Code vor die Füße setzt, dem würde ich nen Arschtritt geben. Total sinnloses define :x



  • für mein Verständnis geht das sehr wohl, zum Zeitpunkt der Rücksprungs ist cBuff doch noch in Ordnung. Und außerdem tuts, zumindest bei mir

    char * test (int n)
    {
      char buf[1000];
      sprintf(buf,"%d",n);
      return buf;
    }
    
    int main(int argc, char * argv[])
    {
       printf("Zahle %d, Str: %s\n", 4711, test(4711));
       return 1;
    }
    

    Funktioniert bei mir prima.
    Also, wenn ich da was falsch verstehe, warum meckert der Compiler nicht und warum tuts?! 😕



  • call-by-value-fan schrieb:

    für mein Verständnis geht das sehr wohl, zum Zeitpunkt der Rücksprungs ist cBuff doch noch in Ordnung. Und außerdem tuts, zumindest bei mir

    char * test (int n)
    {
      char buf[1000];
      sprintf(buf,"%d",n);
      return buf;
    }
    
    int main(int argc, char * argv[])
    {
       printf("Zahle %d, Str: %s\n", 4711, test(4711));
       return 1;
    }
    

    Funktioniert bei mir prima.
    Also, wenn ich da was falsch verstehe, warum meckert der Compiler nicht und warum tuts?! 😕

    Oh man.
    Dein char buf[1000] wird beim Aufruf der Funktion auf den Stack genagelt. Und was passiert, wenn die Funktion wieder verlassen wird?
    Richtig: Die Funktion wird mit allem drum und dran wieder vom Stack gekickt. Der Pointer der zurückgegeben wird mag vielleicht auf irgendwas zeigen, was noch unverändert an der jetzt invaliden Adresse das ehemaligen Funktionsstacks im Speicher liegt, aber das ist reines Glück (oder eher Pech, weil man den Fehler nicht gleich bemerkt).
    Der Compiler meckert nicht, weil es ihm scheiss egal ist, wo ein Pointer hin zeigt. Der kann auch auf NULL zeigen. Das juckt den Compiler nicht die Bohne. Aber zur Laufzeit wirds dann etwas hakelig.



  • feigling schrieb:

    Sorry, aber wenn mir jemand in einem Projekt, an dem ich mitarbeite, so einen Code vor die Füße setzt, dem würde ich nen Arschtritt geben.

    autch! mein popo! du hund!
    ok, ok, #defines schreibt man gross und ein paar klammern fehlen auch noch.
    🙂



  • ok ok ... verstanden ... funktionslokale Variablen nicht über die Funktion heraus zurückgeben ... ok ok ... wäre aber folgendes okay:

    char * test (float fl)
    {
      char * buf = malloc (1000);
      sprintf(buf, "%f", fl);
      return buf;
    }
    


  • call-by-value-fan schrieb:

    ok ok ... verstanden ... funktionslokale Variablen nicht über die Funktion heraus zurückgeben ... ok ok ... wäre aber folgendes okay:

    char * test (float fl)
    {
      char * buf = malloc (1000);
      sprintf(buf, "%f", fl);
      return buf;
    }
    

    Ja, das ist OK. Du gibts einen Wert zurück, keine Adresse einer lokalen variablen



  • call-by-value-fan schrieb:

    ok ok ... verstanden ... funktionslokale Variablen nicht über die Funktion heraus zurückgeben ... ok ok ... wäre aber folgendes okay:

    char * test (float fl)
    {
      char * buf = malloc (1000);
      sprintf(buf, "%f", fl);
      return buf;
    }
    

    Kann man so zwar machen, da das Objekt auf den Heap landet, und nicht auf dem Stack, aber da muss man sich dann im klaren sein, dass die Funktion Speicher allokiert den man wieder frei geben muss. Wenn man das vergisst, hat man schnell mal so ein tolles Speicherleck.
    Was spricht denn dagegen, den zu befüllenden Buffer von aussen in die Funktion zu geben? Das ist tatsächlich die beste Methode und damit den ganzen andren Sachen (außer vielleicht direkt codieren) vorzuziehen.



  • Tachyon schrieb:

    ...und damit den ganzen andren Sachen (außer vielleicht direkt codieren) vorzuziehen.

    deswegen ja das makro auf der vorherigen seite, wofür ich den pöter voll bekommen habe. eine funktion um sprintf zu stricken, die nichts weiter macht, als das, was sprintf sowieso schon kann, finde ich nämlich ziemlich albern.
    🙂



  • trivialfunction-freak schrieb:

    Tachyon schrieb:

    ...und damit den ganzen andren Sachen (außer vielleicht direkt codieren) vorzuziehen.

    deswegen ja das makro auf der vorherigen seite, wofür ich den pöter voll bekommen habe. eine funktion um sprintf zu stricken, die nichts weiter macht, als das, was sprintf sowieso schon kann, finde ich nämlich ziemlich albern.
    🙂

    Makros sind für sowas erst recht scheisse.
    Den Krams sollte mal grundsätzlich vermeiden, weil das NICHT vom Compiler behandelt wird, sondern vom Präprozessor und man damit die ohnehin schon dürftigen Compilezeitchecks in C noch mehr aushebeln. Von den "Mysterien" die bei Operationen mit Nebeneffekten im Zusammenhang mit Makros entstehen mal ganz abgesehen. Dann doch lieber eine Funktion.



  • Tachyon schrieb:

    Den Krams sollte mal grundsätzlich vermeiden, weil das NICHT vom Compiler behandelt wird, sondern vom Präprozessor und man damit die ohnehin schon dürftigen Compilezeitchecks in C noch mehr aushebeln.

    das ist kein ausreichender grund, denn das, was der preprocessor erzeugt, geht anschliessend ja doch durch den compiler.

    Tachyon schrieb:

    Von den "Myterien" die bei Operationen mit Nebeneffekten im Zusammenhang mit Makros entstehen mal ganz abgesehen.

    wenn man sich damit auskennt, sind die risiken beim einsatz von makros leicht überschaubar. deine argumentation erinnert mich doch sehr an die leute, die immer sagen: 'gotos und rekursionen sind grundsätzlich schlecht'.
    🙂



  • ok, tun wir so, als hätte ich das verstanden, wäre dann die richtige Lösung, etwas derartiges:

    int test (float f, char * p)
    {
       sprintf(p, "%f", f);
       return 1;
    }
    int main (void)
    {
       char sz[100];
       float fl = 4711.00;
    
       test(fl, sz);
       printf("float: %f, str: %s\n", f, sz);
       return 1;
    }
    


  • ehemaliger-call-by-value- schrieb:

    int test (float f, char * p)
    {
       sprintf(p, "%f", f);
       return 1;
    }
    

    Wozu der Rückgabewert ?



  • man könnte wohl damit das sprintf in eine if-bedingung packen(sprintf(...),1 <- wäre ja viel schwerer).



  • wurst schrieb:

    man könnte wohl damit das sprintf in eine if-bedingung packen(sprintf(...),1 <- wäre ja viel schwerer).

    Könnte man, und dann ??

    if ( sprintf(p, "%f", f) == ... )
    // dann.. ????
    

Anmelden zum Antworten