How do I properly turn a const char* returned from a function into a const char** in C?
In short, I would like to do this:
const char **stringPtr = &getString();
However, I understand that you can't & on rvalues. So I'm stuck with this:
const char *string = getString();
const char **stringPtr = &string;
I can live with two lines. Am I introducing problems with this hack? I should have no fear of passing stringPtr
out of the function it is declared in, right?
Edit: My apologies for not originally including the full context. I have taken on the summer project of building a video game from the ground up in C using OpenGL for graphics. I'm reading configuration data from a text file using libconfig.
One of the convenience functions for finding a specific string from your configuration file looks like this:
int config_setting_lookup_string(const config_setting_t *setting,
const char *name, const char **value)
{
config_setting_t *member = config_setting_get_member(setting, name);
if(! member)
return(CONFIG_FALSE);
if(config_setting_type(member) != CONFIG_TYPE_STRING)
return(CONFIG_FALSE);
*value = config_setting_get_string(member);
return(CONFIG_TRUE);
}
The way that value is assigned means that if you give the function an uninitialized value
, it attempts to derefence undefined garbage, which pretty much always causes me a segfault. My current workaround for this issue is to initialize value
开发者_C百科to another pointer first, like so:
const char *dummyPtr;
const char **fileName = &dummyPtr;
config_setting_lookup_string(foo, "bar", fileName);
So I am trying to figure out the best way to rewrite the last part of the function so that I won't have to perform this two-step initialization. I was thinking that the changed function would look like this:
int config_setting_lookup_string(const config_setting_t *setting,
const char *name, const char **value)
{
config_setting_t *member = config_setting_get_member(setting, name);
if(! member)
return(CONFIG_FALSE);
if(config_setting_type(member) != CONFIG_TYPE_STRING)
return(CONFIG_FALSE);
const char *string = config_setting_get_string(member);
value = &string;
return(CONFIG_TRUE);
}
If you're calling a function that needs a const char**
, you could do it like this:
const char *s = getString();
myFunction(&s);
Since s
is allocated on the stack in the above example, if you want to return a const char**
from your function, you will need to put it on the heap instead:
const char **sp = malloc(sizeof(const char *));
*sp = getString();
return sp;
HTH
string
in your case is a local, so taking the address of it is a bad idea since the memory for the local can (and likely will be) re-used for other purposes when you leave the method. In general, it is not a good idea to use the address of a local variable outside of its scope.
What are you trying to achieve?
No, you can't change config_setting_lookup_string()
in the way you've described. You're returning a pointer to the string
variable, but as soon as that function ends that variable goes out of scope and is destroyed.
You can, however, fix your initial problem quite easily. Leave the definition of config_setting_lookup_string()
as it is, and call it like so:
const char *fileName = NULL;
config_setting_lookup_string(foo, "bar", &fileName);
From the added information, it seems what you are trying to do is call a function which wants to return a string through one of the function arguments. The best way to do this in my opinion would be something like:
const char* fileName;
config_setting_lookup_string(..., &fileName);
(...)
return fileName;
This will allocate room for a const char* on the stack. The function call will fill the pointer with the address of the string it wants to return. This pointer value can then be passed out of the function if needed (unlike the pointer to the pointer, which would point to the stack, and be invalid when the function returns). Note that initializing fileName with "getString()" would presumably leak memory, since the pointer to the returned string would be overwritten, and the string never deallocated.
You need the two lines. However, string is a local variable on the stack, once it goes out of scope, you may not have a pointer to the data returned by getString().
I like nornagon and caf's solution,
const char *fileName;
config_setting_lookup_string(foo, "bar", &fileName);
but if you can change config_setting_lookup_string
you could also do it this way:
int config_setting_lookup_string(..., const char *&value)
{
...
const char *string = config_setting_get_string(member);
value = string;
...
}
const char *fileName;
config_setting_lookup_string(foo, "bar", fileName);
If you return stringPtr
, you will be returning a pointer to a local variable (string
). So no, you can't do that.
Why are you trying to do this? That might allow us to make better suggestions.
Update: Okay, now I see what you're trying to do. You're doing it wrong:
value = &string;
If value
is meant as an output parameter, the above line cannot work because you're assigning to a local variable.
Don't let the extra level of indirection confuse you. If you were writing a function that had an output parameter of type T
, you'd write it as:
void foo(T* value)
{
*value = GetT();
}
Now replace T
with const char*
:
...
*value = string;
...
And now you're not involving any temporary, local variables. Of course, that's how the code was originally written (and that part of it was correct), so that doesn't really help you. To address your intent, you should:
- Make
config_setting_lookup_string
doassert(value != NULL)
. Audit the callers of the function and fix them to stop passing garbage. They should be doing:
const char* foo; config_setting_lookup_string(..., &foo);
and NOT:
const char** foo;
config_setting_lookup_string(..., foo);
精彩评论