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

Flex/Yacc项目中AST节点指针莫名变值引发段错误求助

问题:Flex/Yacc AST项目中节点指针莫名篡改导致段错误

我正在做一个基于Flex/Yacc的集合表达式AST计算项目,核心问题出在C代码部分。

我编写的createNode函数用于创建节点:

node_t * createNode(node_content_t nodecontent, int nodetype){
    node_t *newNode = (node_t *) malloc(sizeof(node_t * ));
    if(nodetype == 0){
        newNode->content = (node_content_t)strdup(nodecontent.string);
    }
    else
        newNode->content = nodecontent;
    newNode->type = nodetype;

    newNode->leftChild = NULL;
    newNode->rightChild = NULL;
    printf("Right Child in createNode: %p\n", newNode->rightChild);
    return newNode;
}

如代码所示,左右子节点指针均初始化为NULL,但在函数外部打印rightChild的指针值时,它会莫名变为0x23或0x53这类值,进而导致段错误。

node_t和node_content_t的定义如下:

typedef union{
        char* string;
        char singleletter;
    }node_content_t;


    typedef struct node node_t;
    struct node{
        node_content_t content;
        int type; //0 for string, 1 for char
        node_t *leftChild;
        node_t *rightChild;
    };

我在createNode函数内打印该指针时结果为0x0,但在用于打印整棵树的printNode函数中打印时,值发生了变化:

void printNode(node_t *n, size_t indent) {
    
    char *indentation = malloc(sizeof(char) * indent);
    for (size_t i = 0; i < indent; ++i) {
        indentation[i] = ' ';
    }
    printf("LeftChild: %p\n", n->leftChild);
    printf("RightChild: %p\n", n->rightChild);
    switch (n->type) {
        case 0: printf("%s%s\n", indentation, n->content); break;
        case 1: printf("%s%c\n", indentation, n->content); break;
    }
    if (n->leftChild != NULL){
        printNode(n->leftChild, indent+2);
    }
    if (n->rightChild != NULL){
        printf("RightChild: %p\n", n->rightChild); //there
        printNode(n->rightChild, indent+2);
    }
    printf("Non ci sono figli\n");

}

除了addChild函数外,我没有修改过rightChild的值:

void addChild(node_t *parent, node_t *child) {
    printf("Addchild\n");
    printf("Right Child in createNode: %p\n", parent->rightChild);
    if(parent->leftChild == NULL)
        parent->leftChild = child;
    else if(parent->rightChild == NULL && strcmp(parent->content.string, "co") != 0 ){
        parent-> rightChild = child;
        printf("Aggiunto figlio destro\nContent: %c\nType: %d\n", child->content, child->type);
    }
    else
        printf("Error during child adding\n");
}

解决思路

1. 致命错误:内存分配大小错误

createNode里的malloc(sizeof(node_t *))是核心问题——你只分配了一个指针的内存空间,但node_t是结构体,体积远大于指针。往这个过小的内存块写入结构体成员时,会越界篡改相邻内存,导致后续访问时指针值被意外修改。

修正方法:将sizeof(node_t *)改为sizeof(node_t):

node_t *newNode = (node_t *) malloc(sizeof(node_t));

2. Union赋值与输出的错误

  • 当nodetype == 0时,直接将strdup返回的char*强转为node_content_t赋值是错误的union操作方式,正确做法是给union的指定成员赋值:
    newNode->content.string = strdup(nodecontent.string);
    
  • addChild中打印child->content时,未区分节点类型就用%c输出,当节点是字符串类型时,会把指针首字节当字符输出,属于未定义行为,可能干扰内存数据。需根据type选择输出方式:
    if (child->type == 0) {
        printf("Aggiunto figlio destro\nContent: %s\nType: %d\n", child->content.string, child->type);
    } else {
        printf("Aggiunto figlio destro\nContent: %c\nType: %d\n", child->content.singleletter, child->type);
    }
    

3. printNode函数的内存问题

  • indentation分配sizeof(char)*indent字节后,未添加字符串终止符'\0',使用printf("%s")时会读取垃圾数据甚至越界。需分配indent+1字节,并添加终止符:
    char *indentation = malloc(sizeof(char) * (indent + 1));
    for (size_t i = 0; i < indent; ++i) {
        indentation[i] = ' ';
    }
    indentation[indent] = '\0';
    
  • 用完indentation后需调用free(indentation),避免内存泄漏。

4. 其他潜在优化点

  • 检查所有malloc的返回值,添加内存分配失败的处理逻辑,避免空指针访问。
  • 销毁节点时,若节点类型为0(字符串),需先free(content.string)再释放节点本身,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 12:36:03