Problem returning a char pointer

I am working on a simple name generator program. One part of my program has me clicking a button that takes in someone's name, scrambles it and puts the output in another text box. That part works fine. The other button calls a function that is just meant to return a random name. Right now it isn't too fancy because right now it is just returning a jumble of characters that it isn't supposed to. Right now all I've programmed it to do is pick a random number from 5 to 10 to determine the length of the name, loop that many times and put random letters in there, then return the output. When I get that working right, I'll work on making it better. Here is my function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
char* RandomName()
{
	// Determine the number of characters in the randomly generated name
	// The range is 5 to 10 characters
	int numChar = (5 + rand() % ((10 + 1) - 5));

	// Variable to store the randomly generated name
	char pRandomName[256];

	for (int i = 0; i < numChar; i++)
	{
		pRandomName[i] = (97 + rand() % ((122 + 1) - 97));
	}

	// Capitalize the first letter
	pRandomName[0] = (pRandomName[0] - 32);

	// Now we need to indicate the end of the string
	pRandomName[numChar] = '\0';

	return pRandomName;
}


That function is called via this code:

SetWindowText(hOutput, RandomName());

When I step through the program, the array seems to be filled correctly but for some reason it is returning some crazy characters in the text box. Anyone have any ideas? Am I missing a key thing here?

Thanks in advance! :)
pointers are not strings.

You are returning a pointer to your 'pRandomName' array. However that array is local to the RandomName function, so as soon as the RandomName function exits (ie: on the return statement), the pRandomName array goes out of scope (dies), resulting in the function returning a pointer to memory that is no longer allocated, and therefore is garbage.

Typical solutions are either to use actual strings instead of char arrays. Or pass the char array to the function so it's owned at a higher level.

Example of std::strings:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
std::string RandomName()
{
	// Determine the number of characters in the randomly generated name
	// The range is 5 to 10 characters
	int numChar = (5 + rand() % ((10 + 1) - 5));

	// Variable to store the randomly generated name
	std::string pRandomName; // make it a string instead of a char array

	for (int i = 0; i < numChar; i++)
	{
		// append characters with +=
		//  also, for clarity, use literals instead of magic numbers so it's clear what you're
		//  doing
		pRandomName += ('a' + rand() % (('z' + 1) - 'a'));
	}

	// Capitalize the first letter -- again... use literals
	pRandomName[0] = (pRandomName[0] + 'A' - 'a');

	// pRandomName[numChar] = '\0';  no need for this with strings

	return pRandomName;
}

// ...

// need to use the c_str function to get a char* from a string
//  also note we have a char* not a TCHAR* so you should use SetWindowTextA
//  instead of SetWindowText (SetWindowText takes TCHARs, not chars)
SetWindowTextA( hOutput, RandomName().c_str() );
Last edited on
Thank you! Now I can start trying to refine the output to something more "name-like" rather than just random characters. I see what you are saying about how I was trying to use a local char array.

I had no idea you could use literals the way you did and never thought to append them with += like that. I've been teaching myself programming for a while now and every now and then I get tripped up like this.

I do have a question about your mentioning of char* versus a TCHAR*. What exactly is the difference? Why do you recommend using SetWindowTextA when SetWindowText still works?

Again, thank you! I've been working pretty hard trying to get my head wrapped around doing "string manipulation" like this and your post has really helped me to understand more of what is going on.
I had no idea you could use literals the way you did and never thought to append them with += like that.


You can only do it if you're using std::string. If you are using char arrays, you cannot append with +=. Just FYI.

I recommend using std::string because it's much easier, and much safer.

I do have a question about your mentioning of char* versus a TCHAR*. What exactly is the difference?


TCHARs are backwards compatibility weirdness.

In the very early days of Windows, there was no Unicode. Really old programs used "code pages" to print non-ascii or foreign alphabet glyphs to the screen.

Then later Windows built itself on top of UTF-16, meaning that all the strings it deals with internally are stored in UTF-16. The thing with UTF-16 is that it is typically 2 bytes per character, whereas chars are only 1 byte.

This presented a problem, because all of the WinAPI functions which take strings (like SetWindowText) currently took "narrow" (1 byte wide) strings, whereas they needed to change to take "wide" (2 byte wide) strings.

MS's solution to this was to create a 3rd transitory type called a TCHAR which could act as either a narrow or wide character depending on your build settings. It then redefined all its string functions to take TCHARs instead of chars so that they could optionally support wide strings if you tweak your compiler settings.

In the past, if programmers used this tool correctly, it allowed them to flip a switch to enable/disable Unicode support in their program. Disabling Unicode support might have had some performance benefit in a time where computers were not as fast as they are now. However in modern times, such a switch -- and therefore TCHARs -- are near useless and working with them is more of a hassle than they're worth.


Anyway... the just of it is there are 3 character types:

1) char, which uses 'narrow' / non-Unicode strings
2) wchar_t or WCHAR, which uses 'wide' / UTF-16 strings
3) TCHAR which is #defined as either char or wchar_t depending on your compiler settings.


And all WinAPI functions/structs which deal with strings have 3 forms to match:

1) SetWindowTextA takes char strings (LPCSTR)
2) SetWindowTextW takes wchar_t strings (LPCWSTR)
3) SetWindowText takes TCHAR strings (LPCTSTR)

In practice, the TCHAR function really just gets #defined as one of the other forms depending on the compiler settings. windows.h does something like this:
1
2
3
4
5
#ifdef UNICODE
  #define SetWindowText    SetWindowTextW
#else
  #define SetWindowText    SetWindowTextA
#endif 


If passing char strings to SetWindowText works, it's because your compiler settings happen to have unicode disabled. If that were to change (or if someone else were try to build your code with that setting set differently), you'd see a swarm of errors.


The right way to deal with this is to just match the string types correctly regardless of the compiler setting. That way it'll always work. So if you have char strings... use the char form of the function (the 'A' form).


LONG STORY SHORT

Different string types use different functions.

1
2
3
4
5
6
7
8
// only call SetWindowText with TCHAR strings
SetWindowText( wnd, _T("foobar") );

// only call SetWindowTextA with char strings
SetWindowTextA( wnd, "foobar" );

// only call SetWindowTextW with wchar_t strings
SetWindowTextW( wnd, L"foobar" );
Last edited on
Thanks for the info! I'll admit that a lot of that went over my head but you've given me a lot to think about and enough information to start looking into this myself. I enjoy stuff like this because if I understand what is going on "under the hood", I feel I am a better programmer as opposed to someone who uses it simply because it works.

Thanks again! Any recommended reading for some of the inner-workings of things like this?
Hljodulfr wrote:
Any recommended reading for some of the inner-workings of things like this?


I wish. I had to figure most of it out myself. =x
Ivor Horton's Visual C++ for beginners covers a wide area of C++ programming before moving into Windows MFC programming, but like Disch said, you will still have to figure out a lot of things on your own. There's only so much that you can fit in a book, and only so much that you'll remember after reading one.

Anyways, try the book, it was a pretty good one, but be sure to test things out and try out new ways of doing things while you learn.
I can definitely relate to the idea of having to learn for myself and to be honest, I expect a large portion of my energy will go into that. That is one of the reasons why there is a difference between studying something (IE reading a book) and actually having experience with something (figuring it out yourself). You guys have been terrific in giving me that little nudge toward my next phase of "figuring this out" :).
Topic archived. No new replies allowed.