C语言 如何在函数中使用指针?

文章目录


读者,你好!
如果你精通C,希望得到你的斧正;如果你是初学者,希望对你有所帮助!
加粗的是我认为比较重要的内容
#一、指针变量做函数参数
##1、列子引出
先用一个列子来说明,何为指针,指针在函数中是什么身份。

  • 比如下课后,两位同学拿错了作业本,老师告诉了班长两位同学的宿号,让班长去换回作业本。

列子中,老师就是main函数,而班长是swap函数,两位同学的宿舍号就是swap函数的形参,老师告诉班长同学宿舍号就是参数传递的过程。
##2、源码实现

/*this programmer is used to compear 2 double num, and output which is max and which is min*/
#include 
int main()
{
	void swap(double *p1, double *p2);
	double a = 0, b = 0, *p1 = &a, *p2 = &b;
	
	scanf("%lf%lf", &a, &b);
	if(*p1 < *p2)//也可以写为if(a < b){  swap(&a, &b);}
	{
		swap(p1, p2);	
	}	
	printf("max = %lf\nmin = %lf\n", *p1, *p2);
	return 0;
} 
 
void swap(double *p1, double *p2)  //形参p1,p2是指针变量
{
	double temp;
	
	temp = *p1;//通过指针访问了main空间的内容
	*p1 = *p2;//通过指针访问和修改了main空间的内容
	*p2 = temp;//通过指针修改了main空间的内容,并把swap函数的数据temp传回了main
}

运行结果为:
这里写图片描述

代码解析:
swap函数的形参p1,p2前都有* 标识,表明当函数被调用时,p1和p2将被作为swap函数的指针变量(而不是普通变量),p1和p2中只能保存地址,不能保存普通数据。这里形参名为p1和p2,不能说成是*p1*p2。main函数对swap函数的调用语句是swap(p1,p2),这里将p1的值(地址)传给p1,将p2的值(地址)传给p2。
swap函数通过参数p1,p2获得了a,b的地址,在swap函数中,通过这两个地址就可以任意存取a,b这两个变量了,而不论a,b这两个参数位于哪个函数。

  • 注意,swap函数中不能直接使用变量名a,b来访问main函数中的变量a,b如在swap中写为temp = a;a = b;b = temp; 是不行的。在swap中只能通过地址的方式访问它们。
    ##3、错误分析
    ###①错误类型一
    如将swap函数写为如下形式:
void swap(double *p1, double *p2)
{
	int  *temp;
	
	temp = p1;
	p1 = p2;
	p2 = temp;
}

不能达到预期结果,因为这只交换了p1和p2的值,只是交换了他们的储存空间,没有交换内容,并且本身修改后不能传回实参,即不能传到main函数。
###②错误类型二

void swap(double *p1, double *p2)
{
	double *temp;
	
	*temp = *p1;
	*p1 = *p2;
	*p2 = *temp;
}

上述方式,定义了一个未知空间temp,并且通过指针修改了其数据。如果temp中存的是非常重要的内容,那么程序就会出问题,所以这种方法也是非常不可取的。
###③错误类型三

void swap(double x, double y)
{
	int temp;
	
	temp = x;
	x = y;
	y = temp;
}

这种方式,只能单向传递,就是把main函数中想,x,y对应的值传到swap函数中,而不能传回交换后的值。
##4、主调函数传回数据的第二种方式
先看代码

#include 
int main()
{
	void fun(int a, int b, int *sum, int *sub);
	int a = 0, b= 0, m1,m2;
	scanf("%d%d", &a, &b);
	
	fun(a, b, &m1, &m2);
	printf("sum = %d\nsub = %d\n", m1, m2);
}
void fun(int a, int b, int *sum, int *sub)
{
	int p, q;
	p = a + b;
	q = a - b;

	*sum = p;
	*sub = q;
}

运行结果为:
这里写图片描述

这里直接用指针返回和与差,而没有用到return。

#二、数组做函数参数
数组做函数参数,说具体是指向数组的指针变量做函数参数。
由于数组名是该数组的首地址,指针变量的值也是首地址,所以函数的实参和形参都可以指向数组名或者数组的指针。于是有了以下四种对应关系:
           
           数组名和数组指针做函数参数时的对应关系

实参 形参
数组名 数组名
数组名 指针变量
指针变量 指针变量
指针变量 数组名

下面用一段代码来说明问题:


#include 
int main()
{
	float ave(int *b, float num);
	int counter,a[5] = {0};
	float all =0, res;
	
	scanf("%f", &all);
	for(counter = 0; counter < all; counter++)
	{
		scanf("%d", &a[counter]);
	}
	res = ave(a, all);
	printf("%f", res);
	return 0;
} 

float ave(int *b, float num)
{
	int i, sum =0;
	float ave;
	for(i = 0; i < num; i++)
	{
		sum = sum + b[i];
	}
	ave = (float)sum/num;
	return ave;
}

这里传入函数ave的是数组a的首地址,而不是将整个数组传入。传入首地址后,ave函数就按照一定顺序去访问a的储存空间,从而得到a中的数据。

  • 当然float ave(int *b, float num) 也可以写为float ave(int b[], float num) 或者float ave(int b[100], float num) 也就是说b[] 后面方括号内可以是任意数字,因为那个数字是没有意义的,真真起作用的是b和方括号。
    总结一下这部分就是:
    数组做形参,其实就是指针做形参。只要指针向函数内传入数组首地址,那么函数形参和实参是指同一数组。函数内部对数组所做的处理,就是对主调函数中的实参数组所作的处理,可以传回主调函数。
    #三、函数的指针
    部分编译器不支持这部分内容
    ##1、函数语句的存储和函数的指针的定义
    函数是由语句组成的,语句也是被存在连续的一段储存区域中的,所以我们考虑,能不能把函数的首地址也存在一个变量中,方便用一个变量调用不同的函数。。其实这种指向函数首地址的指针变量称为函数的指针,
int (*pf)();

上述语句就是对一个函数的指针的定义,它可以且只能保存函数的首地址。并且该函数的返回值是int形的。当然也可以在后面的()中加上函数的参数如int (*pf)(int , int )

下面介绍一个很重要的定义形式逆序阅读法
int (*pf)(); 有()先读()内的内容,读作:pf是指针,指向函数,函数返回值是int。
int *pf(); ()*优先, 先读() 后读*, 读作pf 是函数, 其返回值是int *
int pf(); 先读(),读作pf 是函数,函数返回值是int。

##2、变量指向函数及函数调用
让指针变量指向函数的方法如下

pf = 函数名;

注意了,这里是干干净净的,没有任何零碎。
不要写为pf = &函数名, 或者*pf = 函数名;
通过函数指针调用函数的方法如下:

(*pf)(参数,参数,.......);

或:

pf(参数,参数,....);

注意,调用函数时用(*pf), 或者直接用pf, 均可。(*pf)的* 仍然是一个标志,不是取其内容。
##3、示例

#include 
int main()
{
	int max(int a,int b);
	int (*pmax)();
	
	int x, y, z;
	pmax = max;
	printf("input two numbers:");
	scanf("%d%d", &x, &y);
	z = (*pmax)(x, y);
	printf("maxmum = %d", z);
	return 0;
}
int max(int a, int b)
{
	if(a > b)
	{
		return a;
	}
	else
	{
		return b;
	}
}

部分编译器,不支持函数的指针。
送福利了

  • 打印出9*9乘法表
  • c语言输入年月日,输出这是一年中的第几天
  • 有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

你可能感兴趣的:(C语言/C++)