what(): basic_string::_M_construct null 无效

what(): basic_string::_M_construct null not valid

我正在编写一个程序,我需要使用一个函数来将字符串的标记存储在向量中。该功能无法正常工作,因此我在较小的程序上尝试了该功能。当然,我使用了字符串分词器函数。但它没有按预期工作。首先,这是代码:

#include <vector>
#include <string>
#include <cstring>
using namespace std;

int main()
{
    vector<string> v;
    string input = "My name is Aman Kumar";
    
    char* ptr = strtok((char*)input.c_str(), " ");
    v.push_back((string)ptr);

    while(ptr)
    {
        ptr = strtok(NULL," ");
        v.push_back((string)ptr);
    }
    cout<<"Coming out";
    for(string s:v)
    {
        cout<<s<<endl;
    }
}

现在是问题。我认为这个问题与命令有关:

(string)ptr

这个东西在第一次调用时完美运行,但在 while 循环中出现时出错。如果我把它注释掉并打印 ptr,那么它工作正常,但是程序在 while 循环后终止,甚至不执行

cout<<"coming out";

不用管向量的内容。但是同样,如果我也不打印 ptr,则会打印存储在矢量中的第一个标记“My”。我真的找不到造成这种情况的原因。任何建议都会有所帮助。

在尝试从中创建字符串之前,您不知道 ptr 是否是 nullptr(并且使用 nullptr 调用 std::string 构造函数是 UB)

您需要重新组织循环,例如像这样:

char* ptr = strtok(input.data(), " ");

while(ptr)
{
    v.push_back(std::string(ptr));
    ptr = strtok(NULL," ");
}

附带说明一下,不要在 C++ 中使用 C 风格的强制转换语法。它很可能会隐藏问题,而 C++ 语法提供了更安全的替代方法。

放弃常量并修改结果在 C++ 中是 UB,因此第一个转换可以替换为 data 调用(需要时 returns 指向非常量的指针)。如果你没有C++11,那么这就是UB,因为不能保证字符串存储在连续内存中,你需要使用different methods.

while(ptr)
{
    ptr = strtok(NULL," ");
    v.push_back((string)ptr);
}

因为最后一个标记 ptr 将为空,从空指针构造 std::string 是未定义的行为。尝试:

while(ptr = strtok(NULL," "))
{
    v.push_back(string(ptr));
}

更多 C++ 解决方案:

#include <vector>
#include <string>
#include <iostream>
#include <sstream>

int main()
{
    std::vector<std::string> v;
    std::string input = "My name is Aman Kumar";
    
    std::stringstream ss(input);
    
    std::string word;
    while(ss >> word)
    {
        v.push_back(word);
    }
    std::cout << "Coming out\n";
    for(std::string& s:v)
    {
        std::cout << s << "\n";
    }
}

您将 std::string 与 C-ish strtok 函数混合使用。这真是个坏主意。 std::string 或多或少可以与 const char * 互换,但不能与可变的 char * 互换。不是说空指针问题。所以选择一种方法并坚持下去。

  1. C-ish 一个:构建一个普通的 char 数组并存储 char *:

    的向量
     char *cstr = strdup(input.c_str());
     ptr = strtok(cstr, " ");
     while(ptr) {
         v.push_back(ptr);
         ptr = strtok(NULL, " ");
     }
    
     cout<<"Coming out";
     for(char *s:v)
     {
         cout<<s<<endl;
     }
    
     free(cstr);         // always free what has been allocated...
    
  2. C++一个,用一个std::stringstream:

     std::stringstream fd(input);
     for(;;) {
         std::string ptr;
         fd >> ptr;
         if (! fd) break;
         v.push_back(ptr);
     }
    
     cout<<"Coming out";
     for(std::string s: v)
     {
         cout<<s<<endl;
     }