善于运用指针--函数与指针
文章目录
- 前言
- 一、函数的指针
- 二、函数指针运用
- 1函数名地址
- 2指针变量调用函数
- 3指向函数的指针变量做函数参数
- 二、返回指针值的函数
- 总结
前言
如果在程序中定义了一个函数,在编译时会把函数的源代码转换为可执行代码并分配一段空间。这段空间有一个起始地址,也称为函数的入口地址。每次调用函数时都从该地址入口开始执行此函数代码。
一、函数的指针
函数名就是函数的起始地址,就是函数的指针。
二、函数指针运用
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)的括号根据需要写上实参
函数指针变量不能进行算数运算
用函数名调用函数,只能调用所指定的一个函数,但是用指针变量调用函数,可以根据不同情况先后调用不同函数。
注意:定义的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;
}
这个地方的解引用是二维数组某行的首地址,也就是找到地址对应的行,依次打印数字
总结
(未完待续...)