std::string, classes and... pointer?

Started by
14 comments, last by kVandaele 20 years, 2 months ago
I''m using a date class in my game called cTimeAndDate, which keeps track of the date in m_Year, m_Month, m_Day, m_Hour, m_Minute, m_Second. I''ve got an instance of cTimeAndDate in cTotal called m_Now. What i now want to do is have a member function of cTotal return a nicely formatted string to print the date on my screen.

cTotal::cTotal(){
	m_Now = cTimeAndDate(3174, 3, 24, 11, 56); 
	// year, month, day, hour, minute

}

std::string cTotal::GetNowString(std::string s){
	s = "Interstellar Time: ";
	s += m_Now.GetYear() + ".";
	if(m_Now.GetMonth() < 10)
		s += ''0'';
	s += m_Now.GetMonth() + ".";
	if(m_Now.GetDay() < 10)
		s += ''0'';
	s += m_Now.GetDay() + " ";
	if(m_Now.GetHour() < 10)
		s += ''0'';
	s += m_Now.GetHour() + ":";
	if(m_Now.GetMinute() < 10)
		s += ''0'';
	s += m_Now.GetMinute() + ":";
	if(m_Now.GetSecond() < 10)
		s += ''0'';
	s += m_Now.GetSecond();
	return s;
}
as you can see i pass along an std::string variable because before (when i was trying to do it with char strings - ouch) it gave me a warning that i was returning a pointer to a temporary variable. Here''s what i put in my winmain:
char Text[1024];
std::string tempText;
sprintf(Text, App->m_Total.GetNowString(tempText).c_str());
App->m_Font.Print(Text, 536, 7);
Also, there''s no problem with m_Font, or m_Font.Print(). Here''s the output i expected to be printed on screen: "Interstellar Time: 3174.03.24 11:56:00" Here''s what i got: "Interstellar Time: 0e: 0x900.8x0" "Interstellar Time: 0e: 0x0012e9xx0" Looking at the second one my thoughts were "looks like a pointer address" but then i''ve never know of two x''s in an address, or a period "."... Also, if they''re adresses why is one 7 chars and the other 9? thanks
Advertisement

Let''s get this straight. You''re passing your function an empty string.. which isn''t modified, because it isn''t passed by reference.. basically, the copy of it on the stack is just used as a temporary variable.

Your mistake, though, is passing the string to sprintf as the format string. Look up sprintf''s documentation, say, here.

Hope that helps.

.bas

[sPiKie] mmorpg isnt hard in vb
.basprintf ( "And for the %dth time, I'm not American!", ++lIdiots );My homepage
A guess the Get* methods return integers? So you know that you add an integer to a character pointer (beeing just pointer arithmetic). The string at the new address is then added to s.
He''s not using a character pointer, he''s using a std::string, which overloads the + and += operators appropriately.

The sprintf call looks right to me, but there has to be a better way to convert std::string to char *. Is there a reason you can''t make the mFont.Print() method use a string instead? (wtf are those values ''536'' and ''7'' anyway? constants please?)

Your function doesn''t modify the input string, as noted; s will get pointed at a new string internally. And then you don''t do anything with the return value. You''ll need to pass in by reference; and then the return value is only worth something if you want to chain calls somehow, which I doubt is the case here. Anyway, the output you''re seeing is probably garbage from the uninitialized string. There might be a lot of non-printing characters in there too :/

Oh, and FFS do the getNowString() calculations in the cTimeandDate class, and delegate there from cTotal. It''s cleaner OO and should actually be faster (because within cTimeandDate you have direct access to the m_Year etc.... even if you made them public, they''re more directly accessible in cTimeandDate).
To convert a string to a C-style string, simply use the "c_str()" member function of the string class.

I''m sorry zahlman, but you''re incorrect. The prototype of the sprintf is:

int sprintf ( char * buffer, const char * format [ , argument , ...] );

The second argument is the format string.

I don''t think the OP should be using the sprintf () at all, or use only sprintf. For an example use of sprintf:

sprintf (Text, "Interstellar time: %d %d %d", &day, &month, &year);

In this case, however, he should change the sprintf to:

sprintf (Text, "%s", App->m_Total.GetNowString(tempText).c_str());

.bas

[sPiKie] mmorpg isnt hard in vb
.basprintf ( "And for the %dth time, I'm not American!", ++lIdiots );My homepage
okay, sorry for the long time to reply, i pulled off an all-nighter and dozed off.

first reply:
Hmm... Right, guess i shouldn''t pass the variable. I don''t know where that came from, i guess i need more experience with pass by reference...

you may be right, bastardos. However, i simplified that for my posting (and my attempts at fixing it). Both of the following lines produce the same gibberish:

sprintf(Text, "Credits: %u\n%s", App->m_Player.GetCredits(), App->m_Total.GetNowString(tempText).c_str());
sprintf(Text, App->m_Total.GetNowString(tempText).c_str());

Perhaps my mistake (if it was wrong) was to assume that sprintf just copied the second arguement into the first arguement (after replacing all %x''s).

Also, thanks for the link but i have it already bookmarked... yay for google

VolkerG:
Actually, they return DWORDS to be precise, but yes. So... what you''re saying is that the integers aren''t converted by the std::string class? I''d find that rather strange considering std::cout does it... I''ll test that with a sprintf later, sounds like that might be it.

