Как правильно превратить const char*, возвращенный из функции, в const char** в C?
Короче говоря, я хотел бы сделать это:
const char **stringPtr = &getString();
Тем не менее, я понимаю, что вы не можете & Rvalues. Так что я застрял с этим:
const char *string = getString();
const char **stringPtr = &string;
Я могу жить с двумя линиями. Я представляю проблемы с этим взломом? Я не должен бояться прохода stringPtr
вне функции, в которой оно объявлено, верно?
Изменить: мои извинения за то, что изначально не включали полный контекст. Я взялся за летний проект по созданию видеоигры с нуля на C, используя OpenGL для графики. Я читаю данные конфигурации из текстового файла, используя libconfig.
Одна из вспомогательных функций для поиска конкретной строки из вашего файла конфигурации выглядит следующим образом:
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);
}
Способ присвоения этого значения означает, что если вы передадите функции неинициализированный value
, он пытается переопределить неопределенный мусор, который почти всегда вызывает у меня ошибку. Мой текущий способ решения этой проблемы - инициализация value
сначала к другому указателю, вот так:
const char *dummyPtr;
const char **fileName = &dummyPtr;
config_setting_lookup_string(foo, "bar", fileName);
Поэтому я пытаюсь найти лучший способ переписать последнюю часть функции, чтобы мне не пришлось выполнять эту двухэтапную инициализацию. Я думал, что измененная функция будет выглядеть так:
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);
}
7 ответов
Судя по добавленной информации, вы пытаетесь вызвать функцию, которая хочет вернуть строку через один из аргументов функции. На мой взгляд, лучший способ сделать это:
const char* fileName;
config_setting_lookup_string(..., &fileName);
(...)
return fileName;
Это выделит место для const char * в стеке. Вызов функции заполнит указатель адресом строки, которую он хочет вернуть. Это значение указателя затем может быть передано из функции при необходимости (в отличие от указателя на указатель, который будет указывать на стек и будет недействительным при возврате функции). Обратите внимание, что инициализация fileName с помощью getString(), вероятно, приведет к утечке памяти, поскольку указатель на возвращаемую строку будет перезаписан, а строка никогда не будет освобождена.
Если вы вызываете функцию, которая нуждается в const char**
, вы можете сделать это так:
const char *s = getString();
myFunction(&s);
поскольку s
расположен в стеке в приведенном выше примере, если вы хотите вернуть const char**
из вашей функции, вам нужно будет поместить его в кучу вместо:
const char **sp = malloc(sizeof(const char *));
*sp = getString();
return sp;
НТН
string
в вашем случае это локальный, поэтому брать его адрес - плохая идея, так как память для локального может (и, вероятно, будет) повторно использоваться для других целей, когда вы покидаете метод. В общем случае не рекомендуется использовать адрес локальной переменной вне ее области действия.
Чего ты пытаешься достичь?
Нет, вы не можете изменить config_setting_lookup_string()
так, как вы описали. Вы возвращаете указатель на string
переменная, но как только эта функция завершается, эта переменная выходит из области видимости и уничтожается.
Вы можете, однако, исправить вашу первоначальную проблему довольно легко. Оставьте определение config_setting_lookup_string()
как есть, и назовите это так:
const char *fileName = NULL;
config_setting_lookup_string(foo, "bar", &fileName);
Мне нравится решение nornagon и caf,
const char *fileName;
config_setting_lookup_string(foo, "bar", &fileName);
но если вы можете изменить config_setting_lookup_string
Вы также можете сделать это следующим образом:
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);
Вам нужны две строки. Тем не менее, строка является локальной переменной в стеке, когда она выходит из области видимости, у вас может не быть указателя на данные, возвращаемые getString().
Если вы вернетесь stringPtr
, вы будете возвращать указатель на локальную переменную (string
). Так что нет, ты не можешь этого сделать.
Почему вы пытаетесь это сделать? Это может позволить нам сделать лучшие предложения.
Обновление: Хорошо, теперь я вижу, что вы пытаетесь сделать. Ты делаешь это неправильно:
value = &string;
Если value
подразумевается как выходной параметр, приведенная выше строка не может работать, потому что вы назначаете локальную переменную.
Не позволяйте дополнительному уровню косвенности сбить вас с толку. Если вы писали функцию с выходным параметром типа T
, вы бы написали это как:
void foo(T* value)
{
*value = GetT();
}
Теперь замени T
с const char*
:
...
*value = string;
...
И теперь вы не задействуете никаких временных локальных переменных. Конечно, именно так изначально был написан код (и эта часть была правильной), так что это вам не поможет. Чтобы решить свои намерения, вы должны:
- Делать
config_setting_lookup_string
делатьassert(value != NULL)
, Проведите аудит вызывающих функций и исправьте их, чтобы прекратить передачу мусора. Они должны делать:
const char * foo; config_setting_lookup_string (..., & foo);
и не:
const char** foo;
config_setting_lookup_string(..., foo);