二级指针的作为函数形参的深入理解

    在上一篇文章《C函数的“传值调用”和“传址调用”的深入分析》我们分析了函数参数的使用,对于一级指针,理解起来相对容易,而二级指针参数的理解相对难一些,我们先说一下二级指针作为函数形参的目的。

   二级指针作为形参,往往是为了获取一个特定“地址”,没错,就是想要通过形参获取地址。这里可能会有些疑问,如果想要获取地址,那么直接将函数 返回值设定为指针型就可以啊,这 当然是可以的,但是还有一种 情况,比如我们想要获取多个特定地址,这个时候就需要使用二级指针了,比如我们想要我们想要从一串字符串中查找指定字符串,返回查找的字符串位置指针,同时在形参中也要返回(这么绕的目的是为了方便理解,)我们先给出错误的程序代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef unsigned char u8;

/*----------  错误的使用案例!!!   -----------------*/
u8 *func(u8 *src,u8 *cstr, u8 *str)
{
	printf("before call str:%d\n", str);
	str = strstr(src, cstr);
	printf("end call str:%d\n", str);
	return strstr(src, cstr);
}


int main(int argc, char *argv[]) {
	
	u8 *src = "abcdefg123ef";
	u8 *cstr = "cde";
	u8 *str1 = NULL;
	u8 *str2 = NULL ;
	
	str1 = func(src, cstr, str2);
	
	printf("str1:%s\n", str1);
	
	printf("str2:%s\n", str2);
	
	return 0;
}

程序执行结果如下:

before call str:0
end call str:4210727
str1:cdefg123ef
str2:(null)

  我们来分析下,这个错误的使用案例, func函数调用strstr库函数函数,返回值作为函数返回值,这样使用时没有问题的,但是如果我们将strstr的返回值赋值给str,那么就有问题了,原因如下:

   调用func时,对于一级指针str,会进行“传址调用”,也就是我们会拷贝一个一模一样的数值到func中,而且本质上,指针 并不是什么特殊的东西,它也只是一个普通的变量,只不过这个变量里的内容是地址,这就相当于我们给一个拷贝后的值赋值一样,对原变量是没有任何改变的,所以我们在调用后,作为形参的str,内容并没有什么改变,当然如果想要改变,只需要对指针进行间接引用即可,为什么 间接引用可以呢?因为间接引用是通过拷贝的地址,读写地址指向的内容。

    那么如何正确实现开头想要的目的呢?答案是,使用二级指针,正确的代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef unsigned char u8;


u8 *func(u8 *src,u8 *cstr, u8 **str)
{
	printf("end call *str:%d\n", *str);
	*str = strstr(src, cstr);
	printf("end call *str:%d\n", *str);
	return strstr(src, cstr);
}


int main(int argc, char *argv[]) {
	
	u8 *src = "abcdefg123ef";
	u8 *cstr = "cde";
	u8 *str1 = NULL;
	u8 *str2 = NULL ;
	
	printf("src addr:%d\n", src);
	
	str1 = func(src, cstr, &str2);
	
	

	
	printf("str1:%s\n", str1);
	
	printf("str2:%s\n", str2);
	
	return 0;
}

 程序运行结果:

src addr:4210706
end call *str:0
end call *str:4210708
str1:cdefg123ef
str2:cdefg123ef

   为什么使用二级指针就可以正确实现呢? 我们知道,一级指针 存放的是变量的地址,而二级指针存放的是一级指针的地址,而不管是几级指针,函数的调用,都是“传址调用”,所以假如形参是二级指针, 我们传入是二级指针的拷贝值,而二级指针的值是一级指针的地址,所以在上面的函数中,我在调用func函数时,一定是传入一级指针的地址,这是个巧妙的地方,不要直接定义一个二级指针,而是定义一级指针,传入一级指针的地址。

   然后我们在函数内部,就可以对这个二级指针进行赋值,赋值为一个地址,这就相当于间接操作,我们不要直接给一级指针赋值,而是通过这个一级指针的地址间接给这个 一级指针赋值,这样很显然是合理巧妙的。

   所以,归根结底,要特别留意,不要忽略掉函数引用的“传值调用” 和“传址调用”的前提。也 就是拷贝而非直接使用。

发布了247 篇原创文章 · 获赞 257 · 访问量 62万+

猜你喜欢

转载自blog.csdn.net/u012351051/article/details/96026652