2010-05-09 90 views
3

總之,我想這樣做:如何正確地將從函數返回的const char *轉換爲C中的const char **?

const char **stringPtr = &getString(); 

不過,據我所知,你不能&上右值。所以我堅持這一點:

const char *string = getString(); 
const char **stringPtr = &string; 

我可以住兩條線。我是否會爲這個黑客引入問題?我不應該害怕從它聲明的函數中傳遞stringPtr,對吧?

編輯:我對最初不包括完整的上下文的道歉。 我已經開始使用OpenGL爲C語言編寫C語言遊戲。我正在使用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); 
} 

回答

0

從添加的信息,好像你正在嘗試做的是調用它想通過函數參數之一返回一個字符串的函數。在我看來,這樣做的最好方法是這樣的:

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

這將爲堆棧上的const char *分配空間。該函數調用將填充指針與它想要返回的字符串的地址。如果需要,可以將該指針值傳遞出該函數(不像指向指向堆棧的指針的指針,並且在函數返回時無效)。 請注意,使用「getString()」初始化fileName可能會泄漏內存,因爲指向返回字符串的指針將被覆蓋,並且字符串從不釋放。

0

你需要兩條線。但是,字符串是堆棧上的局部變量,一旦超出範圍,您可能沒有指向由getString()返回的數據的指針。

0

如果你返回stringPtr,你將返回一個指向局部變量的指針(string)。所以不,你不能那樣做。

你爲什麼要這麼做?這可能會讓我們提出更好的建議。

更新: 好吧,現在我明白你想要做什麼了。你這樣做是錯誤的:

value = &string; 

如果value意味着作爲輸出參數,上面的行不行,因爲你分配到一個局部變量

不要讓額外的間接困擾你。如果你正在寫的是有T類型的輸出參數的函數,你把它寫成:

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

現在用const char*替換T

... 
*value = string; 
... 

現在你沒有任何涉及臨時的局部變量。當然,這就是代碼最初編寫的方式(並且它的一部分是正確的),所以這對你並沒有什麼幫助。爲了解決您的意圖,您應該:

  1. 製造config_setting_lookup_stringassert(value != NULL)
  2. 審覈函數的調用者並修復它們以阻止垃圾通過。他們應該這樣做:

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

和NOT:

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

編輯並添加了我想要完成的內容。基本上,我試圖重寫一個庫函數,通過const char **返回一個字符串,以包含一些更適合我的樣板初始化代碼。 – spirulence 2010-05-09 06:44:46

1

string你的情況是本地的,所以取它的地址是因爲本地可以存儲一個壞主意(可能會)重新在離開方法時用於其他目的。一般來說,在範圍之外使用局部變量的地址並不是一個好主意。

你想達到什麼目的?

+0

應該在之前添加。感謝您的noob耐心。現在編輯。 根據文檔,「由config_lookup_string()返回的字符串的存儲由庫管理,並在設置被銷燬或設置的值被更改時自動釋放;該字符串不能被調用者釋放。 http://www.hyperrealm.com/libconfig/libconfig_manual.html#The-C-API – spirulence 2010-05-09 06:07:54

3

如果你調用一個需要const char**的功能,你可以做這樣的:

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

由於s被分配在上面的例子在堆棧中,如果你想返回從const char**你的功能,你需要把它放在堆來代替:

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

HTH

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); 
相關問題