簡體   English   中英

std :: string compare()給出分段錯誤:

[英]std::string compare( ) giving segmentation fault:

因此,我正在制作一個僅在字符串是矢量中尚未包含的唯一字符串的情況下,才將新字符串添加到字符串矢量中的函數。 這是我的代碼:

void CityMapper::addToVector(string& s)
{
    bool newWord = true;
    if(numAirports > 0)
    {
        for(int i = 0; i < numAirports; i++)
        {
            if(airportNames[i].compare(s) == 0)
                newWord = false;
        }
    }
    if(newWord == true)
    {
        airportNames.pushBack(s);
        numAirports++;
    }
}

airportNames是字符串的向量。 當我運行程序時,它在Valgrind中出現以下錯誤:

Process Terminating with default action of signal 11 (SIGSEGV)
Access not within mapped region at address 0x0

在此之前,此錯誤出現在Valgrind終端中:

Invalid Read of Size 8

兩者都發生在string.compare()行。 有誰知道為什么會這樣? 我也嘗試了在參數中不帶&符號的函數。

編輯:我接受了德里克的建議,並做了他的所有更改。 現在,該程序正在使用另一種方法進行段錯誤處理,即從文件中讀取字符串。 這是該函數的代碼:

void CityMapper::getCities()
{
    ifstream fin;
    fin.open(flightDataFile);
    fin >> numAirports;
    string tempCity1, tempCity2, tossout;
    while(getline(fin, tempCity1, ','))
    {
        fin.ignore(1);
        getline(fin, tempCity2, ',');
        fin.ignore(1);
        getline(fin, tossout, '\n');
        addToVector(tempCity1);
        addToVector(tempCity2);
    }
}

以下是來自Valgrind的錯誤消息:

==8357== Use of uninitialised value of size 8
==8357==    at 0x4EF158B: std::basic_string<char, std::char_traits<char>,     
std::allocator<char> >::basic_string(std::string const&) (in /usr/lib/x86_64-linux-
gnu/libstdc++.so.6.0.17)
==8357==    by 0x402214: CityMapper::getCities() (in 
/home/charlie/NetBeansProjects/Lab4/Lab4)
==8357==    by 0x401EB7: CityMapper::run() (in /home/charlie/NetBeansProjects/Lab4/Lab4)
==8357==    by 0x4050A0: main (in /home/charlie/NetBeansProjects/Lab4/Lab4)
==8357== 
==8357== Invalid read of size 4
==8357==    at 0x4EF158B: std::basic_string<char, std::char_traits<char>, 
std::allocator<char> >::basic_string(std::string const&) (in /usr/lib/x86_64-linux-
gnu/libstdc++.so.6.0.17)
==8357==    by 0x402214: CityMapper::getCities() (in   
/home/charlie/NetBeansProjects/Lab4/Lab4)
==8357==    by 0x401EB7: CityMapper::run() (in /home/charlie/NetBeansProjects/Lab4/Lab4)
==8357==    by 0x4050A0: main (in /home/charlie/NetBeansProjects/Lab4/Lab4)
==8357==  Address 0xfffffffffffffff8 is not stack'd, malloc'd or (recently) free'd
==8357== 
==8357== 
==8357== Process terminating with default action of signal 11 (SIGSEGV)
==8357==  Access not within mapped region at address 0xFFFFFFFFFFFFFFF8
==8357==    at 0x4EF158B: std::basic_string<char, std::char_traits<char>, 
std::allocator<char> >::basic_string(std::string const&) (in /usr/lib/x86_64-linux-
gnu/libstdc++.so.6.0.17)
==8357==    by 0x402214: CityMapper::getCities() (in 
/home/charlie/NetBeansProjects/Lab4/Lab4)
==8357==    by 0x401EB7: CityMapper::run() (in /home/charlie/NetBeansProjects/Lab4/Lab4)
==8357==    by 0x4050A0: main (in /home/charlie/NetBeansProjects/Lab4/Lab4)

compare不會導致分段錯誤。 您嘗試調用它的對象不存在。 一般規則:切勿存儲冗余信息(在這種情況下為numAirports )。 如果必須存儲冗余信息,則至少應檢查一致性。 在您在格式錯誤的輸入文件上方發布的代碼中,應用程序將崩潰。 只需完全刪除numAirports ,就不需要它。

