komische Zeichen im String bei Verwendung von memcpy, strcat, strncat, strcpy und strncpy



  • char und char-Arrays bzw char-Pointer sind in C komplett verschiedene Sachen.
    Z.B.: dein strcat(tmpString, '\0');
    strncat erwartet zwei Zeiger auf char. Dein zweites Argument ist aber ein char. Ein Zeichen.
    Und selbst wenn du da "\0" hinschreibst, ist auch das sinnfrei, da da schon ein "" reicht

    Jeder Speicher der mit malloc geholt wird, muss auch wieder mit free freigegeben werden. Nur hast du die Adressen von dem Speicher gar nicht mehr.
    Das gibt haufenweise Speicherlecks.

    Irgendwie kopierst du immer nur das erste Zeichen aus charSet.

    Warum machst du das rekursiv? Du hast damit so viel Probleme.
    Besorg dir einmal Speicher und befülle den.



  • mirrowwinger schrieb:

    for (i = MinLength; i <= MaxLength; i++)
        {
            // String enthält i Charakter + '\0'
            char* String = malloc(sizeof(char) * (i +1)); 
            strncat(String, CreateString(i, CharSet), i + 1);
            printf("%s\n", String);    
        }
    

    malloc besorgt Speicher, der dann irgendein Inhalt haben kann.
    strcat sucht das erste '\0'-Zeichen und kopiert ab der Stelle den Inhalt von dem zweiten Argument. (strncat halt nur eine bestimmte Anzahl).
    Je nach dem was in dem malloc-Speicher steht, kann da dein Programm schon abstürzen.

    strncpy kopiert (im Gegensatz zu strncat) das '\0'-Zeichen nicht mit, wenn die Längenbegrenzung erreicht ist.

    Du hast also Speicherlecks und nicht-terminierte Zeichenketten.



  • Schock schrieb:

    rüdiger schrieb:

    Und strncpy ist eine sinnlose Wurstfunktion, die man einfach nicht nehmen sollte.

    Diese Aussage hilft Menschen wie mir nur halb weiter - was mir hier im Forum schon öfters aufgfallen ist... Dass strncpy eine sinnlose Wurstfunktion ist, glaube ich einfach mal, viele von Euch haben deutlich mehr Erfahrung; aber wie sieht eine sinnvolle(re) Alternative aus?

    Stimmt. Ich sollte das ein bisschen besser ausführen. strncpy kopiert in den meisten Fällen zu viel oder zu wenig \0en. Wenn die Größe des Zielstrings nicht ausreicht, dann wird der Zielstring nicht(!) nulterminiert! Wenn die Größe mehr als ausreicht, wird der Rest des Zielstrings unnötigerweise mit \0 aufgefüllt. Was die Implementierung unnötig langsam macht.

    In C11 gibt es endlich strcpy_s. Das ist die sinnvollere Variante.



  • rüdiger schrieb:

    Wenn die Größe mehr als ausreicht, wird der Rest des Zielstrings unnötigerweise mit \0 aufgefüllt. Was die Implementierung unnötig langsam macht.

    Das ist wohl das schwächste Argument gegen strncpy.
    Wichtiger ist zu wissen, dass bei Speicherbereichsüberlappung das Verhalten undefiniert ist und dass die Verwendung von Funktionen, die zusätzliche Abhängigkeiten schaffen (hier die Eventualität ob im Ergebnis nun ein gültiger (nullterminierter) String vorliegt oder nicht) nur zu Problemen führt und den Code fehleranfällig machen.



  • Wutz schrieb:

    rüdiger schrieb:

    Wenn die Größe mehr als ausreicht, wird der Rest des Zielstrings unnötigerweise mit \0 aufgefüllt. Was die Implementierung unnötig langsam macht.

    Das ist wohl das schwächste Argument gegen strncpy.
    Wichtiger ist zu wissen, dass bei Speicherbereichsüberlappung das Verhalten undefiniert ist und dass die Verwendung von Funktionen, die zusätzliche Abhängigkeiten schaffen (hier die Eventualität ob im Ergebnis nun ein gültiger (nullterminierter) String vorliegt oder nicht) nur zu Problemen führt und den Code fehleranfällig machen.

    Was ich erwähnt habe 🙄



  • Danke für die Erläuterungen. 🤡



  • Hallo alle miteinander,

    also ich habe jetzt einmal das ganze "einfacher" versucht und es sieht sehr gut aus. Habe die Rekursion auf anraten vieler Kommentare jetzt fallen lassen und erstelle den String jetzt direkt über eine for Schleife. Das sieht folgender Maßen aus:

    for (i = Min; i <= Max; i++)
    {
        char* string = malloc(sizeof(char) * (i + 1));
        int j;
        // für meinen ersten Test habe ich einfach immer nur den 1. Buchstaben des
        // charSets reingeschrieben. Außerdem war das für die Fragestellung unerheblich
        for (j = 0; j < i; j++) string[j] = charSet[0];
        string[i] = '\0';
        printf("string:\t%s\n", string);
        free(string);
    }
    

    Dies ergibt auch für Min = 2 und Max = 12 den gewünschten Ausdruck:

    22
    222
    2222
    22222
    222222
    2222222
    22222222
    222222222
    2222222222
    22222222222
    222222222222

    Vieleicht könnt ihr ja nochmal drüber schauen, ob noch Fehler vorhanden sind. Ansonsten bedanke ich mich bei allen Mitwirkenden und Kommentatoren für ihre Teilnahme an meinem Problem.

    Vielen Dank
    mirrowwinger

    [Edit1] Fehler korrigiert (SeppJ)[/Edit1]


  • Mod

    • sizeof(char) ist per Definition immer 1.
    • Wenn du ganz paranoid bist, könntest du prüfen, ob das malloc überhaupt erfolgreich war.
    • string[i] ) '\0'; Bitte Code immer per Copy&Paste, nicht abtippen. Sonst finden wir nur Fehler, die gar nicht da sind und übersehen die echten Fehler.


  • Danke SeppJ,

    Fehler war wirklich nur Abtippfehler (sitze an 2 Rechnern Linux und Windows). Einer mit Internet und der andere mit Linux halt 😃



  • mirrowwinger schrieb:

    Einer mit Internet und der andere mit Linux halt 😃

    Komisch, hätte ich genau anders herum erwartet 😉
    Und die Linuxkiste hat kein Netzwerk?



  • for (i = Min; i <= Max; i++)
    {
        char* string = calloc( 1, i+1 ); /* calloc = malloc + 0-Initialisierung */
        int j;
        // für meinen ersten Test habe ich einfach immer nur den 1. Buchstaben des
        // charSets reingeschrieben. Außerdem war das für die Fragestellung unerheblich
        for (j = 0; j < i; j++) string[j] = charSet[0];
        /* string[i] = '\0'; kann jetzt entfallen, weil oben calloc schon alle Zeichen mit '\0' initialisiert hat */
        printf("string:\t%s\n", string);
        free(string);
    }
    

  • Mod

    Aber warum alles mit 0 initialisieren, wenn man hinterher alle bis auf eine wieder überschreibt? Gerade bei einem so kurzem Codestück kann man sich ja sicher sein, dass hier die Nullterminierung tatsächlich richtig gesetzt wird. Und falls doch ein Programmierfehler im Code ist, dann bekommt man sowohl bei malloc als auch bei calloc einen Fehler/undefiniertes Verhalten, bloß die Art des Fehlers ist anders.



  • Zwischen malloc-Definition und 0-Terminierung läuft irgendwelcher mehr oder weniger übersichtlicher Code ab, der abstürzen oder sonstwie indifferent reagieren kann, dabei ist der String noch kein "String" was z.B. für eine Fehlerbehandlung wichtig wäre. Auch ist es sehr viel übersichtlicher, wenn man die Zusicherung der Stringeigenschaft nicht auf spätere Codeteile verschiebt, ebenso kann man im "Setting"-Codeteil von der Stringeigenschaft profitieren und vorgefertigte Funktionen benutzen, z.B. strncat statt strncpy.


Anmelden zum Antworten