Zahlman:
the cFont class is basically a wrapper for the following DirectX call:
INT DrawText(
LPCSTR pString,
INT Count,
LPRECT pRect,
DWORD Format,
D3DCOLOR Color
);
As you can see, DrawText takes a Long Pointer to C STRing (... i think). So, even if i modified the cFont.Print class to take a std::string variable, at some point i''d have to convert anyway.
Also, sorry for that, 536 is the x value and 7 the y value of the position to draw (top right corner on 800x600).

>>And then you don''t do anything with the return value.

I get where passing the variable to it doesn''t do anything, but i do return s, and then doesn''t this line call the c_str() of the returned std::string?
App->m_Total.GetNowString(tempText).c_str()
= s.c_str() ?

>>Oh, and FFS do the getNowString() calculations in the cTimeandDate class, and delegate there from cTotal. It''s cleaner OO and should actually be faster (because within cTimeandDate you have direct access to the m_Year etc.... even if you made them public, they''re more directly accessible in cTimeandDate).

Thanks, will do.

Thanks, iamjoesname, but i already do...

bastardos:
true, the second variable of sprintf is usually (and meant to be) a format string, however in my console app i''ve done the following before:
sprintf(str1, "Hello!");
Since that doesn''t produce any errors, i''m assuming the following wouldn''t either:
str2 = "Hello!";
sprintf(str1, str2);
(... well, initialize str2 right and it''d work. Sorry, not much good with Cstrings.
Haven't posted in ages and I'm ill, so go easy on the typos. Anyway, one serious question: Why are you mixing C and C++ like this? C-style output functions are notoriously frought with problems. std::string and std::stringstream exist so that you use them in place of the outdated, and dangerous, C functions.

Shouldn't be a call to sprintf() anywhere.

Edit: Typed up example, which is actually useless, but hopefully it demonstrates the point. Fingers crossed it'll compile.

#include <iostream>#include <sstream>#include <string>using std::cout;using std::endl;int main(){	std::string format;	std::stringstream sstream;	sstream << "Window has been drawn " << 1 << " times.\n";	format = sstream.str();	cout << format << endl;	return 0;}


-hellz

[edited by - hellz on January 25, 2004 10:17:44 PM]
To the OP: there is not conversion from an inter to a std::string object. But <strstream> or <sstream> (which is the prefered one, can't remember) could be what you want (works like any other C++ stream class).
To Zahlman: The rhs of the s+= is a character pointer, no std::string appearing here.

[EDIT]strstreams are not my friends ;-), hope everything is correct now.[/Edit]


[edited by - VolkerG on January 26, 2004 4:30:47 AM]
>>Anyway, one serious question: Why are you mixing C and C++ like this?

... cuz i don''t know any better It''s not like i insist on using C (opposite in fact, else i''d be doing it all with char arrays and pointers).

sstream eh :D Let''s do some research!

GOT IT WORKING!!! Woohoo! stringstream''s pretty awesome. Good to know

Here''s what i did:
First, i added GetString to cTimeAndDate Zahlman said it''s faster (and cleaner). Besides, i agree, the function apparently just got ''lost'' when moving it from console to win32.

Next, i added stringstream to my code:
std::string cTimeAndDate::GetString(){	std::stringstream ss;	ss << "Interstellar Time: " << m_Year << ".";	if(m_Month < 10)		ss << ''0'';	ss << m_Month << ".";	if(m_Day < 10)		ss << ''0'';	ss << m_Day << " ";	if(m_Hour < 10)		ss << ''0'';	ss << m_Hour << ":";	if(m_Minute < 10)		ss << ''0'';	ss << m_Minute << ":";	if(m_Second < 10)		ss << ''0'';	ss << m_Second;	return ss.str();}

I compiled, but over and over it kept crashing. I figured maybe i was an idiot so i tried returning just ''ss << "Hello!";''. When even that crashed, i went looking back to winmain (... after trying ''ss >> "Hello!";'', and another stringstream reference).

apparently the problem laid here:
sprintf(Text, "Credits: %u\n%s", App->m_Player.GetCredits(), App->m_Total.GetNow().GetString());
I was returning a std::string, sprintf didn''t know what to do so it crashed (took me a while to find this).
The solution was simple: stringstream. I quickly replaced the sprintf with the following two lines:
std::stringstream ss;
ss << "Credits: " << App->m_Player.GetCredits() << "\n" << App->m_Total.GetNow().GetString();

Next i had a problem with my m_Font: it needed a char*. According to a stringstream reference (http://www.codeproject.com/vcpp/stl/stlintroduction.asp)
quote:stringstream
A string stream that supports insertions of elements, and elements are inserted via the overloaded operator <<. The method str() gives a reference back to the underlying string, and the c_str() can be used to get a constant pointer to the string buffer.

Naturally, i misread that as "stringstream has a c_str() function". When that didn''t work, it was easy: it did return a string which had a c_str(), giving me this code:
App->m_Font.Print(ss.str().c_str(), 536, 7);
Of course, char* != const char* ...

Next i just created a new m_Font Print member function which takes a std::string, and voila! (yay to DirectX for taking const char*''s).

Thanks for all your help guys!

This topic is closed to new replies.

Advertisement