C语言结构体数组指针传递疑问:回调函数调用为何一成功一失败?
问题分析与解答
核心问题出在数组名的地址与指针变量的地址类型完全不同——即使二者的数值地址相同,类型差异会导致后续解引用行为完全错误。
1. 两种传递方式的类型差异
- 情况1:
char* pString = &pCtrl->buffer[0];中,pString是char*类型的指针变量,&pString的类型是char**。将其转为void**传入回调后,若回调将void**转回char**并解引用,得到的是pString存储的buffer[0]地址,这正是正确的字符串首地址,因此能正常打印。 - 情况2:
&pCtrl->buffer的类型是char(*)[5](指向长度为5的char数组的指针),而非char**。虽然它的数值地址和buffer[0]的地址相同,但类型本质不同。当强行将其转为void**传入回调,回调若把它当作char**解引用,会尝试读取该地址开始的4/8字节(取决于系统指针宽度)作为char*指针——但数组里存储的是't' 'e' 's' 't' '\0',这些字节被解析成指针后是无效地址,自然无法打印正确字符串。
2. 内存布局对比
假设pCtrl->buffer的首地址是0x1000:
- 情况1中,
pString变量可能存在于0x2000地址,它的值是0x1000。&pString是0x2000,回调解引用后得到0x1000,指向字符串。 - 情况2中,
&pCtrl->buffer就是0x1000,回调把它当作char**解引用时,会读取0x1000开始的字节(即't' 'e' 's' 't'),将其解析成指针(比如小端系统下是0x74736574),这显然是无效内存地址,访问后要么打印乱码要么直接崩溃。
3. 修复方案
- 方案一:保持情况1的写法,用临时
char*变量过渡,确保传递的是char**类型的地址。 - 方案二:如果必须直接传递数组相关的地址,需在回调函数中正确处理数组指针类型。比如回调参数改为
void*,再在回调内转回数组指针类型:void callback(void* arg) { char (*buf_ptr)[5] = (char (*)[5])arg; printf("%s\n", *buf_ptr); // *buf_ptr等价于数组首元素地址 } // 调用时传递:(void*)&pCtrl->buffer - 方案三:如果回调只需要字符串首地址,直接传递
(void*)pCtrl->buffer即可(前提是回调参数支持void*类型,而非void**)。
内容的提问来源于stack exchange,提问作者DaRaRa
相关产品推荐
相关产品推荐

