1

我有一个函数可以将字符串分成不同的部分,然后解析它们,但是当将字符串转换为 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++,任何指导和代码示例将不胜感激。

4

3 回答 3

2

您不能strtok()像您正在做的那样同时解析多个字符串。parseJobParameters()的第一次循环迭代中的第一次调用parseJob()将改变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);
}
于 2012-12-25T20:37:53.223 回答
2

std::string您的代码不起作用的“物理”原因与C++无关。它也不适用于纯 C。strtok是一个将其中间解析状态存储在某个全局变量中的函数。这立即意味着您不能strtok一次解析多个字符串。在完成第一个解析会话之前启动第二个解析会话将覆盖第一个解析会话存储的内部数据,从而将其破坏到无法修复的地步。换句话说,strtok解析会话不能重叠。在您的代码中,它们确实重叠。


此外,在 C++03 中,直接使用std::stringwith的想法strtok从一开始就注定失败。不保证存储的内部序列std::string是空终止的。这意味着通常&jobR[0]不是 C 字符串。它不能与strtok. 要将 a 转换std::string为 C 字符串,您必须使用c_str(). 但是返回的 C 字符串c_str()是不可修改的。

在 C++11 中,空终止符应该通过[]运算符可见,但似乎仍然不需要将终止符对象与实际字符串连续存储,因此&jobR[0]即使在 C++ 中仍然不是 C 字符串11. c_str()由or返回的 C 字符串data()是不可修改的。

于 2012-12-25T21:15:32.720 回答
0

虽然这将为您提供字符串中第一个字符的地址char* job = &jobR[0];,但它不会为您提供有效的 C 样式字符串。你应该使用char* job = jobR.c_str();

buffer我相当确定这会解决您的问题,但是您阅读传递给的方式当然也可能有问题parseJob

编辑:当然,您还从使用 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;
}

由于“last”在您调用时被覆盖parseParameters,因此您无法strtok(NULL, ... )在返回时使用parseJobs

于 2012-12-25T20:10:47.390 回答