善于运用指针--函数与指针

文章目录

  • 前言
  • 一、函数的指针
  • 二、函数指针运用
    • 1函数名地址
    • 2指针变量调用函数
    • 3指向函数的指针变量做函数参数
  • 二、返回指针值的函数
  • 总结


前言

如果在程序中定义了一个函数,在编译时会把函数的源代码转换为可执行代码并分配一段空间。这段空间有一个起始地址,也称为函数的入口地址。每次调用函数时都从该地址入口开始执行此函数代码。 


一、函数的指针

函数名就是函数的起始地址,就是函数的指针。

01f28c84c06e499b94c052cfbb34d8ac.png

二、函数指针运用

1.函数名地址

代码如下(示例):

int add(int x, int y)
{
    return x + y;
}
int main()
{
    printf("%p", add);//打印函数地址
    return 0;
}

打印结果为00007FF6BC9013D9 ,是函数地址,由此可见函数名是一个地址,定义指针变量可以将函数名直接赋给指针变量。


2.指针变量调用函数

代码如下(示例):

void swap(int*p1, int*p2)
{
    int tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}
int main()
{
    int arr[] = { 1,2,3,4,5 };
    //swap(&arr[1], &arr[4]);
    void (*pc)(int*, int*) = swap;//定义指向函数的指针变量
    (*pc)(&arr[1], &arr[4]);//用指针变量调用swap函数
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

该处可以看出,swap函数的调用,指针*pc对应函数名,括号后面调用一样。

但是得注意,定义指针变量指向函数名(也就是函数地址)时,定义的类型应与函数返回值类型一致,后面括号里的量也应与被调函数的定义保持一致。

在给指针变量赋值时,只需给出函数名,无需给出函数参数。void (*pc)(int*, int*) = swap;

用指针变量调用函数时,只需用*pc代替函数名,在(*p)的括号根据需要写上实参

6fdfcd6ce1e04e12a360f424374a1710.png

函数指针变量不能进行算数运算

用函数名调用函数,只能调用所指定的一个函数,但是用指针变量调用函数,可以根据不同情况先后调用不同函数。

注意:定义的pc指针,只能指向参数类型为int、int,返回类型为void的函数。


3、用指向函数的指针做函数参数

指向函数的指针,把函数地址作为参数传递给其它函数 

用指向函数的指针做函数参数,这个函数的返回值类型是一个指针,参数是函数指针的参数


设计一个计算器,实现加减乘除:

代码如下:

void print()
{
	printf("********************************\n");
	printf("***** 1.add     2.sub **********\n");
	printf("***** 3.mul     4.div **********\n");
	printf("*****    0.esc   ***************\n");
}
int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}
int mul(int x, int y)
{
	return x * y;
}
int div(int x, int y)
{
	return x / y;
}
int main()
{
	int a = 0;
	int b = 0;
	int ret = 0;
	int input = 0;
	print();
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		printf("请输入两个数\n");
		scanf("%d%d", &a, &b);
	    ret=add(a, b);
		printf("%d", ret);
		break;
	case 2:
		printf("请输入两个数\n");
		scanf("%d%d", &a, &b);
		  ret = sub(a, b);
		printf("%d", ret);
		break;
	case 3:
		printf("请输入两个数\n");
		scanf("%d%d", &a, &b);
		  ret = mul(a, b);
		printf("%d", ret);
		break;
	case 4:
		printf("请输入两个数\n");
		scanf("%d%d", &a, &b);
		  ret = div(a, b);
		printf("%d", ret);
		break;
	default:printf("输入错误");
		break;
	}
	return 0;
}

这里在case里反复重复的内容太多,代码不够简洁,这里add、sub、mul、div的函数参数和返回值都是同样类型的,因此可定义一个指针(即*p)用来指向这几个函数,再定义一个指针函数,参数为指向这几个函数的指针(即*p)


代码如下: 

void col(int(*p)(int,int))
{
	int a = 0;
	int b = 0;
	int ret = 0;
	printf("请输入两个数\n");
	scanf("%d%d", &a, &b);
	ret =(*p)(a, b);
	printf("%d", ret);
}

void print()
{
	printf("********************************\n");
	printf("***** 1.add     2.sub **********\n");
	printf("***** 3.mul     4.div **********\n");
	printf("*****    0.esc   ***************\n");
}
int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}
int mul(int x, int y)
{
	return x * y;
}
int div(int x, int y)
{
	return x / y;
}
int main()
{
	
	int input = 0;
	print();
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		col(add);
		break;
	case 2:
		col(sub);
		break;
	case 3:
		col(mul);
		break;
	case 4:
		col(div);
		break;
	default:printf("输入错误");
		break;
	}
	return 0;
}

这样的程序更简洁,更具可读性。


三、返回指针值的函数

函数返回值是一个地址或者指针。

字符串拷贝函数 

char* string_copy(char* str1, char* str2)
{
	char* start = str2;
	while (*str2++ = *str1++)
		;
	return start;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };
	char* ret = string_copy(arr1, arr2);
	printf("% s\n", ret);
	return 0;
}

如上,函数的返回值是一个指针,这里将函数返回值赋给ret这个指针,通过指针指向的地址找到并打印字符,如果解引用,找到的会是字符数组的首地址的内容,只能打印“a”

在这里,%s, 传参ret是一个地址,打印该地址对应的字符串,遇到\0停止。

在C语言中,找到地址就相当于找到了值。


找学生序号对应的分数

int *score(int(*p)[3], int n)
{
	return *(p + n);
}
int main()
{
	int n = 0;
	int arr[][3] = { {1,2,3},{4,5,6},{7,8,9} };
	int i = 0;
	scanf("%d", &n);
	int* p = score(arr, n);
	for (i = 0; i < 3; i++)
	{
		printf("%d", *(p + i));
	}
	return 0;
}

 这个地方的解引用是二维数组某行的首地址,也就是找到地址对应的行,依次打印数字

总结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值