Trie c ++实现分段错误

时间:2016-10-05 20:39:14

标签: c++ data-structures trie

我使用struct和pointer在c ++中实现一个简单的trie数据结构。当我传递一个字符串以添加trie时,它会在addString()函数中给出分段错误。

struct node {
    char ch;
    node *link[26];

    node() : link(){}
};

node head;


void addString(node *n, string s) {
    if (!s.length()) return;

    if (!n -> link[(int)s[0] - 97]) {
        node m;
        m.ch = s[0];
        n -> link[(int)s[0] - 97] = &m;
    }
    addString(n -> link[(int)s[0] - 97], s.substr(1));
}

int main(){
    addString(&head, "red");
    return 0;
}

我尝试了调试语句,甚至打印并匹配新创建的节点的地址值和递归传递的地址值,它们是相同的。

PS我使用头节点作为epsilon状态。

3 个答案:

答案 0 :(得分:2)

您正在使用堆栈上分配的对象的地址。 node m;正在堆叠中。一旦您离开声明它的if块,它将被删除。然后将它的地址分配给一个比这更长的节点n -> link[(int)s[0] - 97] = &m;

答案 1 :(得分:1)

n -> link[(int)s[0] - 97] = &m;

您在m范围内销毁时private ICommand saveCMD; public ICommand SaveCMD { get { if(this.saveCMD == null) { this.saveCMD = new RelayCommand(this.SaveSettings, this.CanSaveSettings) } return saveCMD; } } public bool CanSaveSettings() { return ((tab1_Selected && tab1Data != null && tab1Data.Count > 0) || (tab2_Selected && tab2Data != null && tab2Data.Count > 0) && _saveEnabled); } 的地址。

您应该使用适当的内存管理重新设计项目。

答案 2 :(得分:1)

有两个问题可以解释分段错误:

  • 第一个是将指向本地对象m的指针添加到链接数组中。一旦从函数返回,指针就会悬空,你就会有UB。正确分配m:node *m = new node;更好:使用unique_ptr而不是原始指针。

  • 您认为该字符串仅包含' a'之间的小写字母。和' z'。如果字符串包含任何其他内容,那么您将超出范围并可能导致内存损坏和UB。您应该至少有一个assert()

根据您当前的结构和方法,这是一个解决这两个问题的小修补程序:

struct node {
    ...
    node(char c=0) : link(), ch(c) {} 
    ~node() { for (int i=0;i<26; i++) delete link[i]; }
};
...
void addString(node *n, string s) {
    if (!s.length()) return;
    size_t c = tolower(s[0]); 
    if (c<'a' || c>'z') return;  // char not ok-> do like end of string
    if (!n -> link[c-'a']) {
        n -> link[c-'a'] = new node(c); 
    }
    addString(n -> link[c-'a'], s.substr(1));
}    

请注意,在结构中使用指针时,必须特别注意rule of 3。但是,在这里不会受到伤害,因为你还没有复制节点。

Online demo