【黄色手套22】5话:函数

 目录

序言:

函数的定义:

函数的声明:

函数的调用:

函数的嵌套调用:

函数的递归调用:   

数组作为函数参数传递:

局部变量和全局变量:

静态变量和动态变量:


序言:

■.  啥是函数?

所谓“函数”是从英文funtion翻译过来的,其意思既是“函数”,也是“功能”。

计算机里的函数侧重于后者--功能。

从本质上来说,函数就是用来完成一定功能的,是把实现功能的代码封装起来,然后给这些打包起来的代码取个名字。

每一个函数用来实现一个特定的功能,函数的名字对应其代表的功能。

■.  为啥使用函数?

为了提高代码的复用性,提高程序的可读性,在使用过程中比较灵活,更加方便了程序代码的编写。

函数的定义:

基本格式:

数据类型 函数名(参数列表)
{
    函数体;    //  函数的功能
    //return语句    //  函数的返回值
}

■.  说明

C语言中要求,在程序中用到的所有函数,必须“先定义,后使用”。

定义函数应包括以下几个内容:

(1) 指定函数的类型,即函数返回值的类型。 

(2) 指定函数的名字,以便后续按名调用。

(3) 指定函数的数据类型及参数个数,以便在调用函数时向它们传递数据(无参函数不需要)。

(4) 指定函数所完成的功能,也就是函数要完成怎样的操作,函数的功能写在函数体中。

   (它说明了函数是做什么的)

■.  定义类型:

1. 定义无参数无返回值函数:

void 函数名()     // 或者void 函数名(void)
{
   函数体 
}

2. 定义有参数无返回值函数:

void 函数名(参数1,参数2,......)
{
  函数体
}

3. 定义无参数有返回值函数:

类型名 函数名()
{
  函数体              // 函数体最后有return语句
}

4. 定义有参数有返回值函数:

类型名 函数名(参数1,参数2,......)
{
   函数体           // 函数体最后有return语句
}

void为空类型,一般用于函数没有返回值时给定函数的类型。

例如:

void weixiao()                   // 或者 void weixiao(void)
{
	printf("hello world\n");
}
int main()
{
	weixiao();
	return 0;
}

附加:

比较两数的大小:

int MAX(int x, int y)           //求两个数中较大数的函数
{
	int z = x > y ? x : y;  
	return z;
}
int main()
{
	int a, b;
	scanf("%d%d", &a, &b);
	printf("%d\n", MAX(a, b));
	return 0;
}

void MAX(int x, int y)            //输出较大数的函数
{
	int z = x > y ? x : y;
	printf("两数中较大数为:%d\n", z);
}
int main()
{
	int a, b;
	scanf("%d%d", &a, &b);
    MAX(a, b);
	return 0;
}

int MAX(int x, int y)       // “准确“判断较大数
{
	if (x == y)
	{
		return printf("两数相等都为:%d\n", x);
	}
	int z = x > y ? x : y;
	return printf("两数中较大数为:%d\n", z);
}
int main()
{
	int a, b;
	scanf("%d%d", &a, &b);
    MAX(a, b);
	return 0;
}

补充:

参数列表:函数的参数,可以没有,也可以有一个或者多个。

函数体:实现函数功能的代码,用于完成具体的操作。

return:函数的返回值语句,用于返回函数体执行的结果;

             返回值可以没有,如果有有且仅有一个;

             函数体返回值的类型需要与函数的类型保持一致;

           (函数类型设置为怎样的类型,返回值语句中就应返回相应类型的数据)

           (返回值语句中返回了什么类型的数据,函数类型就为相应的类型)      

函数名在理论上可以使用中文,但目前不推荐。

在现有技术中,因无法预知编译器解析可能产生的问题,以及代码文件的文本编辑、c++标准的自适应等种种问题,就可能造成编译或运行错误。

所以,我们的变量名、函数名、对象名,甚至文件名和路径目前暂且都推荐使用英文。

函数的定义只能放在主函数前面或后面,

(主函数内定义函数会报错:本地函数定义是非法的)

______________

函数的声明:

一般函数先定义后使用,

若函数的使用在定义之前,就需要在使用之前进行函数的声明,然后补上定义。

如果函数先使用后定义且不事先进行函数声明,会报错:"该函数名":找不到标识符

基本格式:

数据类型  函数名 (参数列表) ;

例如:

#include
int main()
{
	int a, b;
	scanf("%d%d", &a, &b);
	int MAX(int c, int d);      // 函数MAX的声明
	MAX(a, b);
	return 0;
}
int MAX(int x, int y)
{
	if (x == y)
	{
		return printf("两数相等都为:%d\n", x);
	}
	int z = x > y ? x : y;
	return printf("两数中较大数为:%d\n", z);
}

同一函数可进行多次声明,但只能进行一次定义。

如果定义两次及以上,报错:函数"数据类型 函数名(参数列表)"已有主体

______________

函数的调用:

即,使用函数

基本格式:

函数名(参数列表);

主调函数:调用其他函数的函数

被调函数:被其他函数调用的函数

C语言中,main()就为主调函数。

■.  函数参数:

在调用有参函数时,需进行参数的传递。

实参:实际参数,是主调函数中用于给被调用函数参数传递数据的参数。

形参:形式参数,是被调函数中用于接收主调函数参数传递过来的数据的参数。

           也称为虚拟参数

■.  实参和形参之间的数据传递:

