Reputation: 5619
Sorry if something similar has been posted here already, but I couldn't really find it.
I have the following code and, even though I would say this is not correct, I receive the right answer.
char *selectStr(int index){
char *str[] = {
"hello",
"hola",
"epa",
"alright",
};
return str[index];
}
int main() {
printf("String: %s\n", selectStr(2));
return 0;
}
Can anybody tell me why this actually works? The way I see it: an array of strings str
is a local variable inside the selectStr function. This function returns a string contained inside this array. But since this array of strings str
is a local variable, it should be cleaned from memory after it returns (right?), so I was expecting to get some sort of a memory access error.
Should I consider myself lucky that this code works (i.e. is this an undefined behavior?) or this is actually a good way of doing things (in this case, why)?
My guess is that the pointer to the array str
gets cleaned after the function returns, but not the actual content that it points to, which stays in memory until something else writes on it. I would really appreciate if somebody could confirm that, or else, tell me what is actually going on.
Thanks in advance!
PS: The way I would do it is to pass a buffer as a parameter, but I'm just curious to know why, surprisingly --at least for me--, this actually works.
Upvotes: 3
Views: 138
Reputation: 124642
Can anybody tell me why this actually works?
You're assuming this is undefined behavior and UB doesn't mean "your code will crash or fail in obvious ways", it means that anything can happen.
In this case you could envision the stack space used to store the local may not have been reused yet and may still contain the original value. It will probably fail some point down the road, but you cannot expect it to fail in an obvious way.
However, you're not invoking UB here as you're returning a pointer to a string literal which is allocated statically (and likely to be stored in readonly memory, so you really should be returning a const char*
). The array is local; the strings are not.
PS: The way I would do it is to pass a buffer as a parameter...
You could also make the array static within the function. Whether or not that's a good idea depends on your overall design.
Upvotes: 4
Reputation: 47952
This code is correct.
char *str[] = {
"hello",
"hola",
"epa",
"alright",
};
This does not create an array of strings.
It creates an array of pointers to strings. The strings themselves are have static storage duration. The array of pointers has automatic storage duration. When the function returns, the array of pointers becomes off limits, but the strings still exist.
return str[index];
This dereferences the array to retrieve a pointer to one of the strings, and that pointer is returned. str
goes out of scope, but the pointer is still pointing to a string in static storage.
There's no harm in marking str
as static
. The optimizer may already be doing so. So you could write:
static char *str[] = {
"hello",
"hola",
"epa",
"alright",
};
If that makes you more comfortable.
Upvotes: 2
Reputation: 63471
Should I consider myself lucky that this code works (i.e. is this an undefined behavior?) or this is actually a good way of doing things (in this case, why)?
Probably =) Although, from the arguments you've kicked up it's hard to tell. For all intents and purposes, it may work for technical reasons but is not a good idea.
I would make the array static inside the function, but if that still upsets people here, why not just increase the scope?
static const char *str[] = {
"hello",
"hola",
"epa",
"alright"
};
const char *selectStr(int index){
return str[index];
}
Program design considerations regarding globals don't really come into it when you've got this function in the same file as main
... If you split this off into a module, you'd make that array private to the source file and export the selectStr
function. No worries.
Only adjustment I'd make is to name the array something more obviously-global than str
.
Upvotes: 1
Reputation: 39807
String constants, such as "anything", are not stored on the stack. Your stack (in selectStr()) contains an array of pointers, and you are returning a pointer, not the address of a pointer on the stack. Your pointer will be valid at all times in this case.
Upvotes: 2