Record09—指针作函数参数的技术推演

 

目录

间接赋值(<*p>是指针存在的最大意义)

1级指针的间接赋值推演

从1级指针到2级指针的间接赋值推演

间接赋值的工程应用

间接赋值存在的条件(需牢记)

间接赋值的应用场景

间接赋值的推论

总体代码


间接赋值(<*p>是指针存在的最大意义)

1级指针的间接赋值推演

如下是一个在主函数main中,通过*p间接改变变量a的值(将原理的10改成30,再将30改成40),思路很简单,不再赘述。

//1级指针的技术推演
void main32()
{
	int a = 10;  //条件1  定义了两个变量(实参 另外一个变量是形参p)
	int *p = NULL;

	//修改a的值
	a = 20; //直接修改

	p = &a;  //条件2 建立关联

	*p = 30; //p的值是a的地址 *就像一把钥匙 通过地址 找到一块内存空间 求间接的修改了a的值
	printf("a: %d \n", a);

	{
		*p = 40;  //  p的值是a的地址 *a的地址间接修改a的值  //条件3 *p
		printf("a: %d \n", a);
	}

	printf("hello...\n");
	system("pause");
	return ;
}

接着进行进一步推演,如果把 

		*p = 40;  //  p的值是a的地址 *a的地址间接修改a的值  //条件3 *p

 给单独置成一个函数,放在主函数外面,也可以达到同样的效果吗?于是,将其封装成一个函数,

int  getFileLen(int *p)
{
	*p = 41;  //  p的值是a的地址 *a的地址间接修改a的值 
	//在被调用函数里面 通过形参 去 间接的修改 实参的值...
}

再在主函数中调用,

	getFileLen(&a); //建立关联: 把实参取地址 传递给 形参
	printf("getFileLen后 a: %d \n", a);

实现的功能和原来一样。 那么重要的来了:通过被调用函数去间接的修改了a的值,即我们可以通过一个函数把运算结果给甩出来,这正是一个很重要的功能。通过形参去间接的修改实参的值。这个正是通过指针来进行程序内存调用的强大优势,在不添加多余内存空间的同时,可以通过外部函数形参改变主函数中的值,既节省空间,有便捷高效。

那么,如果不用指针做函数参数,直接通过间接赋值的方式,可不可以呢?同样,也在主函数外面设置一个子函数getFileLen3。来进行值对值的间接修改。

//形参的属性
int  getFileLen3(int b)
{
	b = 100;//  p的值是a的地址 *a的地址间接修改a的值
}

在主函数中进行调用,

	getFileLen3(a);
	printf("getFileLen3后 a: %d \n", a);

 答案是否定的,通过子函数getFileLen3这样的方法,是修改不了原函数内容的。因为在子函数getFileLen3运行结束的同时,它的所有值也都给析构了,根本不会对原函数造成任何的影响。(详情请见Record02部分记述)

从1级指针到2级指针的间接赋值推演

先来个2级指针看看,

void main33()
{
	char *p1 = NULL;

	char **p2 = NULL;

	p1 = 0x11;
	p2 = 0x22;

	//直接修改p1的值
	p1 = 0x111;

	//间接修改p1的值
	p2 = &p1; 

	*p2 = 100; //间接赋值  p2是p1的地址

	printf("p1:%d \n", p1);

	{
		*p2 = 200; //间接赋值  p2是p1的地址
		printf("p1:%d \n", p1);
	}

	printf("p1:%d \n", p1);
	system("pause");
	return ;
}

 需要说的是,p1是一个1级指针,p2是一个2级指针,p2放的是p1的地址,换句话说,p2是p1的指针。运行出来之后,

这说明2级指针很容易的把1级指针给修改了。那么,下面还是把2级指针间接修改的部分给提出到主函数外面去,变成一个子函数,

void getMem(char **p2)
{
	*p2 = 400; //间接赋值  p2是p1的地址
}

再在主函数中进行调用,

	getMem(&p1);
	printf("p1:%d \n", p1);

 运行显示,的确修改了值,

2级指针在被调用函数里面,去间接的修改1级指针的值。 需要注意的是给被调用函数传参的时候,传的是1级指针的地址,需要用取地址符(&p1),在被调用函数的形参头上,应该是"char **p2"双星号才对。那么为啥单星号不行呢?那么改一下试试,

