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
相关产品推荐
相关产品推荐