在调用函数的过程中,系统会把实参的值传递给被调函数的形参。

(即形参从实参得到一个值,“复制”操作)

■.  函数调用过程中,以下几点需注意:

(1)实参可以是常量、变量或表达式。(后二者均已被赋值)

(2)实参和形参的数据类型应相同或赋值兼容,

         且实参和形参在各自参数列表中的位置一 一对应。

(3)函数遇到return返回语句过后,不再继续执行return之后的语句(return作用域内)。

(4)形参只参与其所在函数的函数体中的运算,不能用于其他函数中;

         且未被调用函数时,形参不占用存储单元;

         开始被调用时才给形参开辟存储空间;

         函数调用结束后,形参的存储单元会被释放。

(5)函数的形参和实参是两个不同的变量,

         一般请况下,形参值的改变不影响实参的值,

         除非函数参数的传递类型为地址传递(引用传递)。

___________________

函数的嵌套调用:

函数的定义是相互平行独立的,也就是说,一个函数内不能再定义另一个函数(不能嵌套定义)。

但是,

函数可以嵌套调用,即在一个函数执行的过程中,可以调用另一个函数,诸如此类。

函数的递归调用:   

在调用一个函数的过程中又直接或间接的调用此函数本身,称为函数的递归调用。

递归的函数中应有结束递归的条件,否则会和死循环一样,陷入无限递归,称为死递归。

例1:函数递归输出整数10~0

#include
void fun1(int n)
{
	printf("%d\n", n);
	if (n >0)
		fun1(n - 1);      //  函数的递归调用
}
int main()
{
	fun1(10);
	return 0;
}

例2:函数递归输出整型0~10

#include
void fun1(int n)
{
	static int i = 0;
	printf("%d\n",i++);
	if (i<=n)
	    fun1(n);
}
int main()
{
	fun1(10);
	return 0;
}

 例3:函数递归输出整型数组的逆序

#include
void int_arr1_print(int arr1[], int n)   //函数名说明函数的功能
{
	printf("%d\n", arr1[n - 1]);
	if (n-1 > 0)
		int_arr1_print(arr1, n - 1);
}
int main()
{
	int arr1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	int_arr1_print(arr1, 10);
	return 0;
}

例4:函数递归输出整型数组的正序

#include
void int_arr1_print(int arr1[], int n)      // 形参arr1[]代表地址
{
	static int i = 0;
	printf("%d\n", arr1[i]);
	if (++i 

___________________________

数组作为函数参数传递:

数组名为该数组的首地址

因此,

这个数组作为函数参数传递实际上是引用传递,传递的是地址,
形参的改变会影响到实参。

即,

在调用函数中,改变形参数组元素的值,实参数组元素的值会改变。

例如:

#include
void gaibian(int arr2[],int n)
{
	static int i = 0;
	if (i < n)
	{
		arr2[i] += 1;
		printf("%d\t", arr2[i++]);
		gaibian(arr2, n);
	}
	else
		putchar('\n');
}
int main()
{
	
	int arr2[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	printf("原来的实参数据为:\n");                       
	for (int j = 0; j < 10; j++)           // 输出arr2数组数据(原始数据)      
	{
		printf("%d\t", arr2[j]);
	}
	putchar('\n');

	gaibian(arr2, 10);                     // 调用函数
	printf("现在的实参数据为:\n");        
	for (int j = 0; j < 10; j++)           // 输出arr2数组数据(当下数据)
	{
		printf("%d\t", arr2[j]);
	}
	putchar('\n');
	return 0;
}

_________________________

局部变量和全局变量:

按照作用域的不同,可将变量分为局部变量和全局变量。

■.  局部变量

局部变量的作用范围只在一定范围内有效(作用域和生命周期有限)

局部变量的定义:

(1)在函数开头定义

(2)在函数内部的复合语句中定义

■.  全局变量

全局变量的作用范围相对于局部变量来说更为广泛,也称为外部变量(作用域和生命周期为全局)

在定义完成后都能使用,到程序结束时才释放。

全局变量的定义:

 (1)在函数外部定义(一般在预处理指令后)。

——————————————       

静态变量和动态变量:

■.  动态变量

程序中所定义的变量默认为时动态变量(auto)。

■.  静态变量

(1)在定义变量前加一个关键字static,即可定义一个静态变量(作用域为局部,生命周期为全局)。

(2)细分为静态局部变量和静态全局变量

(3)静态变量在一个程序中只会被定义和初始化一次(当再次执行到定义语句时,其值不会被重置(初始化),会保留上次改变的值)。

  例1:

#include
void fun2()                    // 循环输出0~无穷
{
	static int i = 0;          // 静态局部变量
	printf("%d\n", i++);
	fun2();
}                           
int main()
{
	fun2();                    
	return 0;
}

例2:

#include
static int i = 0;                      //  静态全局变量
void fun2()
{
	printf("%d\n", i++);
	if(i==22)printf("最后下一次:\n");
	if(i<=22)fun2();
}
int main()
{
	fun2();
	printf("%d\n", i);                //   i 可用
	return 0;
}

#include
static int a = 0;          // 静态全局变量
void fun4()
{
	printf("%d\n", a++);
}
int main()
{
	while (1)
	{
		fun4();
		if (a > 22)       //  a 可用
			break;
	}
	return 0;
}

_____________________# 

你可能感兴趣的:(1:C语言,c语言)