C语言字符数组传参疑问:为何可传char*却不可传char**?
为什么字符数组能传给
char*函数,而数组地址不能传给char**函数? 这个问题的核心在于C语言里数组和指针的微妙区别,尤其是数组退化为指针的规则,以及不同指针类型的本质差异。咱们一步步拆解清楚:
1. 为什么foo(str)能正常工作?
当你把数组名str作为参数传递给函数时,C语言会自动触发数组到指针的隐式转换:数组名会被转换成指向数组第一个元素的指针。这里str是char[12]类型的数组,第一个元素是char,所以转换后的指针类型是char*——正好和foo的参数char* qux完全匹配,所以编译器不会报错,函数也能正常打印字符串。
2. 为什么bar(&str)会触发警告?
&str的类型并不是你以为的char**,而是指向整个数组的指针,具体类型是char (*)[12](读作“指向包含12个char的数组的指针”)。而bar的参数是char**(指向char指针的指针),这两个类型完全不兼容:
char**期望接收的是一个char*变量的地址,但&str指向的是一块12字节的连续char内存,根本不是char*类型的变量;- 两者的指针逻辑完全不同:比如对
char**做+1操作,会跳过一个char*的大小(通常4或8字节);而对char (*)[12]做+1,会直接跳过整个12字节的数组。强行传递会导致类型不匹配,编译器必然警告,甚至可能引发未定义行为。
3. 为什么char* qux[12]和char** qux没区别?
你发现把baz的参数写成char* qux[12],编译器警告还是没变?这是C语言的一个特殊规则:在函数的参数列表中,数组类型会自动退化为对应的指针类型。不管你写的数组长度是多少,char* qux[12]都会被编译器直接解析成char** qux——因为函数参数里的数组本质上就是指针,数组长度会被直接忽略。所以baz和bar的参数类型其实完全一样,&str传进去自然还是类型不匹配。
怎么让代码合法?
如果你想传递数组的地址给函数,有两种正确的方式:
方式一:修改函数参数为指向数组的指针
#include <stdio.h> void foo(char* qux) { puts(qux); } // 参数改为指向12个char的数组的指针 void bar(char (*qux)[12]) { puts(*qux); } void baz(char* qux[12]) { puts(*qux); } int main() { char str[12] = "Hello there"; foo(str); bar(&str); // 现在类型完全匹配,无警告 }
方式二:先把数组转成char*变量,再传变量地址
如果你非要用char**类型的参数,可以先把数组退化为char*存在一个变量里,再传递这个变量的地址:
#include <stdio.h> void foo(char* qux) { puts(qux); } void bar(char** qux) { puts(*qux); } void baz(char* qux[12]) { puts(*qux); } int main() { char str[12] = "Hello there"; char* ptr = str; // 数组退化为char*,存入ptr bar(&ptr); // &ptr是char**,和bar的参数匹配 }
内容的提问来源于stack exchange,提问作者sleighty
相关产品推荐
相关产品推荐

