2013-02-16 66 views
0

於是,我嘗試寫會返回一個vector<char**>的功能,因爲這樣的:C++的char *解析

vector<char**> test(string mystr) { 

    char*temp=new char[mystr.size()+1]; 

    strcpy(temp,mystr.c_str()); 

    char*subStr=strtok(temp,":"); 

    while(subStr!=NULL) { 

    int i=0; 

    char**args=new char*[200]; 

    char*tempsta=newchar[strlen(subStr)+1]; 

    strcpy(tempsta, subStr); 

    args[i]=strtok(tempsta," "); 

    while(args[i]!=NULL) { 

     i++; 

     args[i]=strtok(NULL," "); 

    } 

    fullVec.push_back(args); 

    //cout<<subStr<<endl; 

    subStr=strtok(NULL,":"); 

    } 
return fullVec; 
} 

所以我想split參數字符串了":"分隔符,然後用「」分隔符。在撥打cout<<subStr的電話時,如果我註釋掉int i=0fullVec.push_back(args)之間的所有內容,我會收到預期的結果。如果我沒有註釋掉所有這些行,我只會得到第一個substring(直到遇到第一個「:」),然後最大的while循環退出。

的期望是什麼我的意思;讓我們假設參數是「我的名字是:邦喬維:XXX AB」 如果一切被註釋掉,下面的線將被打印出來:

my name is 
bon jovi 
xxx ab 

如果我離開它是,會發生什麼事是隻

my name is 

將打印,和大循環將退出

任何幫助表示讚賞,謝謝! (是的,我知道,這似乎是一個愚蠢的練習,可以更優雅地做/易... ...但是我想獲得這個解決方案工作,我招待用串等)之前

+3

混合使用C和C++製造令人討厭的錯誤代碼 – Abhijit 2013-02-16 17:14:58

+2

你不會免費*任何*新的內存...... – nneonneo 2013-02-16 17:15:07

+5

只要你正在編寫C++代碼,就儘可能避免寫C風格的代碼。如果你沒有很好的理由來使用'char *',那麼只需使用'std :: string'。 – LihO 2013-02-16 17:16:40

回答

3

你的問題是strtok()維護調用之間的狀態。

如果第一個參數不爲NULL,則使用以其他方式復位狀態時,它用它救了繼續從停止的地方解析狀態。

既然你有兩個嵌套調用strtok()函數的第二個呼叫與外通話的狀態搞亂。

這一呼籲:

args[i]=strtok(tempsta," "); 

正在重置的strtok的內部狀態()。現在它不再知道你外面的狀態。因此,當你到達內部循環中字符串的末尾時。

這一呼籲:

subStr=strtok(NULL,":"); 

現在使用內循環的保存狀態。所以它基本上只是終止,因爲您已經到達該標記化流的末尾。

+0

我想這是有道理的一些令人費解的方式....你有任何建議,繞過這一點,同時保持封閉的循環結構?我在網上看到的每個解決方案都建議分割循環 – 2013-02-16 18:04:35

+0

更直白地說,'strtok'修改你的C風格的字符串。 – 2013-02-16 18:15:11

+0

@ThomasMatthews:這絕對是一件值得關注的事情(也是關於strtok())的一件壞事)。但這不是造成任何問題的原因。 – 2013-02-16 20:04:03

0

正如在評論中提到,你混合C風格和C++ - 風格的代碼,這導致相當混亂。除非你有「充分的理由」訴諸char*,而不是std::string那麼最好的做法是利用stlboost的。

boost方式:

std::string delims = " :"; 
boost::split(vector, mystr, boost::is_any_of(delims)); 

stl方式:

vector<string> result; 
    std::string delims = " :"; 
    std::istringstream ss(mystr); 
    while (!ss.eof()) 
    { 
    getline(ss, field, delims); 
    if ((empties == split::no_empties) && field.empty()) continue; 
    result.push_back(field); 
    } 

更多的方法和良好的比較,請參閱本cplusplus article

+0

沒有提升!對於初學者來說.. – Arpit 2013-02-16 17:44:09

+0

在限制提升使用的問題中沒有提及,並且我還添加了stl可選方案 – eladidan 2013-02-16 17:46:20

+0

「但是,我希望在我使用字符串等之前獲得此解決方案」:) – Arpit 2013-02-16 17:47:26

2

因爲它是由Loki已經完美地指出, ,你不應該混用C和C++。如果您希望針對您的問題使用C++解決方案,那麼最好堅持使用STL類來處理難以處理的內存管理(請參閱RAII idiom),例如std::string,std::vector,std::istringstream

這是你的功能如何能夠樣子:使用的

typedef std::vector<std::string> Line; 

std::vector<Line> parse(std::string inputString) 
{ 
    std::vector<Line> lines; 
    std::istringstream inputStream(inputString); 
    for (std::string line; std::getline(inputStream, line, ':');) 
    { 
     if (!line.empty()) 
     { 
      lines.push_back(Line()); 
      std::istringstream lineStream(line); 
      for (std::string word; std::getline(lineStream, word, ' ');) 
      { 
       if (!word.empty()) 
        lines.back().push_back(word); 
      } 
     } 
    } 
    return lines; 
} 

例子:

std::vector<Line> lines = parse("my name is: bon jovi: xxx ab"); 

for (int li = 0; li < lines.size(); ++li) 
{ 
    for (int wi = 0; wi < lines[li].size(); ++wi) 
     std::cout << lines[li][wi] << "_"; 
    std::cout << std::endl; 
} 

輸出

my_name_is_ 
bon_jovi_ 
xxx_ab_ 

希望這有助於:)