2013-02-16 62 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_ 

希望这有助于:)