cout verändert char-Array? Wie und warum?
-
Hi alle,
ich hab folgendes Problem:
Ich benutze diese Funktion um Text auf den Bildschirm zu bekommen:void drawstr(GLuint x, GLuint y, const char* format, ...) { va_list args; char buffer[255], *s; va_start(args, format); vsprintf(buffer, format, args); va_end(args); glRasterPos2i(x, y); for (s = buffer; *s; s++) glutBitmapCharacter(font_style, *s); }Gebe zu, die va und vs Befehle kenn´ und verstehe ich nicht, aber die sollten zu meinem eigentlichen Problem nichts beitragen. Denn, um jetzt auch Floatwerte auszugeben, habe ich angefangen mir eine Funktion zu basteln, die floats in char* umwandelt:
char* floatToCString(float fValue) { bool bNegative = fValue < 0; if(bNegative) fValue = -fValue; //Vorkommastellen: int temp = (int)fValue;//Nachkommastellen abschneiden int iDezimalLenght = 1;// Eine Stelle ist immer while(temp >= 10){//Länge über 1 ermitteln iDezimalLenght++; temp = temp / 10; } char acDezimalChars[255]; temp = (int)fValue; acDezimalChars[iDezimalLenght] = 0;//Zeichenkette beenden iDezimalLenght--; // Array mit den Ziffern von oben nach unten füllen for (iDezimalLenght; iDezimalLenght >= 0; iDezimalLenght--){ acDezimalChars[iDezimalLenght] = (temp%10)+48; temp = (int)(temp / 10); } // Wenn diese Zeile fehlt, kommt keine Ausgabe ??? std::cout << acDezimalChars << "\n"; return acDezimalChars; }Wenn ich jetzt drawstr aufrufe,
drawstr(150, 200, floatToCString(fTranslateX));bekomme ich nur eine Ausgabe, wenn die Zeile
std::cout << acDezimalChars << "\n";mit dabei ist. Wieso und wie verändert cout die Zeichenkette, bzw. was muss ich tun, um ohne cout meinen Bitmapfont ins Glutfenster zu bekommen? (Mal davon abgesehen, dass es bestimmt eine Standardbibliotheksfunktion gibt, die den Job viel besser erledigt)
Wenn jemand die Geduld aufbringt, wäre ich dankbar, wenn er mir auch erklären könnte, warum
char* floatToCString(float fValue) { return "test"; }zu einer Ausgabe führt, nicht aber
char* floatToCString(float fValue) { char test[5]; test[0] = 't'; test[1] = 'e'; test[2] = 's'; test[3] = 't'; test[4] = '\0'; return test; }Danke im Voraus.
-
hehe

typischer Anfängerfehler, aber naja, da muss man durch, sonst lernt mans nie.
Also, es liegt an folgendem:char* func(float x) { char bla[256]; // ... return bla; }Du gibst hier einen Zeiger auf Speicher zurück, der nach dem funktionsaufruf nicht mehr existiert. Wenn deine funktion verlassen wird, wird der Speicher, der für bla reserviert wurde, wieder freigegeben. So gehts also nicht.
Merke: niemals Zeiger auf eine lokale Variable zurückgeben
Um dein Problem zu lösen, gibt es jetzt verschiedene Ansätze:
Der einfachste ist sicherlich folgender:
drawstr(100, 100, "%f", 1.0f);Du kannst mehrere Parameter an deine drawstr-funktion übergeben, der erste string gibt dann an, welche Parameter folgen. Die Formatierung vom ersten Parameter folgt der von printf und konsorten. Deshalb gibt es auch ein vprintf in deinem Code. Beispielsweise findest du hier eine Übersicht:
http://cermics.enpc.fr/~ts/C/FUNCTIONS/format.htmlEine zweite, wesentlich modernere Lösung ist folgende, dabei wird boost::format verwendet:
#include <boost/format.hpp> void drawstr(int x, int y, const std::string& c) { const char* text = c.c_str(); // hier jetzt deine Ausgabefunktion, diese muss die variable text ausgeben. } // aufruf: drawstr(100, 100, str(boost::format("Hallo %s, ich bin %d Jahre alt") % "Maxi" % 123));Die Format-Spezifierer sind dabei auch wie bei printf. Dazu musst du aber boost installieren (ist aber sowieso sehr empfehlenswert).
Weiterhin kann ich dir noch den FAQ-Artikel "Einmal string nach zahl und zurück" empfehlen.
Ich hoffe, ich konnte dir helfen

Maxi
-
Warum sich mit den C-Mitteln herumschlagen?
Für die Verwaltung von Zeichenketten gibt es die Klasse
std::string. Die kann man auch gefahrlos als Rückgabetyp von Funktionen verwenden. Zudem muss man sich nicht immer um Nullterminierung, Pufferüberläufe und manuelles Kopieren kümmern.
-
Du musst darauf achten, dass Elemente, die innerhalb einer Funktion erstellt werden und nach Ende der Funktion noch gebraucht werden, dann auch noch vorhanden sind.
acDezimalChars z.B. wird bei dir innerhalb der Funktion floatToCString definiert. Sobald floatToCString beendet ist, ist aber auch dieses Array verschwunden. Der Zeiger den du zurückgibst zeigt also auf einen Speicherbereich, der, je nachdem, wie der Rest des Programms aussieht auf irgendetwas undefiniertes zeigt.
Wurde der Speicherbereich von acDezimalChars noch nicht wieder überschrieben, dann merkst du nichts von diesem Fehler.
Du musst aber dafür sorgen, dass dein acDezimalChars auch nach Ende der Funktion noch gültig ist.
Da gibt es einige Möglichkeiten. Wenn man wie du C-ähnlich programmiert, dann könntest du z.B. ein Array verwenden, welches vorher bereits definiert wurde und nur per Zeiger an floatToCString übergeben wird. Nur ein Vorschlag.

-
Wurde bereits ausführlicher beantwortet. Ich ziehe meinen obigen Beitrag zurück.:D
-
Du konntest mir super helfen. Danke für die ausführliche Antwort.
-
Ihr konntet mir super helfen. Danke für die ausführlichen Antworten.