Trie c++;实现分段错误 我使用C++和StultUnter在C++中实现了一个简单的TIE数据结构。当我将字符串传递给外接程序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; }

Trie c++;实现分段错误 我使用C++和StultUnter在C++中实现了一个简单的TIE数据结构。当我将字符串传递给外接程序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; },c++,data-structures,trie,C++,Data Structures,Trie,我尝试了调试语句,甚至打印并匹配了新创建的节点和递归传递的节点的地址值,它们是相同的 PS我使用头节点作为epsilon状态。您使用的是堆栈上分配的对象的地址节点m在堆栈上。一旦您离开声明它的if块,它就会被删除。然后将其地址分配给节点n->link[(int)s[0]-97]=&m的使用寿命更长。您正在使用堆栈上分配的对象的地址节点m在堆栈上。一旦您离开声明它的if块,它就会被删除。然后将其地址分配给节点n->link[(int)s[0]-97]=&m它的寿命更长 n -> link[(

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


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

您使用的是堆栈上分配的对象的地址<编码>节点m在堆栈上。一旦您离开声明它的
if
块,它就会被删除。然后将其地址分配给节点
n->link[(int)s[0]-97]=&m的使用寿命更长。

您正在使用堆栈上分配的对象的地址<编码>节点m在堆栈上。一旦您离开声明它的
if
块,它就会被删除。然后将其地址分配给节点
n->link[(int)s[0]-97]=&m它的寿命更长

n -> link[(int)s[0] - 97] = &m;
您正在存储
m
的地址,而它在其作用域的末尾被销毁

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

您正在存储
m
的地址,而它在其作用域的末尾被销毁


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

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

  • 第一个是将指向本地对象
    m
    的指针添加到链接数组中。一旦您从函数返回,指针将悬空,您将获得UB。正确分配m:
    节点*m=新节点更好:使用
    唯一\u ptr
    而不是原始指针

  • 假设字符串只包含“a”和“z”之间的小写字母。如果字符串包含任何其他内容,您将超出范围,并可能导致内存损坏和错误。您应该至少有一个
    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));
}    
struct节点{
...
节点(char c=0):link(),ch(c){}
~node(){for(int i=0;我喜欢字符串的结尾
如果(!n->link[c-'a']){
n->link[c-'a']=新节点(c);
}
addString(n->link[c-'a'],s.substr(1));
}    
请注意,当您在结构中使用指针时,您必须格外小心。但在这里这不会有什么坏处,因为您还没有复制节点


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

  • 第一种方法是将指向本地对象的指针
    m
    添加到链接数组中。一旦从函数返回,指针将悬空,您将拥有UB。正确分配m:
    node*m=new node;
    更好:使用
    unique\u 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));
}    
struct节点{
...
节点(char c=0):link(),ch(c){}
~node(){for(int i=0;我喜欢字符串的结尾
如果(!n->link[c-'a']){
n->link[c-'a']=新节点(c);
}
addString(n->link[c-'a'],s.substr(1));
}    
请注意,当您在结构中使用指针时,您必须格外小心。但在这里这不会有什么坏处,因为您还没有复制节点


请不要在问题中使用标记。它们是两个不同的标记,这是有原因的。解决此类问题的正确工具是调试器。在询问堆栈溢出问题之前,您应该逐行检查代码。有关更多帮助,请阅读。至少,您应该[编辑]您的问题包括一个重现您的问题的示例,以及您在调试器中所做的观察。建议不要使用97。“a”几乎更容易解释。πάνταῥεῖ 是正确的。我试过与clang、gcc、visual studio合作……他们中没有一个人像前面所说的那样抱怨提示:“调试语句”是没有更好选择的人的最后手段。我向你保证,你有更好的选择。请不要在问题中使用标记。它们是两个不同的标记,这是有原因的。解决此类问题的正确工具是调试器。在询问堆栈溢出问题之前,你应该逐行检查代码。有关更多帮助,请阅读尼姆,你应该[编辑]你的问题,包括一个重现你的问题的例子,以及你在调试器中所做的观察。建议不要使用97。“a”几乎是无限容易解释的。πάνταῥεῖ 是正确的。我试过使用clang、gcc、visual studio……他们中没有一个人会像前面所说的那样抱怨提示:“调试语句”是没有更好选择的人的最后手段。我向你保证,你有更好的选择。