使用函数分配复杂自定义数据结构的问题排查
问题解决:指针地址传递后的内存分配与类型转换
你的代码核心问题是直接对void*类型解引用——C语言不允许操作void类型的对象,因为它没有明确的大小,编译器无法确定如何访问其指向的内存。当你传入&ptr(指针的地址)时,实际传递的是「指针的指针」,需要先将void*转换为对应类型的「指针的指针」,才能正确赋值。
具体修改步骤
- 修正
void*参数的类型转换:
每个void*参数实际对应不同的「指针的指针」类型,处理前必须先强制转换为目标类型,再解引用赋值。 - 修复错误提示的字符串:
第二个printf错误复用了dist_decharge的提示,应改为对应变量名。 - 可选:用具体类型替代
void*提升安全性:
直接使用具体的「指针的指针」类型作为参数,避免强制转换,还能让编译器做类型检查,从根源避免类型错误。
修改后的代码
#include <stdio.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/msg.h> #include <errno.h> // 假设camion_t是已定义的自定义类型 typedef struct { // 自定义字段 } camion_t; // 假设new_matrix是已实现的矩阵分配函数 int** new_matrix(int m); int init_structures(void* d_decharge, void* d_poubelles, void* e_camions, int m, int n, int *tamp_id, int* file_msg_id) { // 处理int数组:将void*转为int**,再解引用赋值 *((int**)d_decharge) = malloc(m * sizeof(int)); if (*((int**)d_decharge) == NULL){ printf("echec malloc dist_decharge\n"); return 1; } // 处理int矩阵:将void*转为int***,再解引用赋值 *((int***)d_poubelles) = new_matrix(m); if(*((int***)d_poubelles) == NULL){ printf("echec malloc dist_poubelles\n"); return 1; } key_t key_tamp = ftok("./src/main.c", 64); int id = shmget(key_tamp, sizeof(camion_t) * n, 0666 | IPC_CREAT); if (id == -1){ printf("echec creation du tampon etats_camions, error[%s]\n", strerror(errno)); return 1; } *tamp_id = id; // 处理共享内存的camion_t数组:将void*转为camion_t**,再解引用赋值 *((camion_t**)e_camions) = shmat(*tamp_id, NULL, 0); key_t key_msg = ftok("./src/main.c", 64); id = msgget(key_msg, 0666 | IPC_CREAT); if(id==-1){ printf("echec creation de la file de messages Faffec, error[%s]\n", strerror(errno)); return 1; } *file_msg_id = id; return 0; }
更安全的替代方案(不用void*)
如果不需要函数的通用性,直接用具体类型作为参数,完全避免强制转换:
int init_structures(int** d_decharge, int*** d_poubelles, camion_t** e_camions, int m, int n, int *tamp_id, int* file_msg_id) { *d_decharge = malloc(m * sizeof(int)); if (*d_decharge == NULL){ printf("echec malloc dist_decharge\n"); return 1; } *d_poubelles = new_matrix(m); if(*d_poubelles == NULL){ printf("echec malloc dist_poubelles\n"); return 1; } // 后续共享内存处理逻辑不变 key_t key_tamp = ftok("./src/main.c", 64); int id = shmget(key_tamp, sizeof(camion_t) * n, 0666 | IPC_CREAT); if (id == -1){ printf("echec creation du tampon etats_camions, error[%s]\n", strerror(errno)); return 1; } *tamp_id = id; *e_camions = shmat(*tamp_id, NULL, 0); key_t key_msg = ftok("./src/main.c", 64); id = msgget(key_msg, 0666 | IPC_CREAT); if(id==-1){ printf("echec creation de la file de messages Faffec, error[%s]\n", strerror(errno)); return 1; } *file_msg_id = id; return 0; }
调用时直接传入指针的地址:
int* dist_decharge = NULL; int** dist_poubelles = NULL; camion_t* etats_camions = NULL; int tamp_id, msg_id; init_structures(&dist_decharge, &dist_poubelles, &etats_camions, m, n, &tamp_id, &msg_id);
关键说明
- 当你传递
&ptr时,传递的是指针本身的地址,函数需要用「指针的指针」类型接收,才能修改原指针的值(这不是值传递问题,而是之前用错了参数类型)。 void*是通用指针,但只能用来存储地址,不能直接解引用或做算术运算,必须转换为具体类型后才能操作。
内容的提问来源于stack exchange,提问作者Megrah Yacine
相关产品推荐
相关产品推荐

