函数(二)
一、 指针函数
概念:指针函数是指一个函数的返回值为地址量的函数。
指针函数一般形式如下:
<数据类型> * <函数名称>(<参数说明>)
{
语句序列;
}
返回值:全局变量的地址/static变量的地址 /字符串常量的地址/堆的地址
示例程序如下:
#include <stdio.h>
#include <string.h>
char * mystring( )
{
char str[20];
strcpy(str, "hello");
return str;
}
int main(void)
{
printf("%s\n", mystring());
return 0;
}
以上程序执行会出现段错误问题,整体逻辑是正确的,返回的也确实是指针类型,但是忽略了str是在栈上分配的,mystring执行结束后,就会销毁,所以返回的指针是非法指针,因此出错。可以加static修饰str,改为在全局与静态区分配空间,空间直到程序结束才会销毁。如下所示:
上面也可以把str写成字符串常量,也能正确执行,因为字符串常量和静态变量类似,都是程序结束才释放内存。还有一种方法就是返回堆上的地址,堆上的内存不会自动回收,需要手动回收。
二、 函数指针
2.1 基本函数指针用法
函数指针用来存放函数的地址,这个地址是一个函数的入口地址
函数名代表了函数的入口地址
函数指针变量说明的一般形式如下 (函数指针本质是指针 一般出现在定义层,其指针指向这个函数。 指针函数本质是函数,返回值为指针)
<数据类型> (*<函数指针名称>)(<参数说明列表>);
<数据类型>是函数指针所指向的函数的返回值类型 <参数说明列表>应该与函数指针所指向的函数的形参说明保持一致 (*<函数指针名称>)中,*说明为指针()不可缺省,表明为函数的指针。
示例程序如下:
#include <stdio.h>
typedef int (*MFunc)(int ,int); //函数指针类型说明
int test(int a , int b , MFunc pFunc);
int plus(int a , int b); //函数声明
int minus(int a , int b);
int main(int argc, char *argv[])
{
int x = 5 ,y = 8;
MFunc pFunc;
pFunc = plus;
printf("%d\n",(*pFunc)(x,y));
pFunc = minus;
printf("%d\n",(*pFunc)(x,y));
printf("%d\n",test(15 , 5 , plus));
printf("%d\n",test(15 , 5 , minus));
}
int plus(int a , int b)
{
return (a + b);
}
int minus(int a , int b)
{
return (a - b);
}
int test(int a , int b , MFunc pFunc)
{
return (*pFunc)(a , b);
}
该程序演示了如何声明函数指针变量,如何为函数指针赋值及如何通过函数指针调用函数。
2.2 函数指针数组
函数指针数组是一个保存若干个函数名的数组.
一般形式如下:
<数据类型> (*<函数指针数组名称> [<大小>] )(<参数说明列表> );
其中,<大小>是指函数指针数组元数的个数 其它同普通的函数指针
将前面的函数指针程序改写为函数指针数组形式:
#include <stdio.h>
typedef int (*MFunc)(int ,int); //函数指针类型说明
int plus(int a , int b); //函数声明
int minus(int a , int b);
int main(int argc, char *argv[])
{
int x = 5 ,y = 8;
MFunc pFunc[2]; //定义函数指针数组
pFunc[0] = plus;
printf("%d\n",(*pFunc[0])(x,y));
pFunc[1] = minus;
printf("%d\n",(*pFunc[1])(x,y));
}
int plus(int a , int b)
{
return (a + b);
}
int minus(int a , int b)
{
return (a - b);
}
三、 递归函数
递归函数是指一个函数的函数体中直接或间接调用了该函数自身 递归函数调用的执行过程分为两个阶段:
1、递推阶段:从原问题出发,按递归公式递推从未知到已知,最终达到递归终止条件 (必须要有结束条件,不然递归会死循环了。。)
2、回归阶段:按递归终止条件求出结果,逆向逐步代入递归公式,回归到原问题求解
示例程序(利用递归函数实现5!。(温馨提示5!= 5 * 4 * 3 * 2 * 1)):
#include<stdio.h>
int nx(int n);
int main(int argc ,char *argv[])
{
printf("%d %d %d %d %d\n",nx(1),nx(2),nx(3),nx(4),nx(5));
return 0;
}
int nx (int n)
{
if(n == 0 || n ==1)
return 1;
else
return nx(n-1)*n;
}
四、 综合练习
1、 编程实例:编写一个指针函数,删除一个字符串得空格 返回这个字符串
答:
#include <stdio.h>
char* del_sapce(char *s1);
int main(int argc,char *argv[])
{
char s[] = " a b s h";
char *p = s;
puts(s);
p = del_sapce(s);
puts(p);
return 0;
}
char* del_sapce(char *s1)
{
char *r = s1; //存放现在的首地址 后面s1会变
char *s2 = s1;
while(*s1 != '\0')
{
if(*s1 == ' ')
{
s1++;
}
else
{
*s2 = *s1;
s1++;
s2++;
}
}
*s2 = '\0';
return r;
}
2、编程写一个指针函数,实现字符串的连接
答:
#include<stdio.h>
char *mystrcat(char *str1,const char *str2);
int main(int argc,char *argv[])
{
char str1[100] = {"abc"};
char str2[] = {"xyz"};
char *p = str1;
p = mystrcat(str1,str2);
printf("%s %s\n",p);
return 0;
}
char *mystrcat(char *str1 , const char *str2)
{
char *p = str1;
while(*str1 != '\0')
str1++;
while(*str2 != '\0')
{
*(str1++) = *(str2++);
}
return p;
}
3、编写一个指针函数,把整数123转化成字符串”123”
答:
/*
* @Description:
* @Author: 余红祥
* @Date: 2022-03-27 10:41:44
* @LastEditTime: 2022-07-05 21:05:10
* @LastEditors:
*/
#include<stdio.h>
char *itoa(int n);
int main(int argc,char *argv[])
{
int n;
char *s;
printf("input:");
scanf("%d",&n);
s = itoa(n);
puts(s);
return 0;
}
char *itoa(int n)
{
int r = 0,i = 0,m = 0;
static char p[50];
static char q[50];
while(n != 0)
{
r = n % 10;
n /= 10;
p[i] = r + '0';
i++;
}
m = i;
p[m] = '\0';
/*倒序*/
for(i = 0;i < m;i++)
{
q[i] = p[m-i-1];
}
q[i] = '\0';
return q;
}
4、利用递归函数实现5!。(温馨提示5!= 5 * 4 * 3 * 2 * 1)
答:
#include<stdio.h>
int nx(int n);
int main(int argc ,char *argv[])
{
printf("%d %d %d %d %d\n",nx(1),nx(2),nx(3),nx(4),nx(5));
return 0;
}
int nx (int n)
{
if(n == 0 || n ==1)
return 1;
else
return nx(n-1)*n;
}
5、编程实例:编写一个递归函数,计算斐波那契数列
一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子? 我们不妨拿新出生的一对小兔子分析一下: 第一个月小兔子没有繁殖能力,所以还是一对 两个月后,生下一对小兔对数共有两对 三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,所以一共是三对
答:
#include<stdio.h>
int fb(int n);
int main(int argc ,char *argv[])
{
int n = 0;
int sum = 0;
puts("please input n:");
scanf("%d",&n);
sum = fb(n);
printf("%d\n",sum);
return 0;
}
int fb(int n)
{
int sum = 0;
if(n == 1)
sum = 1;
else if(n == 2)
sum = 1;
else
sum = fb(n-1)+fb(n-2);
return sum;
}
6、 调用C库中的qsort函数来实现字符数组的排序(先 man qsort一下,得知要调用函数指针,我们只需要实现这个函数即可)。
答:
#include <stdio.h>
#include<stdlib.h>
int mycompar (const void* p,const void* q)
{
return *(char *)p - *(char *)q;
}
int main(int argc ,char *argv[])
{
char s[] = {"fhkasldop"};
int n = 0,i = 0;
n = sizeof(s)/sizeof(char);
qsort(s,n,sizeof(char),mycompar);
for(i = 0;i<n;i++)
{
printf("%c ",s[i]);
}
putchar('\n');
return 0;
}
这样我们只需要改变函数指针指向的即可实现不同类型的数组排序、