打印出 std::string 崩溃并出现分段错误

Printing out std::string crashes with segmentation fault error

我试图改进我对此处另一个问题的回复 How to cut the content of a string till a particular string or position? 以使用指针算法和 std::substr 所以我得到了以下

#include <iostream>
#include <string>
#include <cstring>

std::string getString(std::string fullString){
    char string[80];
    char* endString;
    strcpy(string, fullString.c_str());
    strtok(string, "|");
    for(int i = 0; i < 4; i++){
        endString = strtok(NULL, "|");
    }
    return fullString.substr(endString - string, std::string::npos);
}
int main( void ){
    std::string str("{[(2015/11/30|01:07:53.357|-1227639088|DefaultThread|./src/Myprogram.cpp:564|int main(int, argv**))]} Server Starting....");
    std::cout << getString(str) << std::endl;
    return 0;
}

但是,如果我将其更改为

,则会因分段错误而崩溃
#include <iostream>
#include <string>
#include <cstring>

std::string getString(std::string fullString){
    char string[80];
    char* endString;
    strcpy(string, fullString.c_str());
    strtok(string, "|");
    for(int i = 0; i < 4; i++){
        endString = strtok(NULL, "|");
    }
    std::cout << fullString.substr(endString - string, std::string::npos) << std::endl;
    return fullString.substr(endString - string, std::string::npos);
}
int main( void ){
    std::string str("{[(2015/11/30|01:07:53.357|-1227639088|DefaultThread|./src/Myprogram.cpp:564|int main(int, argv**))]} Server Starting....");
    std::cout << getString(str) << std::endl;
    return 0;
}

程序运行正常,输出符合预期

./src/Myprogram.cpp:564|int main(int, argv**))]} Server Starting....
./src/Myprogram.cpp:564|int main(int, argv**))]} Server Starting....

为什么在第一种情况下会崩溃?

您输入的字符串是 120 字节宽。您的 C 字符串缓冲区为 80 字节宽。嗯。

使用 find 函数而不是这种容易出错的 C 废话!!

获取自上次以来的所有内容 |:

#include <iostream>
#include <string>
#include <stdexcept>

std::string getString(const std::string& fullString)
{
    size_t pos = fullString.rfind('|');
    if (pos == std::string::npos)
       throw std::runtime_error("Could not find a '|'!");

    return fullString.substr(pos+1);
}

int main()
{
    std::string str("{[(2015/11/30|01:07:53.357|-1227639088|DefaultThread|./src/Myprogram.cpp:564|int main(int, argv**))]} Server Starting....");
    std::cout << getString(str) << std::endl;
}

(live demo)

根据需要调整回扫第 2、3、4 |

您的程序有未定义的行为,因为 str 中存储的字符串长度超过 80 个字符。因此在这个声明中

strcpy(string, fullString.c_str());

你覆盖了超出数组字符串的内存。

此外,使用 C 函数 strtok 代替 class std::string 的成员函数 find(或 rfind)是一种糟糕的方法。

也不清楚为什么在循环中使用了幻数 4

for(int i = 0; i < 4; i++){
    endString = strtok(NULL, "|");
}