2014-01-11 54 views
1

問題是,正如標題所說,當我嘗試將第二個向量元素傳遞給函數「solveSide」時。此向量包含兩個字符串標記,從較大的字符串獲得具有用戶定義的功能。C++傳遞向量<string>元素到函數導致SIGSEGV崩潰

的程序是這樣的:

  • 讀線從文件轉換成字符串
  • 叫「stringSplit」函數從該行字符串獲得兩個令牌,並把它們放入一個載體
  • 通話「solveSide」用於在載體中的矢量
  • 呼叫「solveSide」爲第二元件,第一元件

第二次調用「solveSide」時會出現問題,因爲程序在進入函數體之前崩潰。

如果我刪除第二次調用「solveSide」函數,程序運行得很好。 如果我嘗試輸出矢量的兩個元素而不刪除那條線,它不會輸出任何東西,但刪除它後,它會輸出這兩個元素。

在調試模式下,它在調用「std :: string :: _ M_mutate(unsigned int,unsigned int,unsigned int)」(如調用堆棧所示)時會引發SIGSEGV。

崩潰代碼:

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

+1

的字符串中訪問未分配的內存請使用調試器並將問題縮小到特定行/序列的代碼。 –

+0

我做了,並且執行停止在第二次調用「solveSide」的那一行。 – SaruMihai

+0

@ user2327048:'stringChunkToFloat'基本上是'substr()'後跟'atof'嗎? – Zeta

回答

1

我發現這個問題,它更是一個思維的錯誤:

當函數solveSide調用與第二個字符串作爲具有搜索後的值98x,它將搜索"+""-"標誌,一種說法startPos = npos因爲它簡化版,找到它,它進入這種情況下,就在while

}else{ 
    currentNumber = stringChunkToFloat(side, 0, posStart-1); 
    sum += currentNumber; 
} 

當試圖從0位置獲得數npos,它會拋出SIGSEGV(Segmentation Fault),因爲它試圖從傳遞給stringChunkToFloat

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; 
} 
+3

「給你帶來未定義行爲的喜悅」,也許我只是簡單的愚蠢,但我爲此笑了很多。和好的答案,+1 :) –

+0

你是對的,因爲我已經刪除了「strCopy」這樣做沒有意義,即使我沒有,我假設在第一個標記[i]刪除後,行爲將是未定義的。 – SaruMihai

+0

無論如何,看起來這不是SIGSEGV問題的原因(或者至少它不是唯一的原因)。 – SaruMihai

0

它更安全的方式使用矢量做splits.pushback()方法和尺寸更安全得到儘可能吐奶。尺寸()​​。在分配給矢量'成員之前始終檢查vector.size()。