I read somewhere that if you want a C/C++ function to return a character array (as opposed to std::string), you must return const char* rather than char*. Doing the latter m
If the char* is allocated on the stack, you return a dangling pointer. Otherwise, so long as it matches the function's prototype and the declaration matches the return value, you should be fine.
What you were told is not true.
Returning a const char *
can improve the semantics of a function (i.e. don't mess with what I'm giving you) but returning a char *
is perfectly fine.
However, in either case, you must make sure that you return a char *
or const char *
that was allocated on the heap in my_function
(i.e. allocated using malloc
or new
), otherwise whenever my_function
returns, the memory for the [const] char *
will be deallocated, and you will be accessing an invalid pointer.
And finally you must remember to free
or delete
the [const] char *
that's been returned to you once you're done with it, or you will leak memory. Aren't C/C++ such great languages?
So, in C, you would have
const char *my_function() {
const char *my_str = (const char *)malloc(MY_STR_LEN + 1); // +1 for null terminator.
/* ... */
return my_str;
}
int main() {
const char *my_str = my_function();
/* ... */
free(my_str);
/* ... */
return 0;
}
Usually, that isn't an issue, but there are things to consider. It's usually a matter of const-correctness, which means keeping track of what you can change and what you can't.
If you're returning a double-quoted string, it's const char *
, and treating it like anything else is an invitation for trouble. Changing such a string is undefined behavior, but will usually cause the program to crash or change that string wherever it's referred to.
If you return a character array on the stack (i.e., a called function's local variable), it will go away, and the pointer will point to nothing in particular, probably with bad results at some time.
If the called function is returning something that's already const char *
, then changing it to char *
requires a cast. Further, if you're actually going to change it, you need to be sure it's changeable. It's usually much better to keep it as const char *
.
There's no immediate problem with returning memory allocated with malloc()
or new
, but you do have the problem of ownership: what function should free()
/delete
it, when, and what do you do about possible copies? This is where C++'s smart pointers shine.
Simply changing the return code won't cause a crash. However if the string you return is static (for example return "AString"
), you should return const char *
to make sure that the compiler detects any attempted modification of that memory, which will likely cause a crash. You can certainly use casts and such to get around the compiler checks, but in that case you'd have to work to make the crash happen.
If you have a function that returns "string literals" then it must return const char*. These do not need to be allocated on the heap by malloc because they are compiled into a read-only section of the executable itself.
Example:
const char* errstr(int err)
{
switch(err) {
case 1: return "error 1";
case 2: return "error 2";
case 3: return "error 3";
case 255: return "error 255 to make this sparse so people don't ask me why I didn't use an array of const char*";
default: return "unknown error";
}
}