而是使用以下命令:

void CityMapper::addUnique( const string& name )
{
    if ( std::find( airportNames.begin(), airportNames.end(), name )
         == airportNames.end() )
    {
        // Name does not yet exist -> add it
        airportNames.push_back( name );
    }
}

注意事項:

  • 該方法已重命名以反映其語義。 您不應該在函數名稱(向量)中編碼數據類型。
  • 簽名已更改為采用const引用。 該方法不會更改此參數,這就是通過編譯器可以驗證的方式對此進行記錄的方式。
  • 參數名稱已更改為name 畢竟,這就是它的代表。
  • 該循環已替換為庫代碼( std::find )。 不要試圖重新發明輪子。

正如評論中指出的那樣,如果沒有令人信服的理由使用std::vector您應該看看std::setstd::unordered_set 這兩個容器都存儲唯一的對象,因此您不必編寫自己的addUnique

如果必須為此使用std::vector (而不是std::unordered_set ):

void CityMapper::addToVector(const string& s) // you aren't changing the string, pass it by const-reference
{
    std::vector<std::string>::iterator it = std::find(airportNames.begin(), airportNames.end(), s);
    if (it == airportNames.end()) // not found, so unique
    {
        airportNames.push_back(s);
    }
}

std::vector具有大小成員(因此不需要numAirports ),並且使用std::find函數可以消除額外的條件檢查。

另外,您可以使用std::unordered_setstd::set並完全避免執行std::find操作(盡管這樣會占用更多內存):

void CityMapper::addToVector(const string& s)
{
    std::set<std::string> airports(airportNames.begin(), airportNames.end());
    airports.insert(s);
    airportNames.assign(airports.begin(), airports.end());
}

更好的解決方案是簡單地將數據存儲在一個集合中,開始於:

void CityMapper::addUnique(const string& s)
{
    // assume airportNames is defined as a std::set<std::string>
    airportNames.insert(s);
}

但是對於您的原始問題:seg錯誤可能是由於您沒有使用std::vector的實際大小,而是存儲了一個單獨的numAirports值(可能不會保持同步,因此不必要)如果您進行了上述更改),那么當您嘗試訪問未分配給向量的內存(可能根本沒有分配)時,您正在調用未定義的行為。 所有這些都不再需要更好的代碼。

編輯

使用您的附加信息,還應該注意,可以大大簡化getCities函數:

struct line_reader : std::ctype<char>
{
    line_reader() : std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table()
    {
        static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
        rc['\n'] = std::ctype_base::space;
        rc[','] = std::ctype_base::space;
        rc[' '] = std::ctype_base::alpha; // allowing city names with spaces
        return &rc[0];
    }
};

void CityMapper::getCities()
{
    ifstream fin(flightDataFile);
    line_reader reader;
    fin.imbue(std::locale(std::locale(), &reader));
    // if using a set
    std::copy(std::istream_iterator<std::string>(fin), std::istream_iterator<std::string>(), std::inserter(airportNames, airportNames.begin()));  

    // or, if using a vector
    // NOTE:  to keep this exception safe 
    // (e.g. keep the values in the actual vector unique even if something happens after we've read in the file data, 
    // pull the values into a temp vector and then swap
    std::vector<std::string> temp;
    std::copy(std::istream_iterator<std::string>(fin), std::istream_iterator<std::string>(), std::back_inserter(temp));
    std::sort(temp.begin(), temp.end());
    temp.erase(std::unique(temp.begin(), temp.end()), temp.end());
    std::swap(airportNames, temp);
}

將代碼更改為此。 我更改了一些使用airportNames.size()東西,該函數返回airportNames向量中的元素數。 如果在向量上調用了pop_back或remove但未更新numAirports,則可以防止發生任何錯誤。 這是造成段故障的最可能原因。

我還修復了我希望是您的airportNames.push_back()調用出現錯字的airportNames.push_back() 您的airportNames.pushBack()語法錯誤。

最后只是樣式,而newWord == true是多余的,只要說if( newWord)兩條語句的評估結果都為true。

void CityMapper::addToVector(const string& s)
{
    bool newWord = true;
    for(int i = 0; i < airportNames.size(); ++i)
    {
        if(s == airportNames[i])
        newWord = false;
        break;
    }
    if(newWord)
    {
        airportNames.push_back(s);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM