1、函数介绍

函数可以把相对独立的某个功能抽象出来,使之成为程序中的一个独立实体。可以在同一个程序或其他程序中多次重复使用

分类:

内置函数: 由C语言系统提供; 用户无须定义,也不必在程序中作类型说明; 只需在程序前包含有该函数定义的头文件。

自定义函数: 用户在程序中根据需要而编写的函数。

优点:

①使程序变得更简短而清晰

②有利于程序维护

③可以提高程序开发的效率

④提高了代码的重用性

实例:

#include <stdio.h>


double add_function(int , double ); //函数声明:提前告诉编译器函数的类型


double sub_function(int x, double y)
{
	double result ;
	result = x-y;
	return result;
}


int main()  //主函数   调用函数
{
    int a = 1;
	double b = 2.5;
    double ret;
//	ret = add_function(a, b);  //函数调用 ,  a,b  实参
    
	ret = sub_function(a, b);

	printf("ret = %.2lf\n",ret);
	return 0;
}



//函数定义:  具体实现某个功能的步骤    x, y是形参
double add_function(int x, double y)  //子函数   被调用函数
{
	double result;

	result = x+y;

	return result;
}

2、函数的嵌套调用的递归调用

2.1 嵌套调用

从一个函数调用另一个函数称为函数的嵌套调用

注意:函数不可以无限嵌套调用下去,会导致栈越界

实例:

#include <stdio.h>

void  func1();
void  func2();
void  func3();

void  func1()
{
	func2();
	printf("AAA\n");
}

void  func2()
{
	printf("BBB\n");
	func3();
}

void func3()
{
	printf("CCC\n");
	func1();
}

int main()
{
	func1();
	return 0;
}

2.2 递归调用

在一个函数体内调用自身称为函数的递归调用

实例:

#include <stdio.h>

int factorial(int a) 
{     
	if (a == 1)        
		return 1;     
	else     
	{         
		a = a * factorial(a-1);    
		return a;  
	}
}

int main()
{
	int ret;
	ret = factorial(5);
	printf("ret = %d\n", ret);
	return 0;
}

3、函数返回值

C 语言中的 return 语句用于向调用函数返回值,语法如下:              

return (<表达式>);

(1)最多只能返回一个值

(2)一旦遇到return,表示本函数结束

(3)如果返回值和定义的返回值类型匹配,以返回值类型为主,返回值会自动转换成指定的类型

4、函数的传值调用

4.1 数值传参

这种调用方式是将实参的数据传递给形参,即将实参值拷贝一个副本存放在被调用函数的栈区中。在被调函数中,改变了形参的值而不影响调用函数实参值。

实例:

#include <stdio.h>

void func(int x)
{
	x = 10;
	return ;
}

int main()
{
	int a = 0;

    func(a);

	printf("a = %d\n", a);
	return 0;
}

4.2 地址传参

这种调用方式是将实参变量的地址传递给形参,这时形参应是指针。即让形参指针指向实参地址。于是,这就提供了一种可以改变实参变量的值的方法:在被调函数中改变形参所指向的变量值。

实例:

#include <stdio.h>

int func1(int x, int  y)
{
	int result = x+y;
	return result;
}

//通过指针传入参数!!!
int  func2(int *px, int *py)
{
	int result ;
	result = *px + *py;
	return result;
}

//通过指针传出参数!!!!
void  func3(int x, int y, int *pret)
{
	*pret = x+y;
}

int main()
{
	int a = 1, b=2;

	int ret;

	//ret = func1(a, b);
	
	//ret = func2(&a, &b);
	
	func3(a, b, &ret);
	return 0;
}

数值传参和地址传参的选择:

1、如果只需要实参中的数据参与运算,不需要改变实参中的内容,地址传参和数值传参可以

2、如果要修改形参内容, 必须选择地址传参

5、数组作为函数参数传递

在用数组作实参时,以传址方式调用函数,也就是说把实参数组的首地址赋给形参

实际上形参数组和实参数组为同一数组,共同拥有一段内存空间

传递数组至少两个条件:1、数组首元素的起始地址     2、数组的元素个数

实例:

#include <stdio.h>

//  形参a  :表示接收一个整型数组首元素的起始地址!!!
void  function1(int a[], int n)
{
	printf("function1:sizeof(a)= %ld\n", sizeof(a));// 8
	for(int i=0; i<n; i++)
	{
		printf("a[%d] = %d\n", i, a[i]);
	}
}

void  function2(int *p, int n)
{
	for(int i=0; i<n; i++)
	{
		printf("*(p+%d)= %d\n", i, *(p+i));
	}
}

int main()
{
	int a[5] = {1,2,3,4,5};
    
	printf("main: sizeof(a)=%ld\n", sizeof(a)); //  20

	//function1(a, 5);
	
	function2(a, 5);
	return 0;
}

6、函数指针

1、函数指针: 本质是一个指针变量,保存函数的入口地址

2、函数指针语法: 返回值类型 (*pfun)(参数表);

int (*pfun)(int , double);   //pfun是一个函数指针,保存有两个参数,分别是整型和浮点类型, 返回值是整型函数的入口地址

ps:  函数名就是函数的入口地址!!!!

3、函数调用的方式:
(1)直接通过函数名调用
(2)通过函数指针回调函数:    函数指针(参数表)

实例:

#include <stdio.h>

void  func()
{
	printf("#####\n");
}

int main01()
{
	func();

	void (*pfun)() = NULL; 

	pfun = func;
    
	pfun();   //回调函数:使用函数指针调用函数

	return 0;
}

7、综合练习题

1、实现简单的图形面积管理系统
(1)显示菜单

    欢迎进入图形面积管理系统
    1、计算矩形面积
    2、计算三角形面积
    3、计算圆的面积
    0、退出系统
    请输入你的选择
   

(2)根据菜单进入不同的分支

#include <stdio.h>

int function1(int n)
{
	if(1 == n)
	{
		return 1;
	}
	else
	{
		int sum = 0;
		sum = n+ function1(n-1);
		return sum;
	}
}

double func1(double x, double y)
{
	return x*y;
}

double func2(double d, double h)
{
	return (double)1/2*d*h;
}

double func3(double r)
{
	return 3.14*r*r;
}

int main()
{
	double result;
	double x, y;
	int sel;
	int flag = 1;
	while(flag)
	{
		printf("欢迎进入图形面积管理系统!\n");
		printf("1、计算矩形面积\n");
		printf("2、计算三角形面积\n");
		printf("3、计算圆形面积\n");
		printf("0、退出系统\n");
		printf("请输入你的选择:\n");
		scanf("%d", &sel);
		while(getchar()!='\n') ;  //清空缓冲区
        
		switch(sel)
		{
			case 1:
				printf("请输入矩形的长和宽:");
				scanf("%lf%lf", &x, &y);
				while(getchar()!='\n');
				result = func1(x, y);
				printf("矩形的面积为:%.2lf\n", result);
				break;
			case 2:
				printf("请输入三角形的底和高:");
				scanf("%lf%lf", &x, &y);
				while(getchar()!='\n');
				result = func2(x, y);
				printf("三角形的面积为:%.2lf\n", result);
				break;
			case 3:
				printf("请输入圆的半径:");
				scanf("%lf", &x);
				while(getchar()!='\n');
				result = func3(x);
				printf("圆的面积为:%.2lf\n", result);
				break;
			case 0:
				flag = 0;
				break;
			default:
				printf("输入有误,请重新选择!\n");
				break;
		}
	}
	return 0;
}