Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

04.04.2012, 22:19

integer in const char* umwandeln, Fehler bei printf

Hallo Spieleprogrammierer.de -Gemeinde!

bin noch so einer, der das Buch C++ für Spieleprogrammierer durchgearbeitet hat und jetzt an dem SDL Spiel weiter experimentiert.

Ich versuche derzeit die erreichten Punkte am oberen Bildschirmrand anzuzeigen. Hab mir ne eigene Klasse geschrieben, die Textfelder erzeugt und sie funktioniert auch einwandfrei. Jetzt habe ich das Problem, dass ich Zahlen als Text ausgeben will. Die Funktion TTF_RenderText_Solid der SDL_ttf.h verlangt einen const char*. Es gibt die Möglichkeit mittels printf(charText, intZahl) einen Integer in const char* umzuwandeln (hab ich zumindest in anderen Foren aufgeschnappt). Das Problem bei mir ist, dass jedes mal beim Aufruf dieser Funktion eine Zugriffsverletzung (und kein Fehler) gemeldet wird.

Ich deklariere im header bei den Membervariablen: const char *m_pText
Rufe dann die printf-Funktion zb in der Init oder Run Procedur auf und setze dann probeweise zB "10" als Integer ein: printf(m_pText, 10)
und übergebe anschließend m_pText weiter an die TTF_RenderText_Solid Funktion.

Nun bekomme ich, egal wo ich dies aufrufe, eine Zugriffsverletzung genau an der Stelle, an der die Funktion aufgerufen wird.

Was mache ich falsch? Habe ich vielleicht etwas übersehen?

(hab schon sämtliche Foren und Beiträge durchsucht, habe aber leider keine Lösung gefunden)

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

04.04.2012, 22:22

Vergiss char*. Schmeiß es weg. Benutz std::string statt char* und std::stringstream statt printf.
Da hast Du erstens den ganzen Ärger nicht und zweitens ist das das, was man in C++ nutzt. Char* ist C.

(was bei Dir aber vermutlich fehlt ist eine Speicher-Allokierung für Dein char*)
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

CodingCat

1x Contest-Sieger

Beiträge: 420

Beruf: Student (KIT)

  • Private Nachricht senden

3

05.04.2012, 08:12

Nun bekomme ich, egal wo ich dies aufrufe, eine Zugriffsverletzung genau an der Stelle, an der die Funktion aufgerufen wird.

Was mache ich falsch? Habe ich vielleicht etwas übersehen?

(hab schon sämtliche Foren und Beiträge durchsucht, habe aber leider keine Lösung gefunden)

Schritte in so einem Fall: Zunächst solltest du dich vergewissern, dass dein Quelltext auch das tut, was du möchtest. Ein Blick in die Dokumentation zu printf verrät:

Zitat

C-/C++-Quelltext

1
int printf ( const char * format, ... );

Print formatted data to stdout
Writes to the standard output (stdout) a sequence of data formatted as the format argument specifies.


Standard Output meint in aller Regel die Konsole, dein Quelltext schreibt also zunächst irgendwas in die Konsole, und dann irgendwas auf den Bildschirm. Der Text, auf den m_pText zeigt, wird jedoch auf gar keinen Fall durch den Aufruf von printf aktualisiert, wie du schon am Typ des printf-Parameters format ablesen kannst: Das const in const char * bedeutet, dass keines der Zeichen, auf die format zeigt, im Ablauf der aufgerufenen Funktion je verändert werden darf.

Was du suchst, ist offensichtlich sprintf.

Zitat

C-/C++-Quelltext

1
int sprintf ( char * str, const char * format, ... );

Write formatted data to string
Writes into the array pointed by str a C string consisting on a sequence of data formatted as the format argument specifies. After the format parameter, the function expects at least as many additional arguments as specified in format.
This function behaves exactly as printf does, but writing its results to a string instead of stdout. The size of the array passed as str should be enough to contain the entire formatted string.


Wie du siehst, nimmt sprintf einen Parameter mehr, was auch so sein muss, weil die gesamte printf- und scanf-Familie immer einen Formatierungsstring erwartet, der angibt, was im Anschluss überhaupt noch folgt. Zur Ausgabe eines Integers entnimmst du der Tabelle unter format, dass der entsprechende String "%d" sein muss, wenn im Anschluss ein Integer folgt. Damit wärst du also bei:

C-/C++-Quelltext

1
sprintf(m_pText, "%d", 10);


Dies löst jedoch noch nicht die Zugriffsverletzung. sprintf erwartet, dass du selbst Speicher für den Ergebnisstring bereitstellst. Das heißt konkret: Das Char-Array, auf das dein m_pText zeigt, muss schon vor Aufruf der Funktion sprintf groß genug für das Ergebnis sein. Ich vermute mal, dass dein m_pText bisher einfach auf gar nichts zeigt, wodurch natürlich schon ein Schreib- oder Lesezugriff mit m_pText[0] unweigerlich zum Absturz führen muss. Integers werden in Textform nicht allzu groß (vgl. Minimal- und Maximalwerte), du könntest deinen m_pText-Zeiger also direkt durch ein Char-Array char m_text[16] ersetzen. Es gibt in C/C++ eine implizite Konvertierung von T[] zu T*, das heißt Arrays lassen sich immer auch als Zeiger übergeben, und du kannst schreiben:

C-/C++-Quelltext

1
2
3
// mit char m_text[16]; anstatt m_pText
sprintf(m_text, "%d", 10); // schreibt "10" in den Speicherbereich m_text
TTF_RenderText_Solid(..., m_text, ...); // zeichnet den neuen Text


Die Tatsache, dass du die Länge des Ergebnis schon vorher wissen musst, ist auch der Grund für das, was BlueCobold nennt: Für komplexere Strings ist es manchmal schwierig bis unmöglich, die maximale Länge des Ergebnis einigermaßen genau vorauszusagen. Und selbst wenn es möglich wäre, bleibt es eine bedeutende Fehlerquelle, sollte sich der String mal ändern, aber der Programmierer vergessen, auch die Maximallänge anzupassen. Die von C++ bereitgestellten Klassen std::string und std::stringstream nutzen intern zwar auch nur sprintf, verwalten den notwendigen Speicher jedoch völlig autonom und wurden so oft getestet, dass du dir der Fehlerfreiheit einigermaßen sicher sein kannst. Damit sähe dein Anwendungsfall so aus:

C-/C++-Quelltext

1
2
3
// mit std::string m_text; anstatt m_pText
m_text = (std::stringstream() << 10).str(); // schreibt "10" in den stringstream und speichert das Ergebnis im String m_text
TTF_RenderText_Solid(..., m_text.c_str(), ...); // zeichnet den neuen Text


Nichtsdestotrotz ist es wichtig, dass du auch die erste Variante und die Zugriffsverletzung verstehst, weil du auch in C++ immer wieder auf das Konzept von Zeigern und Speicherbereichen stoßen wirst. Im Falle einer sehr häufigen Textänderung (z.B. einmal pro Frame) würde ich persönlich sogar bei sprintf mit festem Speicherbereich bleiben, um ständigen Speicherallokationen aus dem Weg zu gehen.
alphanew.net (last updated 2011-06-26) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »CodingCat« (05.04.2012, 08:27)


4

05.04.2012, 14:21

Hey, vielen Dank für die Antworten!

es funktioniert tatsächlich mit sprintf.

Vielen Dank für die ausführlichen Erklärungen, denn das ist genau das, was so ein Anfänger sucht und barucht!

Werbeanzeige