C++将char数组转换为二叉树实现后缀表达式求值问题求助
问题根因分析
- 段错误核心诱因是单字符逐位读取逻辑不兼容多位数:原有代码大概率是逐char遍历数组时把每个数字字符都单独当做独立操作数生成节点入栈,遇到多位数时会把
35拆成3和5两个独立节点,导致后续运算符弹出的节点数量不匹配,栈空时还强行pop就会触发段错误。 - 额外的越界风险:如果char数组没有正确加
\0终止符,遍历的时候会访问非法内存,也会触发段错误。
适配多位数的实现方案
第一步:string转char数组的合规处理
严格符合作业要求的转换逻辑,同时保证终止符存在,示例代码:
std::string expr_str; getline(infile, expr_str); // 动态分配char数组,长度+1存储终止符 char* expr_arr = new char[expr_str.size() + 1]; strcpy(expr_arr, expr_str.c_str());
不要直接对c_str()返回的const指针做强制非const转换,避免未定义行为。
第二步:多位数识别与入栈逻辑改造
遍历char数组时新增连续数字拼接逻辑,仅改动操作数读取部分,原有运算符处理逻辑、二叉树构建规则不需要调整:
- 遍历指针每次遇到数字字符时,开启循环读取所有连续的数字字符,拼接成完整的整型值,再生成操作数节点入栈
- 遇到空格直接跳过,遇到运算符就正常弹出右、左两个节点,生成运算符节点入栈
后缀表达式的二叉树构建规则本身兼容多位数,仅操作数读取环节需要适配
第三步:入栈步骤边界校验
针对段错误高发点加防御逻辑:
- 每次生成运算符节点前,先判断栈内节点数是否≥2,不足直接抛出非法表达式错误,避免栈空pop
- 所有节点指针初始化时显式置空,避免野指针访问
核心代码片段示例
// buildExpressionTree方法内的核心遍历逻辑(基于char数组实现) stack<node*> st; int i = 0; while (expr_arr[i] != '\0') { // 跳过空格分隔符 if (isspace(expr_arr[i])) { i++; continue; } // 识别多位数操作数 if (isdigit(expr_arr[i])) { int num = 0; // 连续读取所有数字字符 while (isdigit(expr_arr[i])) { num = num * 10 + (expr_arr[i] - '0'); i++; } // 生成操作数节点入栈 node* numNode = new node; numNode->data = num; // 可根据节点结构体定义调整存储字段 numNode->left = numNode->right = nullptr; st.push(numNode); } // 处理运算符 else if (expr_arr[i] == '+' || expr_arr[i] == '-' || expr_arr[i] == '*' || expr_arr[i] == '/') { // 边界校验,避免栈空弹出触发段错误 if (st.size() < 2) { throw invalid_argument("非法后缀表达式:运算符缺少对应操作数"); } node* right = st.top(); st.pop(); node* left = st.top(); st.pop(); node* opNode = new node; opNode->data = expr_arr[i]; // 运算符可直接存ASCII码,求值时判断类型即可 opNode->left = left; opNode->right = right; st.push(opNode); i++; } else { throw invalid_argument("表达式存在非法字符"); } } // 最终校验:栈内必须仅剩1个根节点 if (st.size() != 1) { throw invalid_argument("非法后缀表达式:节点数量不匹配"); } root = st.top();
内容的提问来源于stack exchange,提问作者imt
相关产品推荐
相关产品推荐

