C++ Char Array "sauber" reservieren

KingJoshii1000

Lieutenant
Registriert
Apr. 2010
Beiträge
879
Hallo,
ich bin aktuell dabei eine Übungsaufgabe bezüglich Vektoren und Arrays zu lösen,dabei soll ein C-Style String in einen zuvor reservierten Bereich auf dem Freispeicher kopiert werden und es sollen keine Funktionen der STL verwendet werden. Zugleich ist nur der Dereferenzierungsoperator (*) gestattet, nicht der Indexierungsoperator.
Mein Code:
Code:
char* strup(const char* v){
	int size = 0;
	for (int i = 0; i > -1; ++i){
		if (*v == NULL){
			size = i;
			break;
		}
		++v;
	}
	char* s = new char[size];
	v -= size;
	for (int i = 0; i < size; ++i){
		*s = *v;
		++s;
		++v;
	}
	s -= size;
	return s;
}
int main(int args_size, char** argc){
	char test[] = "TESTSTRING";
	char* temp = strup(test);
	cout << *temp << endl; //Gibt den ersten Buchstaben T aus
	keep_window_open();
}
Soweit funktioniert der Code auch wie gewünscht, jedoch ab der Stelle wo der Speicher für char s reserviert wird hat dieser den Wert "0x0058f320 "ÍÍÍÍÍÍÍÍÍÍýýýý««««««««îþ"". Der Code überschreibt die "Í", aber "ýýýý««««««««îþ" bleibt. Der Pointer Temp zeigt nun auf "0x007df320 "TESTSTRINGýýýý««««««««îþ"". Wie kann ich das vermeiden, bzw. wo genau liegt das Problem? Würde mich über Kritik (sowohl positive als auch negative) freuen, möchte mich schließlich verbessern:).


Mit freundlichen Grüßen :)
 
Zuletzt bearbeitet:
Hey,
super vielen Dank:) dachte, dass die Nullterminierung automatisch erzeugt wird, wie bei dem Char Array "test".

Mit freundlichen Grüßen
 
Noch was nebenbei. Obwohl NULL in C++ sowieso nix anderes als der Integerwert 0 ist, lautet die Konvention eigentlich, dass NULL nur als Null-Pointer-Konstante genutzt wird. Also z.B. int * ptr = NULL; Du prüfst in Zeile 4 ja nicht einen Pointer sondern ein char auf den Wert 0; von daher würde ich an dieser Stelle lieber explizit das Literal 0 verwenden.

Und nachdem in C++11 dafür explizit der neue Null-Pointer-Wert nullptr eingeführt wurde, gibt es für NULL eigentlich überhaupt keine Daseinsberechtigung mehr.

Das ist natürlich absolut nix kritisches, und man könnte es sogar als Geschmackssache bezeichnen, aber du hattest ja um Kritik gebeten. ;)
 
Du solltest das zurückgegebene Array auch noch am Ende der main-Funktion per delete[] löschen - aktuell wäre das Programm ein Paradebeispiel für Memory Leaks ;)

Ansonsten eine Kleinigkeit, die man nicht verbessern muss, aus der man aber einiges herausholen kann:

Code:
for (int i = 0; i > -1; ++i){
  if (*v == NULL){
    size = i;
    break;
  }
  ++v;
}

Die gesamte Schleife wird zwar natürlich so funktionieren, wie sie ist, aber sie ist unglaublich umständlich geschrieben. Liegt zwar unter anderem auch daran, dass du aus irgendwelchen Gründen keinen Index-Operator verwenden darfst, aber in die Abbruchbedingung der For-Schleife kann man ja alles Mögliche schreiben - auch den Vergleich mit *v:

Code:
size_t size = 0;
for (size_t i = 0; *v != '\0'; v++)
  size = ++i;

Normalerweise würde man eben jetzt i als Index für v benutzen. Aber das waren vielleicht jetzt viele Dinge auf einmal:
  • Ich habe mir mal erlaubt, den Typen von size und i auf size_t zu ändern. Das entspricht normalerweise einem unsigned long und ist dafür da, die Größe eines Typen oder eben eines Arrays zu halten - eignet sich aus demselben Grunde aber auch hervorragend als Array-Index. Der Parameter von new [] ist zum Beispiel auch vom Typen size_t.

    Warum nicht beim int bleiben? Nun, der Vergleich i > -1 in deinem Code zeigt es: i kann überlaufen - und du hast eine negative Größe, die dir deine Pointer-Arithmetik und letztenendes auch die Schleife um die Ohren haut.
  • *v != '\0': Das ist jetzt unsere neue Schleifenbedingung. Eigentlich genau das Gegenteil von der Bedingung deiner if-Abfrage. Das '\0' ist, wie von Antred im letzten Beitrag angesprochen, die korrekte Art und Weise, einen Char mit dem Wert 0 zu erzeugen.
  • v++ ist nun im Schleifenheader gelandet, weil es bei dir einfach die letzte Aktion in der Schleife war. Wenn man mehrere solcher Aktionen hat, kann man diese dort durch ein Komma trennen - also i++, v++ - was es nebenbei auch erlauben würde, ganze Schleifen ohne Body auszuführen, aber das ist in der Regel nicht sinnvoll und schon gar nicht lesbar.
  • size = ++i: Anstatt i direkt im Schleifenkopf zu erhöhen, machen wir es hier und weisen den Wert auch direkt an size zu.
    Warum? Nun - das ist der Nachteil an diesem Ansatz - wenn wir es im Header der Schleife machen, wird i erst nach der Zuweisung erhöht, size wäre damit also immer genau um 1 zu klein. i bei 1 starten zu lassen wäre eine Lösung, die hier funktionieren würde, aber bei der Variante mit Index-Operator wieder für Probleme sorgt.


Edit zum Beitrag unter mir: Dickes +1 für Valgrind, das spuckt einem Meldungen aus, wenn am Ende noch herrenloser Speicher irgendwo herumfliegt. Das gilt allerdings leider auch für Speicher, den irgendwelche (System-)Bibliotheken nicht freigegeben haben, wogegen man möglicherweise nichts tun kann.
 
Zuletzt bearbeitet:
Zurück
Oben