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.: deinstrcat(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 "" reichtJeder 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
222222222222Vieleicht 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]
-
- 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); }
-
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.