L1D9 C语言函数(二)

函数(二)

一、 指针函数

概念:指针函数是指一个函数的返回值为地址量的函数。
指针函数一般形式如下:

<数据类型>  *  <函数名称>(<参数说明>) 
{      
 语句序列;
 } 
 返回值:全局变量的地址/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;
}

在这里插入图片描述
这样我们只需要改变函数指针指向的即可实现不同类型的数组排序、

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值