void getMem2(char *p2)
{
	p2 = 800; //间接赋值,改变指针指向内存地址为800的地方,并且,随着被调用函数运行结束后,析构
        //所有被调用函数中的内容都将被擦除。 
}

 在主函数中进行调用,

	getMem2(p1);
	printf("p1:%d \n", p1);

答案肯定是不行的,原理和之前的调用值来间接改变值是一样的,因为在getMem2结束运行后,其所有内容就析构了,于主函数中的值来说,没有任何改变。(详情请见Record02部分记述)。故,要想修改p1的值,只有把p1的地址,扔给被调用函数来进行修改!只把变量本身扔给被调用函数,相当于改变指针指向的内存,并不是改变指针指向内存空间的值。

间接赋值的工程应用

下面是一个用1、2级指针来间接赋值的案例,

int  getMem3(char **myp1, int *mylen1,  char **myp2, int *mylen2)
{
	int		ret = 0;
	char	*tmp1, *tmp2;

	tmp1 = (char *)malloc(100);
	strcpy(tmp1, "1132233");

	//间接赋值 
	*mylen1 = strlen(tmp1);  //1级指针
	*myp1 = tmp1; //2级指针的间接赋值

	tmp2 = (char *)malloc(200);
	strcpy(tmp2, "aaaaavbdddddddd");

	*mylen2 = strlen(tmp2);  //1级指针
	*myp2 = tmp2; //2级指针的间接赋值

	return ret;
}

int  main35()
{
	int		ret = 0;
	char	*p1 = NULL;
	int		len1 = 0;
	char	*p2 = NULL;
	int		len2 = 0; 

	ret = getMem3(&p1, &len1, &p2, &len2);
	if (ret != 0)
	{
		printf("func getMem3() err:%d \n", ret);
		return ret;
	}
	printf("p1:%s \n", p1);
	printf("p2:%s \n", p2);
	if (p1 != NULL)
	{
		free(p1);
		p1 = NULL;
	}
	if (p2 != NULL)
	{
		free(p2);
		p2 = NULL;
	}


	printf("p1:%d \n", p1);
	system("pause");
	return ret;
}

一个main函数可以配套很多子函数,而这种通过指针作函数参数,实现了间接赋值,实现了模块之间的一个分层和联合。如果没有这种间接赋值的方法,就不可能有函数之间的分层;没有分层就不可能有函数之间的接口和封装的设计;没有封装和设计,就不可能有功能和功能之间的划分。没有软件之间功能与功能之间的划分,就不可能有软件信息系统;没有软件信息系统,就没有程序员了!

C语言精华:通过指针作函数参数,使不同的函数可以同时操作一块儿内存空间。通过不同的首地址把内存空间给传过去,同时,把运算结果在多个函数中进行运算和分解,精华莫过如此。

间接赋值存在的条件(需牢记)

一个函数内:

条件1,定义两个变量

条件2,建立关联

条件3,通过*p,找到一个地址,去间接的修改这个地址内的值

多个函数之间:

条件1,定义两个变量,一个是实参,另一个是形参

条件2,建立关联,把实参取地址扔给形参

条件3,被调用函数里面,通过形参去间接的修改实参的值

间接赋值的应用场景

以上的三个条件,不同组合,变成不同的应用场景。下面的代码是举1,2,3在同一个函数里面的例子,

//间接赋值的应用场景
void main37()
{
	//1 2 3 这3个条件 写在同一个函数里面
	//12 写在一块   3 单独写在另外一个函数里面  =====>函数调用
	//1         23写在一块 ===>抛砖 ====C++会有,到时候,你别不认识......
	char from[128];
	char to[128] = {0};
	char *p1 = from;
	char *p2 = to;

	strcpy(from, "1122233133332fafdsafas");

	while (*p1 != '\0')
	{
		*p2 = *p1;
		p2 ++;
		p1++;
	}

	printf("to:%s \n", to);
	
	system("pause");
	return ;

}

 运行结果如下:

间接赋值的推论

 在函数调用的时候,

用1级指针形参,去间接修改0级指针(实参)的值。

用2级指针形参,去间接修改1级指针(实参)的值。

用3级指针形参,去间接修改2级指针(实参)的值。

用n级指针形参,去间接修改n-1级指针(实参)的值。

总体代码

dm03_间接赋值的技术推演.c



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


//return 只能返回一个结果
//
int  getFileLen2()
{
	int a = 100;  
	return a;
}


