C 函数参数 char **s与char *s[]
本文同时发表在https://github.com/zhangyachen/zhangyachen.github.io/issues/126
先来看一个小例子 : 编写函数遍历一个整型数组的元素,数组最后一个元素为-1标志数组的结束。
#include <stdio.h>
void test(int *a){
int x;
while((x = *a++) != -1) {
printf("%d\n",x);
}
}
int main(void) {
int arr[] = {1,2,3,4,5,6,-1};
test(arr);
return 0;
}

原理是在函数参数为数组名时,实际传递的是该数组第一个元素的地址,通过*a++即可遍历该数组。实际上*a++分三步:
- 产生一个a的拷贝
- 对a地址进行++操作,编译器发现a地址存储的是整型数据,所以a++指向a之后的sizeof(int)个字节,即数组下一个元素
- 对a的拷贝进行间接访问,即取出a的拷贝指向的数据。
下面对题目进行一下升级 : 编写函数遍历一个指针数组的元素,数组最后一个元素为NULL标志数组的结束。
#include <stdio.h>
void test_char(char *s){
char *string = NULL;
while((string = *s++) != NULL){
printf("%s\n",string);
}
}
int main(void) {
char *s[] = {"hello","world","ni","hao",NULL};
test_char(s);
return 0;
}
一运行代码,卧槽崩溃了。什么鬼。表面看起来很对啊,将数组首地址传递到函数内部,然后取出每个元素存储的字符串常量地址,再输出字符串。

盯着代码看了10分钟左右我才发现错误 : 虽然传递给函数的是数组第一个元素的地址,即0x000(为方便起见做的假设)。但是由于函数形参是char *类型,所以*s操作取得是0x000-0x001之间的数据赋值给char * string,而不是数组元素里的内容,由于这不是字符串常量的首地址,所以printf("%s\n",string);就报错了。而且还有一点是s++也不是指向数组的第二个元素。因为数组是指针数组,存放的是字符串常量的首地址,每个数组元素是8字节(32位机器4字节)。而s是char *类型,s++的结果也只是0x001。
有什么办法让s++指向数组下一个元素,并且*s取出来的是数组元素的内容?其实将函数参数s声明为char **即可。因为编译器发现指针s存储的地址指向的是char *类型,8字节,所以*s取出来的是s存储的地址 - s存储的地址+8字节之间的内容。(后来想想第一个例子函数形参为int *a,需要一次取址取到数据。第二个例子为指针数组,需要两次取址取到数据,函数形参自然就是char **,当然这都是马后炮了)。

