C语言解析S-expression时结构体内部void*指针转换与打印问题
核心问题
你的故障和void*语法本身无关,主要存在三类错误:
- 非法引用栈内存:函数内定义的局部变量(
temp数组、tmp整型)都存在栈空间,函数执行结束后栈会被回收,你直接把这些局部变量的地址赋值给blob,后续访问这些地址属于未定义行为,是乱码、无输出的核心原因 - 打印函数逻辑错误:
switch分支没有加break,匹配后会顺序执行后续所有分支代码;同时格式化符和传入参数类型不匹配,void*需要先转换为对应类型的指针再解引用才能正常取值 - 内存操作逻辑错误:字符串解析分支中你给
current->blob申请了堆内存后,又直接把栈地址赋值给blob,既造成内存泄漏,又回到了栈引用的问题,没有做实际的字符串拷贝
修复代码
修正parse_term函数
atom* parse_term(char* str) { atom* current = malloc(sizeof(atom)); // 初始化避免野指针 current->blob = NULL; current->type = -1; if(str[0] == '\'') { // letter类型存储单个字符,需要在堆上申请char大小的空间 char* letter_val = malloc(sizeof(char)); *letter_val = str[1]; current->blob = letter_val; current->type = letter; } else if(str[0] == '"') { char temp[256] = {0}; int pos = 0; int str_pos = 1; while(str[str_pos] != '"' && str_pos < 255) { temp[pos++] = str[str_pos++]; } // 申请对应长度的堆内存,+1给字符串结束符 char* str_val = malloc((pos + 1) * sizeof(char)); strcpy(str_val, temp); current->blob = str_val; current->type = string; } else if(isdigit(str[0])){ char temp[256] = {0}; int pos = 0; while(str[pos] != ' ' && str[pos] != '\0' && pos < 255) { temp[pos++] = str[pos]; } // 整型单独申请堆空间存值 int* int_val = malloc(sizeof(int)); *int_val = atoi(temp); current->blob = int_val; current->type = integer; } return current; }
修正print_atom函数
void print_atom(atom* current) { if(current == NULL || current->blob == NULL) return; switch(current->type) { case string: printf("atom: %s\ttype: %d\n", (char*)current->blob, current->type); break; case letter: printf("atom: %c\ttype: %d\n", *(char*)current->blob, current->type); break; case integer: printf("atom: %d\ttype: %d\n", *(int*)current->blob, current->type); break; default: printf("unknown atom type\n"); } }
可选优化方案
你提到的在结构体中单独定义所有类型变量确实会浪费空间,更推荐用C语言的联合体实现,既节省空间,也比void*更安全,不需要手动处理内存类型对应关系,示例定义如下:
typedef struct { union { char letter_val; int int_val; char* str_val; } value; atom_type type; } atom;
内容的提问来源于stack exchange,提问作者Bithov Vinu
相关产品推荐
相关产品推荐

