C语言中strcmp函数传入一维与二维字符数组的差异解析
问题描述
在C语言中使用<string.h>库的strcmp函数时,遇到了传参的疑问:
- 传入二维字符数组作为比较参数时,若直接写
mainlist[i][0]会触发警告:warning: passing argument 1 of 'strcmp' makes pointer from integer without a cast [-Wint-conversion],而用&mainlist[i][0]的写法则正常; - 但传入一维字符数组作为比较参数时,仅需写数组名(比如
mainlist[i]或myname)即可,无需添加取地址符。
想知道造成这种差异的原因是什么?
代码示例
#include <stdio.h> #include <string.h> #define FOUND 1 #define NOT 0 int main() { char mainlist[5][10] = {"test1", "test2", "test3", "test4", "test5"}; int flag, i; flag = NOT; char myname[50]; printf("Enter ur name.\n"); scanf("%s", myname); for(i = 0; i < 5; i++) { if(strcmp(mainlist[i], myname)== 0) // 对比写法:if(strcmp(&mainlist[i][0], myname)==0) { flag = FOUND; printf("Your name was found welcome.\n"); break; } } if(flag == NOT) { printf("Your name was not found .\n"); } }
原因解释
首先要明确:strcmp函数的两个参数都要求是指向char的指针(const char*),它需要从指针指向的地址开始,逐字节比较字符串直到遇到终止符'\0'。
1. 二维数组的mainlist[i]为何合法?
mainlist是char[5][10]类型的二维数组,mainlist[i]代表数组中第i个一维子数组(类型为char[10])。在C语言的规则中,一维数组名在绝大多数场景下会自动隐式转换为指向数组首元素的指针,所以mainlist[i]会直接转换成char*类型,指向该子数组的第一个元素(也就是mainlist[i][0]的地址),完全符合strcmp的参数要求。
2. mainlist[i][0]为何触发警告?
mainlist[i][0]是二维数组中第i个子数组的第一个字符元素,它的类型是char(本质是一个整数,对应字符的ASCII值)。把一个整数直接传给需要指针的strcmp,编译器会尝试将这个整数强制转为指针地址,这既不符合逻辑也存在风险,因此会抛出“将整数转换为指针”的警告,这种写法是错误的。
3. &mainlist[i][0]与mainlist[i]的关系
&mainlist[i][0]是显式获取第i个子数组首元素的地址,它的类型是char*,和mainlist[i]隐式转换后的指针完全等价,两种写法都能正常被strcmp接受。
4. 一维数组的传参逻辑
对于一维字符数组(比如示例中的myname),数组名同样会自动转换为指向首元素的char*指针,因此直接传数组名就符合strcmp的参数要求,不需要额外加取地址符。如果错误地传入myname[0],同样会触发和mainlist[i][0]一样的警告。
总结
- 无论是二维数组的子数组名
mainlist[i],还是一维数组名myname,本质都是数组名,会自动转为指向首元素的指针,符合strcmp的参数要求; mainlist[i][0]是单个字符(整数),并非指针,传给strcmp会触发错误警告;&mainlist[i][0]是显式取首元素地址,和mainlist[i]是等价的合法写法。
内容的提问来源于stack exchange,提问作者Steve Bob

