2010-09-15 95 views
2

由於某些原因,我無法解釋,字符數組中的每個項目...等於最後添加的項目...例如progArgs [0]通過progArgs [size]包含最後一項的值。將std :: list轉換爲char * [size]

我無法弄清楚我在做什麼對我來說是錯誤的。有什麼建議麼?

int count = 0; 
char *progArgs[commandList.size()] 

    for(list<string>::iterator t=commandList.begin(); t!=commandList.end(); t++) 
    { 
     char item[strlen((*t).c_str())]; //create character string 
     strcpy(item, (*t).c_str()); //convert from const char to char 
     progArgs[count] = item; 
     count++; 
    } 

編輯:

感謝所有的快速反應大家......我看你說什麼

+1

除了其他的東西外,'strlen((* t).c_str())'可以替換爲't-> size()'。 – 2010-09-15 02:14:32

回答

3

您正在爲每個元素progArgs分配相同的指針(堆棧數組item的第一個元素的地址),然後重複覆蓋該內存。你可以這樣做:

progArgs[count] = strdup(t->c_str()); 

並擺脫了身體的前兩行。

strdup分配內存,所以你將不得不在每個元素後面用free釋放。另外,你沒有爲NUL終結符分配一個字符。您需要strlen + 1.但是,這不是strdup的問題,因爲它爲您分配。

+0

非常感謝。 – Ryan 2010-09-15 02:15:30

+1

這忽略了commandList將處於作用域並且至少在progArgs被使用之前保持不變的情況,在這種情況下'progArgs [count] = t-> c_str();'就足夠了,並且不需要free()。 – 2010-09-15 02:31:53

+0

@Tony:'progArgs [count] = t-> c_str()'是非法的,因爲'progArgs'是'char *'的數組,而不是'const char *'的數組。如果這是針對'exec'和朋友的猜測,那麼Ryan是其不友好但向後兼容的API的犧牲品。 – 2010-09-15 03:04:44

3

progArgs是指向字符數組。

您將每個指針設置爲指向itemitem是循環中的局部變量,因此一旦循環退出,item不再存在,並且指針不再有效[*]。但是,在您的C++實現中,它們仍然指向堆棧上曾經是數組item的內存位。該內存包含上次使用的內容,它是列表中最後一個字符串的字符序列。

如果你想字符串列表複製到一個數組,它會更好,如果可以使用字符串數組:

std::string progArgs[commandList.size()] // if your compiler has C99 VLAs as an extension 
int count = 0; 

for(std::list<std::string>::iterator t=commandList.begin(); t != commandList.end(); ++t) { 
    progArgs[count] = *t; 
    ++count; 
} 

甚至更​​好,用一個向量而不是數組:

std::vector<std::string> progArgs(commandList.begin(), commandList.end()); 

[*]更準確地說,的item範圍是循環的一個重複,它的標稱「創造」和「破壞」圍繞每個時間。但是這並沒有做任何工作 - 在你的C++實現中,每次都重用相同的內存區域,並且不需要在堆棧上創建或銷燬char數組。

+0

複製到char *數組對於調用期望它的C API非常有用,例如UNIX/Linux execv(...),execvp()。 – 2010-09-15 02:30:28

+0

@Tony:是的,雖然這並不排除使用'vector '來存儲複製的字符串數據。也就是說,如果'char *'數組僅用於對exec的調用,然後立即丟棄,我認爲根本不需要複製字符串。 'exec'函數實際上並不修改字符串數據,由於歷史的原因,它們只取非const,所以對於這個用法,你可以''const_cast''c_str()'的結果。我想,只是爲了避免複製一些字符串有點棘手。 – 2010-09-15 02:52:25

+0

我想'在執行'的情況下,你不需要釋放內存,因爲進程即將被替換,所以有關RAII的良好實踐是無關緊要的...... – 2010-09-15 03:01:06

0

您每次都將progArgs[count]設置爲相同的項目!

int count = 0; 
char *progArgs[commandList.size()] 

for(list<string>::iterator t=commandList.begin(); t!=commandList.end(); t++) 
{ 
    char * item = new char[strlen((*t).c_str()) + 1]; //create new character string 
    strcpy(item, (*t).c_str()); //convert from const char to char 
    progArgs[count] = item; 
    count++; 
} 

然後記得要爲progArgs中的每個元素調用delete[]

就我個人而言,我會創建一個string的數組,並根據需要隨時轉換爲char *

0

char數組item是局部變量,僅在for循環內可用。

改爲動態分配它。

0

你說得對:

for(list<string>::iterator t=commandList.begin(); t!=commandList.end(); t++) 
{ 
    char item[strlen((*t).c_str())]; //create character string 

...這並創建一個數組,但它會創建它在堆棧上,所以當你到達其範圍的結束,它就會被銷燬。

strcpy(item, (*t).c_str()); //convert from const char to char 
    progArgs[count] = item; 
    count++; 
} 

......並且這個右大括號表示其範圍的結束。這意味着你正在創建一個字符串,將它放入你的數組中,然後在添加下一個之前銷燬它。由於你在堆棧中創建它們,所創建的每個新創建的目標都與上一個創建的完全相同,所以毫不奇怪,在最後,你會有一堆相同的字符串

如果你告訴我們你想在這裏完成什麼,也許會更好,所以我們可以幫你做到這一點。

1

item具有本地循環範圍。因此,propArgs數組包含一堆基於堆棧的指針,可能都是一樣的。你可以在調試器中檢查它是如何工作的,只需循環兩次,應該清楚發生了什麼。

當您退出循環時,由公共指針尋址的緩衝區包含最近複製的c_str()

你可以通過做

char* item = new char[strlen((*t).c_str()) + 1]; 

解決這個問題,但是,你不得不在退出循環刪除[]所有propArgs數組項。

此代碼顯示了對內存管理的基本缺乏理解,因此在重構代碼之前進一步閱讀可能會有用。如果這裏使用的代碼只比這個例子稍微複雜一些,那麼它可能只會崩潰,因爲在循環外部任何訪問propArgs都將依賴於無效(不在範圍內)item

+0

您的建議修補程序與原始修補程序一樣有一個脫機。 – 2010-09-15 02:14:49

+0

@Matthew - 謝謝,修正 – 2010-09-15 11:16:42