首页 > 解决方案 > 将.csv读入`map>`

问题描述

我正在尝试将 .csv 文件读入map<vector<uint>>.

.csv 文件表示一个 modbus 寄存器映射,格式为 name,register,register,register...。例如。

address,1
position,10,11
status,20,21,22

我已经尝试过了(基于https://stackoverflow.com/a/24930415/15655948),并得到了分段错误。 register_map在头文件中声明为类属性。

int SomeClass::readCSV(std::string fileName)
{   
    const uint MAX_LINE_LENGTH = 1024;
    const char* DELIMS = ",";

    std::fstream fin(fileName);

    if (!fin.is_open()) { 
        spdlog::get("runtime_log")->error("Could not open file {0}.", fileName);
        return -1;
    }

    char buffer[MAX_LINE_LENGTH] = {};
    char* pch;
    std::vector<uint> values;

    while (fin.getline(buffer, MAX_LINE_LENGTH)){

        const char* row = strtok(buffer, DELIMS);
        pch = strtok(NULL, DELIMS);
        values.push_back(strtoul(pch,NULL,10));

        while (pch != NULL){
            pch = strtok(NULL, DELIMS);
            values.push_back(strtoul(pch,NULL,10));
        }

        register_map[std::string(row)] = values;
        values.clear();
    }

    return 1;
}

为什么我得到上面的分段错误?

标签: c++

解决方案


在其他假设中,关键的一个是:

while (pch != NULL) {
    pch = strtok(NULL, DELIMS);                 //<-- pch can be NULL
    values.push_back(strtoul(pch, NULL, 10));   //<-- BOOM!
}

在这里,您正在调用strtok,它可能返回 NULL。但是你仍然继续转换字符串。这保证了未定义的行为。

要修复它,您应该颠倒逻辑,以便只转换已经过 NULL 测试的指针。

const char* row = strtok(buffer, DELIMS);

pch = strtok(NULL, DELIMS);
while (pch != NULL) {
    values.push_back(strtoul(pch, NULL, 10));
    pch = strtok(NULL, DELIMS);
}

通过在调试器中运行程序并一次单步执行一行代码,可以很容易地检测到这种类型的错误。调试器也可能会因此类错误而中断执行,并在崩溃时向您显示调用堆栈。所以你会看一看并想“哦,它在这里崩溃了,因为 pch 是 NULL”。

我推荐 Right Now (TM) 作为学习如何调试小程序的好时机。大多数 IDE 都带有一个集成的调试器,这使它变得更加容易。


推荐阅读