int  getFileLen(int *p)
{
	*p = 41;  //  p的值是a的地址 *a的地址间接修改a的值 
	//在被调用函数里面 通过形参 去 间接的修改 实参的值...
}

//形参的属性
int  getFileLen3(int b)
{
	int  i = 0;
	b = 100;//  p的值是a的地址 *a的地址间接修改a的值
}


//1级指针的技术推演
void main32()
{
	int a = 10;  //条件1  定义了两个变量(实参 另外一个变量是形参p)
	int *p = NULL;

	//修改a的值
	a = 20; //直接修改

	p = &a;  //条件2 建立关联

	*p = 30; //p的值是a的地址 *就像一把钥匙 通过地址 找到一块内存空间 求间接的修改了a的值
	printf("a: %d \n", a);

	{
		*p = 40;  //  p的值是a的地址 *a的地址间接修改a的值  //条件3 *p
		printf("a: %d \n", a);
	}

	getFileLen(&a); //建立关联: 把实参取地址 传递给 形参
	printf("getFileLen后 a: %d \n", a);
	getFileLen3(a);
	printf("getFileLen3后 a: %d \n", a);


	printf("hello...\n");
	system("pause");
	return ;
}

void getMem(char **p2)
{
	*p2 = 400; //间接赋值  p2是p1的地址
}

void getMem2(char *p2)
{
	p2 = 800; //间接赋值  p2是p1的地址
}

void main33()
{
	char *p1 = NULL;

	char **p2 = NULL;

	p1 = 0x11;
	p2 = 0x22;

	//直接修改p1的值

	p1 = 0x111;

	//间接修改p1的值
	p2 = &p1; 

	*p2 = 100; //间接赋值  p2是p1的地址

	printf("p1:%d \n", p1);

	{
		*p2 = 200; //间接赋值  p2是p1的地址
		printf("p1:%d \n", p1);
	}

	getMem(&p1);

	getMem2(p1);

	printf("p1:%d \n", p1);



	system("pause");
	return ;
}


int  getMem3(char **myp1, int *mylen1,  char **myp2, int *mylen2)
{
	int		ret = 0;
	char	*tmp1, *tmp2;

	tmp1 = (char *)malloc(100);
	strcpy(tmp1, "1132233");

	//间接赋值 
	*mylen1 = strlen(tmp1);  //1级指针
	*myp1 = tmp1; //2级指针的间接赋值

	tmp2 = (char *)malloc(200);
	strcpy(tmp2, "aaaaavbdddddddd");

	*mylen2 = strlen(tmp2);  //1级指针
	*myp2 = tmp2; //2级指针的间接赋值


	return ret;
}

int  main35()
{
	int		ret = 0;
	char	*p1 = NULL;
	int		len1 = 0;
	char	*p2 = NULL;
	int		len2 = 0; 

	ret = getMem3(&p1, &len1, &p2, &len2);
	if (ret != 0)
	{
		printf("func getMem3() err:%d \n", ret);
		return ret;
	}
	printf("p1:%s \n", p1);
	printf("p2:%s \n", p2);
	if (p1 != NULL)
	{
		free(p1);
		p1 = NULL;
	}
	if (p2 != NULL)
	{
		free(p2);
		p2 = NULL;
	}


	printf("p1:%d \n", p1);
	system("pause");
	return ret;
}


/* 间接赋值成立的三个条件
	条件1  //定义1个变量(实参) //定义1个变量(形参)
	条件2//建立关联:把实参取地址传给形参
	条件3://*形参去间接地的修改了实参的值。
	*/

//间接赋值的应用场景
void main37()
{
	//1 2 3 这3个条件 写在有一个函数
	//12 写在一块   3 单独写在另外一个函数里面  =====>函数调用
	//1         23写在一块 ===>抛砖 ====C++会有,到时候,你别不认识......
	char from[128];
	char to[128] = {0};
	char *p1 = from;
	char *p2 = to;

	strcpy(from, "1122233133332fafdsafas");

	while (*p1 != '\0')
	{
		*p2 = *p1;
		p2 ++;
		p1++;
	}

	printf("to:%s \n", to);
	
	system("pause");
	return ;

}

 

发布了140 篇原创文章 · 获赞 6 · 访问量 4877

猜你喜欢

转载自blog.csdn.net/qq_17846375/article/details/103660713
今日推荐