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

为何二叉树序列化反序列化代码在VSCode正常却在在线编辑器报运行时错误?

二叉树序列化/反序列化的运行时错误分析

问题背景

实现二叉树的序列化与反序列化功能,本地VSCode测试运行正常,序列化结果为12345,反序列化后重新序列化结果仍为12345,但在线代码测试平台触发运行时错误,错误信息如下:

Address 0x7f547eb00021 is located in stack of thread T0 at offset 33 in frame
#0 0x40280f in helper /app/example.c:65
This frame has 1 object(s):
[32, 33) 'temp' (line 68) <== Memory access at offset 33 overflows this variable

错误信息含义解释

这段错误信息的中文翻译及核心含义:

地址0x7f547eb00021位于线程T0的栈帧中,偏移量33的位置
#0 错误发生在helper函数(对应代码第65行)
该栈帧中有一个变量:
占据内存区间[32,33)的temp变量(对应代码第68行)<== 访问偏移量33的内存超出了该变量的边界

简单来说:temp是单个char类型变量,在栈中仅占用1字节内存(左闭右开区间[32,33)),但代码访问了该区间之外的内存,触发了栈内存溢出。

代码问题根源

1. atoi(&temp)的越界访问

在helper函数中,你通过atoi(&temp)将单个字符转换为整数:

char temp = removeStr(Q);
// ...
new->val = atoi(&temp);

atoi函数要求输入是以\0结尾的C字符串,但temp是单个char变量,&temp指向的栈地址后没有自动补\0。atoi执行时会从temp的地址开始持续读取字节,直到遇到\0,这就会越界访问temp之后的栈内存,触发运行时错误。

本地测试未报错是巧合:你的本地栈中temp之后恰好有一个\0字节,atoi读取到此处停止,未触发越界检测;但在线平台的栈布局不同,temp之后没有\0,atoi继续读取超出变量范围的内存,触发了平台的内存保护机制。

2. 序列化/反序列化的逻辑错误(潜在问题)

当前序列化仅输出节点值,未记录空节点信息,但反序列化采用递归创建(类似前序遍历逻辑),会导致反序列化后的树结构与原树完全不同。比如原树为:

1
   / \
  2   3
     / \
    4   5

序列化结果是12345,反序列化后生成的树结构实际为:

1
       /
      2
     / \
    3   4
   /
  5

只是恰好层序遍历结果仍为12345,导致你误以为结构正确,但实际逻辑存在严重错误。

修复方案

1. 修复atoi的越界问题

将单个字符转换为以\0结尾的字符串后再调用atoi:

struct TreeNode* helper(struct Queue* Q){
    if(!isEmpty(Q)){
        char temp = removeStr(Q);
        if(temp == '\0') return NULL;
        struct TreeNode* new = malloc(sizeof(struct TreeNode));
        printf("\nChar : %c",temp);
        // 修复:创建临时字符串,确保以'\0'结尾
        char buf[2] = {temp, '\0'};
        new->val = atoi(buf);
        new->left = helper(Q);
        new->right = helper(Q);
        return new;
    }
    return NULL;
}

2. 修复序列化/反序列化的逻辑错误

需要在序列化时用特殊字符(如#)标记空节点,反序列化时根据标记正确构建树:

  • 修改LOT函数(序列化):遇到空节点时写入#
  • 修改helper函数(反序列化):读取到#时返回NULL,停止递归创建子节点

修改后的LOT函数示例:

void LOT(struct TreeNode* root,char* s){
    struct Queue Q1;
    Q1.front = 0;
    Q1.rear = 0;
    int index = 0;
    addQueue(&Q1,root);
    while(!isEmpty(&Q1)){
        int size = qSize(&Q1);
        for (int i = 0; i < size; i++)
        {
            root = removeQueue(&Q1);
            if(root == NULL){
                s[index++] = '#';
                continue;
            }
            s[index++] = root->val + '0';
            addQueue(&Q1,root->left);
            addQueue(&Q1,root->right);
        }
    }
    s[index]='\0';
}

修改后的helper函数示例:

struct TreeNode* helper(struct Queue* Q){
    if(isEmpty(Q)) return NULL;
    char temp = removeStr(Q);
    if(temp == '#' || temp == '\0') return NULL;
    struct TreeNode* new = malloc(sizeof(struct TreeNode));
    char buf[2] = {temp, '\0'};
    new->val = atoi(buf);
    new->left = helper(Q);
    new->right = helper(Q);
    return new;
}

修改后,序列化结果会包含空节点标记(如原树的序列化结果为12##34##),反序列化能准确还原原树结构,同时彻底解决内存越界问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 11:07:03