一、概念
1、函数
具有某种功能的独立程序段,用来实现一个模块的功能。换句话说,函数就是一系列语句的组合,用以实现一些相对独立且具有一定通用性的功能。
如:y = f(x);
2、分类
从用户使用角度看,函数可分为:
①标准函数(库函数)
②用户自定义的函数
从函数的参数形式看,函数可分为:
①无参函数;
②有参函数
二、函数声明
1、标准函数(库函数)的声明
调用标准c库函数时无需声明,但要包含对应函数的头文件。
如:#include <stdio.h>
2、调用用户自定义函数的声明
当用户自定义的函数若与主函数在在同一文件中:
若被调函数写在后面,则应该在主调函数中声明被调函数。
声明形式如下:类型标识符 函数名(类型1 形参1,类型2 形参2,……);
当用户自定义的函数若与主函数在不在同一文件中:
主函数调用之前需要包含被调函数所在文件的头文件和声明被调函数。
如:#include “file.h”
3、函数声明和函数定义的区别
(1)函数声明的作用是把函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查。
(2)函数定义是指对函数功能的确立,包括指定函数名、函数值类型、形参及其类型、函数体等,它是一个完整的、独立的函数单位。
(3)可省略被调用函数声明的情况
1)被调用函数定义在主调函数之前,可以不进行函数声明,定义本身即是声明。
2)已在所有函数定义之前,在文件的开头,在函数的外部已做过函数声明,则在各个主调函数中不必对所调用的函数再做声明。
三、函数定义
1、函数定义的一般形式
(1)无参函数的定义:
类型标识符 函数名()//"()"表可接受任意参数;(void)表不接受任何参数。
{
说明部分
语句
}
(2)有参函数的定义:
类型标识符 函数名(形式参数表列)
{
说明部分
语句
}
函数一般结构包括函数首部和函数体:
函数首部 - 函数返回值类型 函数名()。(函数返回值类型缺省时默认int。)
函数体 - {}。(用于存放代码,包含声明语句和功能语句。)
2、函数的返回值
通过函数调用使主调函数得到一个确定的值,称为函数的返回值。
函数的返回值通过 return语句获得,return语句将被调函数的一个确定的值带回主调函数中去。
return语句的一般形式:return 函数返回值;//函数返回值是有确定值的常量、变量或表达式。
说明:
(1)return 后面的值可以是一个表达式,例如:
z=x>y? x:y;
return(z);
(2)一个函数中可以有多个return语句,但是一次函数执行只能执行其中的一个。当执行到某个return语句时,则终止函数执行,并带回函数值。
(3)若函数体内没有return语句,就一直将函数执行完,再返回调用函数,有一个不确定的值带回。
(4)return后面可以无“返回值”(即 return ;),则该return语句只起到终止函数执行,返回主调函数的作用。
3、函数值的类型
函数值的类型指的是函数返回值的类型。通常与return语句的表达式类型一致。
说明:
(1)凡不加类型说明的函数,一律自动按整型处理。
(2)如果函数类型和return语句的类型不一致,以函数类型为准。对数值型数据,可以自动进行类型转换。既函数类型决定返回值的类型。
(3)如果函数不返回值,可以将函数定义为“无类型”void (或称“空类型”)。
四、函数调用
1、函数调用的一般形式
有参数函数:函数名(实际参数表);
无参数函数:函数名();
说明:
(1)多个实参间用逗号隔开;
(2)实际参数表中的参数可以是常量、变量或表达式;
(3)实参与形参个数必须相等,类型应一致或赋值兼容;
(4)实参与形参按顺序对应,一一传递数据;
(5)实参表求值的顺序与系统有关。
2、函数调用的具体方式
(1)把函数调用单独作为一个语句: 函数名(实际参数表);
使用情况:这种方式常用于调用一个可以忽略返回值或没有返回值的函数。
(2)函数调用出现在表达式(函数表达式)中: 变量名=函数表达式
使用情况:这种方式用于调用带返回值的函数,函数的返回值将参加表达式的运算。
3、函数的特殊调用
(1)函数的嵌套调用
嵌套调用:在调用一个函数的过程中,又调用另一个函数。
C语言不能嵌套定义,但可以嵌套调用。在调用一个函数的过程中,又调用另一个函数。
(2)函数的递归调用
定义:在调用一个函数的过程中直接或间接地调用该函数本身。
//直接递归调用
sum()
{
......
sum();
......
}
//间接递归调用
sum1()
{
......
sum2();
......
}
sum2()
{
......
sum1();
......
}
说明:不应出现无终止的递归调用,因此,应该给定一个限制递归次数的条件。
递归函数的执行过程:
递归调用:记住本次现场,递归调用。
终了调用:返回上次调用现场。
五、函数参数
1、参数分类
(1)形式参数:在定义函数时函数名后面括弧中的变量名,简称形参。通知系统要预留内存位置。
①形参调用前不占内存单元,调用时占用, 调用后释放;
②形参是函数的内部变量,只在函数内部才有意义;
③对每个形参必须指明其名字和数据类型;
(2)实际参数:在调用函数时函数名后面括弧中的表达式,简称实参。在运行时把值传给函数。
①实参可以是常量、变量或表达式,并且必须有确定的值;
②实参个数必须与对应的形参个数严格一致
③实参对形参的数据传递是单向值传递,只由实参传递给形参,反之不可。调用结束后,只有形参单元被释放,实参单元中的值不变。
2、数组作为函数的参数
数组元素可以做函数的实参(单向值传递);
数组名可以做函数的参数(双向地址传递);
多维数组可以做函数参数。
(1) 数组元素可以做函数的实参
由于表达式可以做实参,数组元素可以作为表达式的组成部分,因此,数组元素可以做函数的实参,并且可以单向传递给形参。
(2) 数组名可以做函数的参数
由于数组名代表的就是数组在内存中存放区域的首地址。把数组名作为函数参数来实现大量数据的传递是一个非常好的数据传递方法。
数组名做函数参数的具体方法:
1)在主调函数和被调函数中分别定义数组;
2)实参数组和形参数组类型应一致;
3)实参数组和形参数组大小不一定一致,形参数组可以不指定大小(这里指一维数组)。
说明:数组名做函数的实参和形参时不是“值传递”,而是“地址传递”。因此,形参数组各元素的值如果发生变化会使实参数组各元素的值发生同样的变化。
形参数组不指定大小,另设一个形参传递数组元素个数,这样在每次调用时才确定数组元素个数,使子函数具有通用性。
六、函数应用
1、一般函数调用示例
[file.h]
#ifndef _FILE_H_
#define _FILE_H_
int glb_putString(char str[],int ilent,int type,int isplant);
#endif
[file.c]
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include "file.h"
int glb_putString(char str[],int ilent,int type,int isplant)
{
char ch=0;//获取字符
int ilen=0;//输出字符长度
while(1)
{
ch=getch();
if(ch=='\r')//回车结束
{
if(ilen)//非空
{
str[ilen]=ch;
break;
}
}
if(ch=='\b')//回删
{
if(ilen)//非空,长度大于0
{
printf("\b \b");//光标回退
ilen--;
str[ilen]='\0';
}
}
if(ilen<ilent && ch!='\b')//限定输入长度
{
switch(type)
{
case 0:
{
if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')//输入字母
{
if(isplant)
{
putchar('*');
}
else
{
putchar(ch);//打印输出
}
}
str[ilen]=ch;//存入数组
ilen++;
}
break;
case 1:
{
if(ch>='0'&&ch<='9')//输入数字
{
if(isplant)
{
putchar('*');
}
else
{
putchar(ch);//打印输出
}
}
str[ilen]=ch;//存入数组
ilen++;
}
break;
case 2:
{
if(ch>='0'&&ch<='9'||ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')
//输入数字和字母
{
if(isplant)
{
putchar('*');
}
else
{
putchar(ch);//打印输出
}
}
str[ilen]=ch;//存入数组
ilen++;
}
break;
}
}
}
return ch;
}
[main.c]
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include "file.h"
int main()
{
char name[8]={0};//定义账号
char pwd[6]={0};//定义密码
printf("请输入姓名:");
glb_putString(name,8,0,0);//引用被调用封装密码登录函数
printf("\n");
printf("请输入密码:");
glb_putString(pwd,6,1,1);//引用被调用封装密码登录函数
printf("\n");
return 0;
}
编辑 2020-09-13 03:48 首次编辑
增改 2021-07-04 17:30 内容结构优化
注:本文旨于作为自己的学习笔记,不作他用。