结构体char指针在void函数赋值后main函数打印出现乱码
问题描述
我用typedef定义了名为Node的结构体,其中key成员是char类型指针,用于动态赋值。头文件cnode.h代码如下:
#include <stdio.h> typedef struct Node { char *key; int value; Node *next = NULL; } Node; void print_node(Node x){ printf("[%s, %d]\n",x.key, x.value); } void print_list(Node head){ printf("\n"); while (head.next !=NULL){ print_node(head); head = *head.next; printf("-->"); } print_node(head); }
我将Node声明为set[CAPACITY]数组,试图实现近似O(1)访问的集合结构,通过哈希函数计算插入位置,在外部void insert()函数中完成插入操作。为验证正确性,我在insert()和main()函数中均打印key值,但结果不一致。主程序代码如下:
#include <stdio.h> #include "cnode.h" #define CAPACITY 50 unsigned long hash_function(int x) { unsigned long i; i = x*(x+3)+x; //Knuth Variant on Division return i % CAPACITY; } void insert(Node *set, int value){ char key[20]; sprintf(key, "%d", value); int loc = hash_function(value); set[loc].key = key; set[loc].value = value; print_node(set[loc]); } int main(){ Node set[CAPACITY]; insert(set, 18); insert(set, 122); printf("\nVALIDATION\n"); print_node(set[46]); print_node(set[22]); }
使用g++编译命令:
g++ -o main main.c && ./main
输出结果:
[18, 18] [122, 122] VALIDATION [�7�H�, 18] [�7�H�, 122]
尝试了多种指针和地址操作仍无法解决乱码问题,请问忽略了什么?
问题原因与解决方案
核心问题:栈内存的生命周期
你在insert()函数中定义的char key[20]是栈上的局部数组,函数执行完毕后,当前函数的栈帧会被销毁,这块内存会被操作系统回收或重新分配给其他操作使用。当你把key的地址赋值给set[loc].key时,这个指针在insert()函数内是有效的(因为函数还在执行),所以打印正常;但回到main()函数后,这个指针指向的内存已经无效,访问它就会读取到随机的垃圾数据,也就是你看到的乱码。
解决方案:使用动态分配的堆内存
要解决这个问题,需要为key分配堆内存,堆内存的生命周期不受函数栈帧影响,直到你主动释放它。修改insert()函数如下:
#include <stdlib.h> // 需要引入stdlib.h来使用malloc和free void insert(Node *set, int value){ char *key = malloc(20 * sizeof(char)); // 动态分配20字节的内存 if (key == NULL) { // 检查内存分配是否成功 perror("malloc failed"); return; } sprintf(key, "%d", value); int loc = hash_function(value); // 如果该位置之前已经有key,先释放旧内存避免泄漏 if (set[loc].key != NULL) { free(set[loc].key); } set[loc].key = key; set[loc].value = value; print_node(set[loc]); }
额外注意事项
- 内存泄漏:使用
malloc分配的内存需要在不再使用时用free释放,比如程序结束前遍历整个set数组,释放每个非空的key指针。 - 结构体初始化:你的
Node结构体中Node *next = NULL;是C++的写法,纯C语言不支持在结构体定义中直接初始化成员。如果后续要改用C编译器(比如gcc)编译,需要在创建Node实例时手动将next初始化为NULL,比如在main()中可以用循环初始化set数组:int main(){ Node set[CAPACITY]; // 初始化数组中的每个Node for (int i = 0; i < CAPACITY; i++) { set[i].key = NULL; set[i].value = 0; set[i].next = NULL; } // ... 后续代码 }
内容的提问来源于stack exchange,提问作者exiled
相关产品推荐
相关产品推荐

