2

我正在尝试根据此示例通过指定的分隔符拆分字符串:http: //msdn.microsoft.com/en-us/library/ftsafwz3 (v=VS.90).aspx

我的代码在 Visual C++ 2010 中编译没有错误,但是当我想运行它时,我收到以下错误消息:

Test.exe 中 0x773a15de 处的未处理异常:0xC0000005:访问冲突读取位置 0x00000000。

这是我的代码:

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <regex>

using namespace std;

vector<char *> splitString(char in[])
{
vector<char *> parts(15);
char seps[]   = " ,\t\n";
char *next_token1 = NULL;
char *token1 = NULL;
token1 = strtok_s(in, seps, &next_token1);
while ((token1 != NULL))
{
    if (token1 != NULL)
    {
        token1 = strtok_s( NULL, seps, &next_token1);
                    //printf( " %s\n", token1 );
        parts.push_back(token1);
    }
}
return parts;
}

int main(int argc, char * argv[])
{
char string1[] =
    "A string\tof ,,tokens\nand some  more tokens";
vector<char *> parts=splitString(string1);
cout << parts[0] <<endl;
cout << parts[1] <<endl;
return 0;
}

我尝试显示向量的元素似乎是非法的,但为什么呢?

载体的容量应该足够,并且

printf("%s\n", token1);

在while循环中打印出令牌!

4

2 回答 2

2

的使用vector不正确。它由15元素构成,然后push_back()用于添加在初始 15之后添加新元素的字符串。这意味着第一个15元素未分配(空):

std::cout << parts[0] << end; // parts[0] is null

任何一个:

  • 不要在构造时预先分配元素,或者
  • 使用operator[]而不是push_back()(添加额外的循环终止符以保护超出向量的末尾)

(考虑改为std::vector<std::string>。)

顺便提一下,它可以从输入字符串boost::split()生成标记列表 ( ) 并允许指定多个分隔符。std::vector<std::string>

于 2012-10-03T08:12:13.177 回答
2

问题是一个普遍的警告:您strtok在 c++ 中使用(系列)函数。请注意,这个API修改了它的参数。这通常不是你所期望的,因此我建议不要使用这个C库函数。

此外,您假设将读取 15 个元素,而未初始化“剩余”元素。这也会导致访问这些元素时出现未定义的行为。


我可以建议一种 C++ 方法,因为您正在使用它:

#include <iostream>
#include <sstream>
#include <iterator>
#include <algorithm>

using namespace std;

vector<std::string> splitString(const char in[])
{
    std::istringstream iss(in);
    std::istream_iterator<std::string> first(iss), last;

    std::vector<std::string> parts;
    std::copy(first, last, std::back_inserter(parts));
    return parts;
}

int main(int argc, char * argv[])
{
    const char string1[] = "A string\tof ,,tokens\nand some  more tokens";
    vector<std::string> parts = splitString(string1);
    cout << parts[0] <<endl;
    cout << parts[1] <<endl;
    return 0;
}

这使用了一个事实,默认情况下,iostreams 将skipws(跳过空格)

于 2012-10-03T08:24:40.033 回答