我使用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状态。
答案 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。但是,在这里不会受到伤害,因为你还没有复制节点。