簡體   English   中英

嘗試在單詞中插入單詞時出現段錯誤

[英]Segmentation fault while trying to insert a word into trie

嗨:)誰能告訴我下面的代碼為什么不起作用? 程序在與'B'對應的節點中的if(children[word[letter_no] - 'A'] == nullptr)行處崩潰。 但是節點創建,並且當我嘗試在構造函數中調用children[1]時,它就可以工作。 但是在insert()函數中調用它時,它不會...

包括

#include <memory> //shared_ptr
#include <string>    
using namespace std;    
const int ALPHABET = 26;

class Node {
public:
    shared_ptr<Node> children[ALPHABET];

    Node() { for (int i = 0; i < ALPHABET; ++i) children[i] = nullptr;}
    void insert(const string &word, unsigned letter_no) {
        if (letter_no < word.length()) {
            if (children[word[letter_no] - 'A'] == nullptr) 
                children[word[letter_no] - 'A'] = make_shared<Node>();
            children[word[letter_no] - 'A']->insert(word, letter_no+1);
        }
    }
};

int main() {
    Node trie{};
    trie.insert("ABC", 0);
    return 0;
}

啟用您的編譯器警告!

  • 由於未指定評估順序,因此出現未定義的行為

     children[word[letter_no] - 'A']->insert(word, ++letter_no); 

    警告:未進行letter_no修改和訪問letter_no [-未進行順序]

  • 您在這里也有一個潛在的危險比較:

     letter_no < word.length 

    警告:有符號和無符號整數表達式之間的比較

在魔盒上


同樣,您不應該在現代C ++代碼中使用newdelete 根據所需的所有權語義,使用std::unique_ptrstd::shared_ptr


從評論:

傑克 :沒錯,但這都不是造成問題的原因。 我簡化了代碼,使它在一個問題中更具可讀性。 在我的原始代碼中,我嘗試使用shared_ptr,但是結果是相同的。 看,pastebin.com / MFZdrp22效果不好(仍然存在分段錯誤)

仔細查看以下行:

if (letter_no < word.length()) 
{
    if (children[word[letter_no] - 'A'] == nullptr)
    {
        children[word[letter_no] - 'A'] = make_shared<Node>();
    }

    ++letter_no;                                              // (0)
    children[word[letter_no] - 'A']->insert(word, letter_no); // (1)
}
  • word"ABC"

  • word[letter_no] - 'A'0

  • (0)處 ,您增加letter_no

  • (1)處word[letter_no] - 'A'1

  • children[1]nullptr 繁榮!

同樣, 編譯器是您的朋友 使用-fsanitize=undefined編譯,您將收到以下錯誤消息:

runtime error: member call on null pointer of type 'Node'
runtime error: member access within null pointer of type 'Node'

在魔盒上

維托里奧(Vittorio)已經回答了有關風格的理由:

您只能使用一種方法:

void insert(const string &word, size_t letter_no = 0);

那么您就不需要重寫,可以使用std::unique_ptr並且不需要在ctor中循環,並且如果您消除了代碼重復:

    if (letter_no < word.length()) {
        auto &child = children[word[letter_no] - 'A'];
        if ( !child ) 
            child = std::make_unique<Node>();
        child->insert(word, ++letter_no);
    }

這不僅會使您的代碼更具可讀性,而且會使您的問題消失

維托里奧·羅密歐的答案是正確的。 您應該始終清理警告。

但是為了給您一個完整的解釋:

考慮一下您的第一個遞歸, letter_no0 word包含'A''B''C''\\0' 所以letter_no'A'索引。

確認letter_noword的有效索引后: letter_no < word.length()您可以遞增 letter_nochildren[word[letter_no] - 'A']->insert(word, ++letter_no);

letter_no作為此行的第一個操作遞增,因此它實際上具有值1 ,索引為'B' 然后將其減去以'A'得出的索引為1 ,這是未分配的元素。


就解決方案而言,您不必關心保持letter_no的值,因此只需執行以下操作: children[word[letter_no] - 'A']->insert(word, letter_no + 1);

暫無
暫無

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

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