2010-05-09 4 views
3

Короче говоря, я хотел бы сделать это:Как правильно преобразовать 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, он пытается derefence undefined мусор, который почти всегда вызывает у меня segfault. Мой текущий обходной путь для этой проблемы заключается в инициализации 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); 
} 

ответ

0

с добавленной информации, кажется, что вы пытаетесь сделать, это вызвать функцию, которая хочет вернуть строку через один из аргументов функции. Лучший способ сделать это, на мой взгляд было бы что-то вроде:

const char* fileName; 
config_setting_lookup_string(..., &fileName); 
(...) 
return fileName; 

Это выделит место для константный символ * в стеке. Вызов функции заполнит указатель адресом строки, которую он хочет вернуть. Это значение указателя затем может быть передано из функции, если необходимо (в отличие от указателя на указатель, который указывает на стек, и будет недействительным, когда функция вернется). Обратите внимание, что инициализация fileName с помощью «getString()» предположительно будет утечка памяти, поскольку указатель на возвращаемую строку будет перезаписан, а строка никогда не будет освобождена.

0

Вам нужны две линии. Однако строка - это локальная переменная в стеке, как только она выходит из области видимости, у вас может не быть указателя на данные, возвращаемые getString().

0

Если вы вернетесь stringPtr, вы вернете указатель на локальную переменную (string). Так что нет, вы не можете этого сделать.

Почему вы пытаетесь это сделать? Это может позволить нам сделать лучшие предложения.

Обновление: Хорошо, теперь я вижу, что вы пытаетесь сделать. Вы делаете это неправильно:

value = &string; 

Если value предназначен в качестве выходного параметра, выше строка не может работать, потому что вы присваивание локальной переменной.

Не допускайте, чтобы дополнительный уровень косвенности путал вас. Если вы пишете функцию, которая имела выходной параметр типа T, вы бы написать:

void foo(T* value) 
{ 
    *value = GetT(); 
} 

Теперь замените T с const char*:

... 
*value = string; 
... 

И теперь вы не связанные с какой-либо временные локальные переменные.Разумеется, так изначально был написан код (и эта часть была правильной), так что это действительно не поможет вам. Для решения ваших задач вам необходимо:

  1. config_setting_lookup_string do assert(value != NULL).
  2. Аудит вызывающих функций и их устранение, чтобы остановить передачу мусора. Они должны делать:

    const char * foo; config_setting_lookup_string (..., & foo);

и НЕ:

const char** foo; 
config_setting_lookup_string(..., foo); 
+0

Отредактировано и добавлено полное контекст того, что я пытаюсь сделать. В принципе, я пытаюсь переписать библиотечную процедуру, которая возвращает строку через const char **, чтобы включить некоторый код инициализации шаблона, который мне подходит лучше. – spirulence

1

string в вашем случае является локальным, поэтому принимать адрес это плохая идея, так как память для локального может (и скорее всего будет) повторно используется для других целей, когда вы покидаете метод. В общем, не рекомендуется использовать адрес локальной переменной вне ее области.

Что вы пытаетесь достичь?

+0

Должен был добавить это раньше. Спасибо за ваше терпение noob. Отредактировано сейчас. В соответствии с документацией «Хранение для строки, возвращаемой config_lookup_string(), управляется библиотекой и автоматически выдается, когда параметр уничтожается или когда значение параметра изменяется, а строка не должна быть освобождена вызывающим». http://www.hyperrealm.com/libconfig/libconfig_manual.html#The-C-API – spirulence

3

Если вы вызываете функцию, которая нуждается в const char**, вы могли бы сделать это следующим образом:

const char *s = getString(); 
myFunction(&s); 

Поскольку s выделяется в стеке в приведенном выше примере, если вы хотите вернуть const char** из ваша функция, вам нужно будет поместить его в куче вместо:

const char **sp = malloc(sizeof(const char *)); 
*sp = getString(); 
return sp; 

НТН

1

нет, вы не можете изменить config_setting_lookup_string() так, как вы описали. Вы возвращаете указатель на переменную string, но как только эта функция заканчивается, эта переменная выходит за пределы области действия и уничтожается.

Вы можете, однако, исправить свою начальную проблему довольно легко. Оставьте определение config_setting_lookup_string(), как она есть, и назвать его так:

const char *fileName = NULL; 
config_setting_lookup_string(foo, "bar", &fileName); 
0

Мне нравится 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); 
Смежные вопросы