2012-12-25 30 views
1

我有一個函數將字符串分割成不同的部分,然後解析它們,但是當將字符串轉換爲char *時,我得到格式錯誤的輸出。在C++中將字符串轉換爲char *時的格式不正確

int parseJob(char * buffer) 
{ // Parse raw data, should return individual jobs 
    const char* p; 
    int rows = 0; 
    for (p = strtok(buffer, "~"); p; p = strtok(NULL, "~")) { 
     string jobR(p); 
     char* job = &jobR[0]; 
     parseJobParameters(job); // At this point, the data is still in good condition 
    } 
    return (1); 
} 

int parseJobParameters(char * buffer) 
{ // Parse raw data, should return individual job parameters 
    const char* p; 
    int rows = 0; 
    for (p = strtok(buffer, "|"); p; p = strtok(NULL, "|")) { cout<<p; } // At this point, the data is malformed. 
    return (1); 
} 

我不知道在調用第二個函數的第一個函數之間會發生什麼,但是它會使數據變形。

正如您從給出的代碼示例中所看到的,使用將字符串轉換爲char *的相同方法並且它工作正常。

我正在使用Visual Studio 2012/C++,任何指導和代碼示例將不勝感激。

+1

你做錯了:) 請參閱http://stackoverflow.com/questions/7352099/stdstring-to-char – Davita

+0

你試過string :: c_str()而不是&jobR [0]?不知道這是否改變了語義。 –

回答

2

「物理」的原因您的代碼不工作無關,與std::string或C++。它在純C中也不起作用。 strtok是一個將其中間解析狀態存儲在某個全局變量中的函數。這立即意味着您不能使用strtok一次解析多個字符串。在完成第一個分析會話之前開始第二個分析會話將覆蓋第一個分析會話存儲的內部數據,從而將其破壞無法修復。換句話說,strtok解析會話一定不能重疊。在你的代碼中,它們確實重疊。


而且,在C++ 03使用與std::string直接strtok從一開始就註定的想法。保存在std::string中的內部序列不保證以空終止。這意味着一般&jobR[0]不是C字符串。它不能與strtok一起使用。要將std::string轉換爲C字符串,您必須使用c_str()。但是由c_str()返回的C字符串是不可修改的。

在C++ 11中,空終止應該通過[]運算符可見,但似乎仍不需要將終結符對象與實際字符串連續存儲,因此&jobR[0]仍不是C-即使在C++ 11中也是如此。由c_str()data()返回的C字符串是不可修改的。

+0

感謝您爲我解決這個問題,您能給出一些關於如何阻止兩個解析會話重疊的建議嗎? – Ryan

+0

@ user1661022:重新設計您的代碼(以便它們不重疊)或保持設計原樣,但停止使用'strtok'。編寫你自己的可重複使用的解析器,或者使用來自Boost或其他庫的現有庫解決方案。 – AnT

+0

在我看來,這是一個非常強大的回答在SO上其他地方提問的問題。我會支持將這個問題作爲冗餘問題的典型答案。 –

0

雖然這會給你字符串char* job = &jobR[0];中第一個字符的地址,但它不會給你一個有效的C風格的字符串。你氣應該使用char* job = jobR.c_str();

我相當肯定,將解決你的問題,但當然也有可能是什麼問題你讀傳遞給parseJob在爲好buffer的方式。

編輯:當然,你也從使用strtok的函數調用strtok。裏面的strtok看起來有點像這樣:

char *strtok(char *str, char *separators) 
{ 
    static char *last; 
    char *found = NULL; 

    if (!str) str = last; 
    ... do searching for needle, set found to beginning of non-separators ... 
    if (found) 
    { 
      *str = 0; // mark end of string. 
    } 

    last = str; 
    return found; 
} 

由於「最後」被覆蓋,當你調用parseParameters,您不能使用strtok(NULL, ...)當你回到parseJobs

+0

我已經試過這樣做,但IntelliSense報告說:「類型爲」const char *「的值不能用於初始化一個類型爲」char *「的實體。 – Ryan

+0

啊,是的,當然,你也是搞亂了關於std :: string中的字符串 - 壞主意,你需要將它複製到一個新的地方 使用std :: string一路通過C++編寫代碼可能會更容易! –

2

不能使用strtok()解析多個字符串同時,就像你正在做的一樣。在parseJob()的第一次循環迭代中第一次調用parseJobParameters()將改變strtok()指向的內部緩衝區,因此parseJob()的第二循環迭代不再處理原始數據。你需要重寫代碼不使用strtok()嵌套調用了,如:

#include <vector> 
#include <string> 

void split(std::string s, const char *delims, std::vector &vec) 
{ 
    // alternatively, use s.find_first_of() and s.substr() instead... 
    for (const char* p = strtok(s.c_str(), delims); p != NULL; p = strtok(NULL, delims)) 
    { 
     vec.push_back(p); 
    } 
} 

int parseJob(char * buffer) 
{ 
    std::vector<std::string> jobs; 
    split(buffer, "~", jobs); 
    for (std::vector<std::string>::iterator i = jobs.begin(); i != jobs.end(); ++i) 
    { 
     parseJobParameters(i->c_str()); 
    } 
    return (1); 
} 

int parseJobParameters(char * buffer) 
{ 
    std::vector<std::string> params; 
    split(buffer, "|", params); 
    for (std::vector<std::string>::iterator i = params.begin(); i != params.end(); ++i) 
    { 
     std::cout << *i; 
    } 
    return (1); 
} 
相關問題