C ++将vector <string>元素传递给函数会导致SIGSEGV崩溃</string>

时间:2014-01-11 13:43:25

标签: c++ string vector sigsegv function-call

问题是,正如标题所说,当我尝试将第二个向量元素传递给函数“solveSide”时。此向量包含两个字符串标记,从具有用户定义函数的较大字符串中获取。

该程序的工作方式如下:

  • 从文件中读取行到字符串
  • 调用“stringSplit”函数从该行字符串中获取两个标记,并将它们放入向量中
  • 为vector
  • 中的第一个元素调用“solveSide”
  • 为vector
  • 中的第二个元素调用“solveSide”

问题出现在第二次调用“solveSide”中,因为程序在进入函数体之前崩溃。

如果我删除对“solveSide”函数的第二次调用,程序运行就好了。 如果我尝试输出vector的两个元素而不删除该行,它不会删除任何内容,但删除它后,它会输出两个元素。

在调试模式下,它会调用SIGSEGV,当它调用“std :: string :: _ M_mutate(unsigned int,unsigned int,unsigned int)”时(如调用堆栈所示)。

崩溃代码:

ifstream fin("ecuatii.in");
string ecuatie;
vector<string> sideSplit;

fin>>ecuatie;
sideSplit = stringSplit(ecuatie, "=");
fout<<sideSplit[0]<<"="<<sideSplit[1]<<"\n";
solveSide(sideSplit[0], leftCoeffSum, leftSum);
solveSide(sideSplit[1], rightCoeffSum, rightSum);

stringSplit函数:

vector<string> stringSplit(string str, const char *delim){
    char *strCopy = new char [str.size()+1];
    char *token;
    char **tokens = new char* [(str.size()+1)*2];
    unsigned tokenCount = 0;

    strcpy(strCopy, str.c_str());
    token = strtok(strCopy, delim);
    while(token != NULL){
        tokens[tokenCount++] = token;
        token = strtok(NULL, delim);
    }

    vector<string> splits(tokenCount);
    for(unsigned i = 0; i < tokenCount; ++i){
         splits[i] = "";
         splits[i] += tokens[i];
    }

    delete[] strCopy;
    for(unsigned i = 0; i < tokenCount; ++i){
         delete[] tokens[i];
    }
    delete[] tokens;

    return splits;
}

stringChunkToFloat函数(应该使用“substr()”,现在我知道了):

float stringChunkToFloat(string str, unsigned posStart, unsigned posEnd){
    char numberStr[20];
    for(unsigned i = posStart; i <= posEnd; ++i){
        numberStr[i-posStart] = str[i];
    }
    numberStr[posEnd-posStart+1] = '\0';

    float number = atof(numberStr);

    return number;

}

solveSide功能:

void solveSide(string &side, float &coeffSum, float &sum){
    coeffSum = 0;
    sum = 0;

    unsigned posStart = side.find_first_of("+-", 1);
    unsigned posEnd;
    float currentNumber;

    if(side.size() == 1){
        if(side[0] == 'x'){
            coeffSum = 1;
        }else{
            sum = atof(side.c_str());
        }
        return;
    }

    if(side[0] == 'x'){
        coeffSum += 1;
    }else if(side[1] == 'x' && side[0] == '-'){
        coeffSum -= 1;
    }else if(side[posStart-1] == 'x'){
        currentNumber = stringChunkToFloat(side, 0, posStart-2);
        coeffSum += currentNumber;
    }else{
        currentNumber = stringChunkToFloat(side, 0, posStart-1);
        sum += currentNumber;
    }

    while(posStart != string::npos && posStart != side.size()){
        posEnd = side.find_first_of("+-", posStart+1);
        if(posEnd == string::npos){
            posEnd = side.size();
        }

        if(side[posStart+1] == 'x'){
            if(side[posStart] == '+'){
                coeffSum += 1;
            }else{
                coeffSum -= 1;
            }
        }else if(side[posEnd-1] == 'x'){
            currentNumber = stringChunkToFloat(side, posStart, posEnd-2);
            coeffSum += currentNumber;
        }else{
            currentNumber = stringChunkToFloat(side, posStart, posEnd-1);
            sum += currentNumber;
        }

        posStart = posEnd;
    }
}

输入字符串:2.0x-4+5x+300=98x

3 个答案:

答案 0 :(得分:4)

这个块不仅没有必要,而且带给你未定义行为的乐趣:

for(unsigned i = 0; i < tokenCount; ++i){
     delete[] tokens[i];
}

考虑一下:你为tokens分配了内存,而不是为自己的代币分配内存。毕竟,它们是指向您的标记化字符串的指针(std::strtok具有破坏性)。

更好的是,如果可以避免,请不要使用原始内存:

vector<string> stringSplit(const string& str, const char *delim){
    // Note: if you use C++11, you can use std::string::data() 
    // and don't need a copy to a vector, just take the string by value
    vector<char> strCopy(str.begin(), str.end());
    strCopy.push_back('\0');

    vector<char*> tokens;
    {        
        char * token = strtok(strCopy.data(), delim);
        while(token != NULL){
            tokens.push_back(token);
            token = strtok(NULL, delim);
        }
    }

    vector<string> splits(tokens.size();
    for(unsigned i = 0; i < tokens.size(); ++i){
         splits[i] = "";
         splits[i] += tokens[i];
    }

    return splits;
}

答案 1 :(得分:1)

我发现了问题,这更像是一个思考错误:

当使用第二个字符串作为具有值solveSide的参数调用函数98x时,它会在搜索后搜索"+""-"个符号{ {1}}因为它找不到它,并且在startPos = npos之前就进入了这种情况:

while

当它尝试从位置}else{ currentNumber = stringChunkToFloat(side, 0, posStart-1); sum += currentNumber; } 获取数字到0时,它会抛出SIGSEGV(分段错误),因为它尝试从传递给npos的字符串中访问未分配的内存

答案 2 :(得分:0)

使用vector更安全的方法是使用splits.pushback()方法和大小更安全得到spits.size()。始终在赋值给vector'成员之前检查vector.size()。