#include <stdio.h>
void test_char(char **s){
char *string = NULL;
while((string = *s++) != NULL){
printf("%s\n",string);
}
}
int main(void) {
char *s[] = {"hello","world","ni","hao",NULL};
test_char(s);
return 0;
}
函数形参也可以声明为char *s[],相似的还有函数形参为int a[]与int *a是等价的。
工作一年了还犯这种低级错误,真是有点羞愧啊。
C 函数参数 char **s与char *s[]的更多相关文章
- char *与const char **函数参数传参问题
传参方法 ## 函数 extern void f2 ( const char ** ccc ); const char ch = 'X'; char * ch_ptr; const char ** c ...
- C++ Error C2664:无法将参数 1 从“const char [9]”转换为“LPCWSTR”解决方案
问题出现 编译平台:VS2013 Windows 出现地方:在使用LoadLibrary( )函数动态链接DLL文件时出现的一个问题 Eg. 在使用 UNICODE字符的工程中, HIN ...
- 不能将参数1从“const char []”转换为“LPCTSTR
今天在使用vs2008+MFC时候,使用editControl的replacesel(“”)发生报错.如下::不能将参数1从“const char []”转换为“LPCTSTR” 其解决方案就是, 在 ...
- error C2664: “CWnd::MessageBoxW”: 不能将参数 1 从“const char [17]”转换为“LPCTSTR”
vs2008提示 error C2664: “CWnd::MessageBoxW”: 不能将参数 1 从“const char [17]”转换为“LPCTSTR” 在外面用vs2005编写mfc程序的 ...
- [转载] 已知strcpy的函数原型:char *strcpy(char *strDest, const char *strSrc),编写函数 strcpy(C++版)
已知strcpy的函数原型:char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串,strSrc 是源字符串.不调用C++/C ...
- VS2010 error C2664: “CWnd::MessageBoxW”: 不能将参数 1 从“const char [3]”转换为“LPCTSTR”
VS2010 (VC2010)建立工程时默认的字符集是Unicode,所以在代码中使用MessageBox时需要输入Unicode,用TEXT()这个宏输入参数,否则会报错: 代码:Message ...
- list排序成员函数对string对象与char*对象排序的差别
对list容器中的对象排序,不能使用sort()算法,只能采用其自身的排序函数sort().因为,算法sort()只支持随机存取的容器的排序,如vector等. 对基本数据对象list排序:成员函数s ...
- error: C2664: “zajiao::zajiao(const zajiao &)”: 无法将参数 1 从“const char [12]”转换为“char *”
原本打算在QT用一个字符串"ABCDEF12345"作为类zajiao的构造函数的参数,用来创建类zajiao的对象zajiao1. zajiao zajiao1("AB ...
- 给定一个字符串,把字符串内的字母转换成该字母的下一个字母,a换成b,z换成a,Z换成A,如aBf转换成bCg, 字符串内的其他字符不改变,给定函数,编写函数 void Stringchang(const char*input,char*output)其中input是输入字符串,output是输出字符串
import java.util.Scanner; /*** * 1. 给定一个字符串,把字符串内的字母转换成该字母的下一个字母,a换成b,z换成a,Z换成A,如aBf转换成bCg, 字符串内的其他字 ...
随机推荐
- 《java.util.concurrent 包源码阅读》24 Fork/Join框架之Work-Stealing
仔细看了Doug Lea的那篇文章:A Java Fork/Join Framework 中关于Work-Stealing的部分,下面列出该算法的要点(基本是原文的翻译): 1. 每个Worker线程 ...
- 常用IO按位操作
PORTD |= (1 << op) //位置高PORTD &= ~(1 << op) //位置低PORTD ^= (1 < ...
- JavaSE学习入门
Java基础: 1.安装JDK1.7(JDK 包括JRE,Java工具包,Java的类库) 2.编写Hello,world 程序 public class Hello{ public static v ...
- shell,bash,zsh,console,terminal到底是什么意思,它们之间又是什么关系?
原文链接 终端(terminal,或者叫物理终端):是一种设备,不是一个程序,一般说的就是能提供命令行用户界面的设备,典型的是屏幕和键盘,或其他的一些物理终端.虚拟终端:屏幕和键盘只是一个终端,可能不 ...
- 翻译连载 | 附录 C:函数式编程函数库-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...
- 白话图解HTTPS原理
[前言]最近看过几篇文章,内容是关于"全民HTTPS"的.为什么HTTPS,突然会受到如此多业内人士的青睐呢?HTTPS究竟是什么呢?它与HTTP又有怎样的区别呢? 带着这 ...
- webMagic解析淘宝cookie 提示Invalid cookie header
webMagic解析淘宝cookie 提示Invalid cookie header 在使用webMagic框架做爬虫爬取淘宝极又家页面时候一直提醒cookie设置不可用如下图 淘宝的验证特别严重,c ...
- OI大佬博客集
郭家宝:byvoid 早年大牛,题解更新到2014年,其博客内容非常丰富,不止题解 hzwer:hzwer 从OI到ACM,一直在更新 陈立杰:WJMZBMR 无需解释,不过貌似只更到2015 顾森 ...
- 【HNOI2002】营业额统计
https://www.luogu.org/problem/show?pid=2234 用Treap维护,每次查询这个数的前驱与后继哪个和它差值更小. 由于查询一个数时在Treap走出的路径必定经过它 ...
- windows 怎样查看port占用情况
開始--执行--cmd 进入命令提示符 输入netstat -ano 就可以看到全部连接的PID 之后在任务管理器中找到这个PID所相应的程序假设任务管理器中没有PID这一项,能够在任务管理器中选&q ...