You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用C++库时unordered_map触发Segmentation fault问题求助

排查C++ Trie实现中的Segmentation Fault问题

我在Python中调用修改后的C++ Trie自动补全代码时,持续触发Segmentation fault (core dumped)错误,经定位错误出现在unordered_map的children.count(remaining_w.at(0))语句,恳请帮忙排查原因。

完整代码

C++ 实现代码

#include <iostream>
#include <unordered_map>
#include <string>
#include <fstream>
#include <unordered_set>
#include <vector>
#include <sstream>
#include <typeinfo>

using namespace std;
// using namespace std::chrono;

class trie{
    public:
        string word;
        unordered_map<char, trie*> children;

        // this function works
        // with the argument flag set to zero
        int insert(string w, int flag, string remaining_w = ""){  
            //the first time we call insert
            if(flag == 0)
                remaining_w = w;
            int the_size = remaining_w.size();

            if(children.count(remaining_w.at(0)) == 0){
                children[remaining_w.at(0)] = new trie();
    
            }
            if(the_size == 0){
            word = w;
            return 0;
            }else{
            //the recursive calls with flag one
            children[remaining_w.at(0)]->insert(w, 1, remaining_w.erase(0, 1));
            return 0;
            }
        }
};

class AutoCorrect{

    public:
        // The tree
        trie tree;
        //the dictionary with the words
        const int max_cost = 2;
        const int too_big_distance = 10;

        void insert(char* word){
            
            ifstream ifp(word);
            
            while(ifp >> word){
                cout << word <<endl;
                tree.insert(word, 0);
        // }
        }

        }

        void test(char* test){
            cout << test << endl;        
        }

        void search_recursive(trie* p_tree, char ch, const string& word, vector<int>& previous_row, int max_cost, unordered_map <string, int>& results)
        {
            int sz = previous_row.size();
            int min_row = 12;
        
            vector<int> current_row(sz, too_big_distance);
            current_row[0] = previous_row[0] + 1;
        
            // Calculate the min cost of insertion, deletion, match or substution
            int insert_or_del, replace;
            for (int i = 1; i < sz; i++) {
                insert_or_del = min(current_row[i-1] + 1, previous_row[i] + 1);
                replace = (word[i-1] == ch) ? previous_row[i-1] : (previous_row[i-1] + 1);
        
                current_row[i] = min(insert_or_del, replace);
            }
        

            if ((current_row[sz-1] <= max_cost) && (p_tree->word != "")) {
            results[p_tree->word] = current_row[sz-1];
            }

            for(auto& it: current_row){
                if (it < min_row)
                    min_row = it;
            }
            if(min_row <= max_cost){
                for(auto& it: p_tree->children){
                    search_recursive(it.second, it.first, word, current_row, max_cost, results);
            }
            }
            
        }


        int search(string word)
        {
            unordered_map <string, int> results;
                
            int sz = word.size();
            
            vector<int> current_row(sz + 1);
            
            for (int i = 0; i <= sz; ++i){ 
                current_row[i] = i;
            }
            
            for(auto& it: tree.children){
                search_recursive(it.second, it.first, word, current_row, max_cost, results);
            }

            for(auto& p:results)
                cout << p.first << ", " << p.second <<  endl;

            return 0;
        }

};

// The cost and a distance for vector initialization

extern "C" {
    AutoCorrect* AutoCorrect_new(){ return new AutoCorrect(); }
    void AutoCorrect_insert(AutoCorrect* autocorrect, char* word){ autocorrect->insert(word); }
    void AutoCorrect_search(AutoCorrect* autocorrect, string input_word){ autocorrect->search(input_word); }
    void AutoCorrect_test(AutoCorrect* autocorrect, char* name){ autocorrect-> test(name); }
}

Python 调用代码

from ctypes import cdll
lib = cdll.LoadLibrary('autocorrect.so')

class AutoCorrect(object):
    def __init__(self):
        self.obj = lib.AutoCorrect_new()

    def insert(self, word):
        lib.AutoCorrect_insert(self.obj,word)
    
    def search(self,input_word):
        lib.AutoCorrect_search(self.obj,input_word)

    def test(self,test):
        lib.AutoCorrect_test(self.obj,test)

if __name__ == "__main__":
    import json
    WordCount = 0

    autocorrect = AutoCorrect()

    data_dir = "some_txt_file.txt"
autocorrect.insert(bytes(str(data_dir), encoding='utf8'))

问题原因分析及修复方案

1. Trie插入函数的字符串越界问题

这是触发段错误的直接原因:

  • 在trie::insert函数中,代码先执行children.count(remaining_w.at(0)),之后才判断the_size == 0。当remaining_w为空字符串时,remaining_w.at(0)会直接抛出std::out_of_range异常,进而导致程序崩溃(段错误)。
  • 修复逻辑:调整判断顺序,先检查字符串是否为空,再执行后续操作:
int insert(string w, int flag, string remaining_w = ""){  
    if(flag == 0)
        remaining_w = w;
    int the_size = remaining_w.size();

    // 先判断字符串是否为空,避免越界访问
    if(the_size == 0){
        word = w;
        return 0;
    }

    if(children.count(remaining_w.at(0)) == 0){
        children[remaining_w.at(0)] = new trie();
    }
    // 递归插入剩余字符
    children[remaining_w.at(0)]->insert(w, 1, remaining_w.erase(0, 1));
    return 0;
}

2. AutoCorrect::insert的缓冲区溢出问题

  • 函数参数char* word被同时用作文件名和读取单词的缓冲区,当读取的单词长度超过原指针指向的内存空间时,会发生缓冲区溢出,破坏内存结构,导致后续操作出现不可预测的错误(包括段错误)。
  • 修复方案:使用std::string接收读取的单词:
void insert(char* filename){
    ifstream ifp(filename);
    string word; // 用string安全接收单词
    while(ifp >> word){
        cout << word << endl;
        tree.insert(word, 0);
    }
}

同时注意修改extern "C"中的对应函数声明,保持参数一致。

3. C++与Python交互的类型不匹配问题

  • extern "C"中的AutoCorrect_search函数参数使用std::string,但C语言没有该类型,Python的ctypes无法正确传递参数,会导致内存错误。
  • 修复方案:将参数改为char*,内部转换为std::string:
// C++端修改
void AutoCorrect_search(AutoCorrect* autocorrect, char* input_word){ 
    autocorrect->search(string(input_word)); 
}

// Python端调用时直接传字符串(ctypes会自动转为char*)
def search(self, input_word):
    lib.AutoCorrect_search(self.obj, input_word.encode('utf8'))

4. 额外的内存泄漏风险

  • 当前代码中trie节点使用new创建,但没有对应的delete操作,长期运行会导致内存泄漏。建议后续添加析构函数,递归销毁所有子节点。

内容的提问来源于stack exchange,提问作者John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 09:50:27