Skip to main content
GameDev.net gamedev.net
🔒 Locked

Strings on the stack

Started by samson77 Mar 10, 2009 at 3:43 PM 9 replies 1.3k views
Original Post
samson77
samson77
Hi there, I am currently programming a text adventure in C++. Needless to say there will be a lot of text. I have a function which fills a character array with one sentence depending on the Sentence ID I pass in:

void GetText(wchar_t* pTextArray, int TextID)
{
switch(TextID)
{
case TEXT_01:
wcscpy_s(pTextArray, 256, L"Hello, how are you?");
break;
case TEXT_02:
wcscpy_s(pTextArray, 256, L"Good, thanks, how are you?");
break;
default:
break;
}

}

The problem is that my text adventure will end up with a few MB of strings and all the strings are landing on the stack when I enter this function. The stack size if I remember correctly is at its maximum about 1MB; so I don't think the current approach works. How should I resolve this? Hash-defines won't really work for me since I plan to implement different languages and the TextIDs should be the same for every language for every particular sentence. Any ideas? Cheers.
Rewdew
Rewdew
Constant literals are not stored on the stack
Also you might want to use std::string instead (and possibly an external file to store all that text)...
As for hashmaps (or just maps) not working because of different languages, it doesn't really matter, you can just have one more "indirection" level, for example strings[language][id]...
Sneftel
Sneftel
Quote:
Original post by samson77
Hi there, I am currently programming a text adventure in C++
Doesn't look like it. If it were C++, you'd be able to use std::string and wouldn't have to deal with the pain which is null-terminated char arrays.
Quote:
I have a function which fills a character array with one sentence depending on the Sentence ID I pass in
Cool, so you just look up the integer in your string vector or hash-table, right? You don't actually plan to implement it as a gigantic switch statement?
Quote:
all the strings are landing on the stack when I enter this function.
That would be a very strange thing for a compiler to do. Have you checked that it is actually occurring?
samson77
samson77
Thanks for the fast reply!
Are you guys saying that for example the L"Hello, how are you" is not put on the stack? Is this a globally accessible string then and could I just pass a pointer back from my function like:
wchar_t* GetText(int TextID){switch(TextID){case TEXT_01:return L"Hello, how are you?";break;case TEXT_02:return L"Good, thanks, how are you?");break;default:return NULL;break;}}


I was planning to use just one gigantic switch statement and have all the text in one .cpp file. Since I am still learning I am open to any suggestions for a better approach?

I know I should use std::string, but I (for some reason) like the idea better to just pass a pointer around than having std::string copy the string a few times until it's passed into the function that processes it; I might be wrong there though.

Cheers.
Red Ant
Red Ant
String literals are usually placed in constant memory that is READ-ONLY to the program. They don't go on the stack.

Also, please please PLEASE do yourself a favor and do not worry about std::string being inefficient or anything. I guarantee you that std::string is reasonably fast and it's also __MUCH__ easier to use and far less error prone than messing with raw character arrays. When learning a new language, there are more than enough opportunities to shoot yourself in the foot; don't ask for trouble by choosing pointers and character arrays over string objects.
Evil Steve
Evil Steve
Quote:
Original post by samson77
Thanks for the fast reply!
Are you guys saying that for example the L"Hello, how are you" is not put on the stack? Is this a globally accessible string then and could I just pass a pointer back from my function like:
*** Source Snippet Removed ***
Yes, that'll work.

Quote:
Original post by samson77
I was planning to use just one gigantic switch statement and have all the text in one .cpp file. Since I am still learning I am open to any suggestions for a better approach?
If your text IDs are sequential, you could have a simple text file, with one string per line, and then read all of those lines at startup. That'd eliminate the need to recompile whenever the strings change.

Quote:
Original post by samson77
I know I should use std::string, but I (for some reason) like the idea better to just pass a pointer around than having std::string copy the string a few times until it's passed into the function that processes it; I might be wrong there though.
For now, it's not too bad, but as soon as you want to use non-constant strings ("E.g. Hello [name], how are you?") you're going to run into a lot of pain that std::string (or std::wstring for wide character strings) would avoid.
Red Ant
Red Ant
Oh, by the way, the return value of your function should be const, since you MUST not try to modify the memory occupied by a string literal.

const wchar_t* GetText(int TextID){    // ....    return L"bla bla bla";}

samson77
samson77
Cool, thanks!
I will change my code to use std::wstring.

Quote:

If your text IDs are sequential, you could have a simple text file, with one string per line, and then read all of those lines at startup. That'd eliminate the need to recompile whenever the strings change.

So I would have a global array of std::wstring and when my app start read all the sentences into each std::wstring of that global array, right?
Evil Steve
Evil Steve
Quote:
Original post by samson77
So I would have a global array of std::wstring and when my app start read all the sentences into each std::wstring of that global array, right?
That's the easiest way, yes. Personally, I'd make some sort of manager class (Which you could have a global instance of), with a const wchar_t* getString(int nTextID); function. That'd let you easily change your code to read from a file, hard code it, autogenerate it, etc.
Red Ant
Red Ant
You could use an array, where your TextIDs are the indices into the array. However, consider using an std::map< int, std::wstring >, as that's precisely the kind of thing a map is meant for. A map stores key-value pairs. Your keys are your text ids and the values are your string objects.


P.S. Well, as long as your strings are literals, you can safely use raw pointers instead of std::wstring objects but as someone else has said before, if you need to manipulate strings, std::wstring and std::wostringstream / std::wistringstream will come in extremely handy.
Codeka
Codeka
Quote:
Original post by samson77
I know I should use std::string, but I (for some reason) like the idea better to just pass a pointer around than having std::string copy the string a few times until it's passed into the function that processes it; I might be wrong there though.
People are going to be typing their answers in, right? Most people type, what? 2 or 3 characters per second? You'd be able to copy about a million std::string's in the time it takes a person to type just one character!

When worrying about performance, you need to take the context into consideration.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.