一.函数的定义
函数头:函数对外的公开接口
函数名称:命名规则与跟变量一致,一般取与函数实际功能相符合的、顾名思义的名称。
1.只能以数字,字母,下划线组成,首字符不能是数字
2.函数名不能重复
3.命名的时候,最好一看就知道这个功能是干嘛的, 不要使用a,b,c,d这些单字母的, 不用拼音作为函数名
参数列表:即黑箱的输入数据列表,一个函数可有一个或多个参数,也可以不需要参数。
例如: 买装备, 需要传递2个信息, ①买什么装备 ②有多少钱
返回类型:即黑箱的输出数据类型,一个函数可不返回数据,但最多只能返回一个数据。
作用: 用于返回黑箱执行的结果
函数体:函数功能的内部实现
语法:
返回类型 函数名( 参数1, 参数2, 参数3, ... )
{
函数体;
}
例子:
1. 对比2个数值大小的函数
int Compare( int num1, int num2)
{
int retval = 0;
retval = num1 > num2 ? num1 : num2;
return retval;
}
语法汇总:
当函数的参数列表为 void 时,表示该函数不需要任何参数。
当函数的返回类型为 void 时,表示该函数不返回任何数据。
关键字 return 表示退出函数。
①若函数头中规定有返回数据类型,则 return 需携带一个类型与之匹配的数据;
②若函数头中规定返回类型为 void,则 return 不需携带参数。
例子:
申请一片内存空间,并且返回内存的起始地址
错误: int RequestMemory( int size) --> 返回类型--int
{
int *p = (int *)malloc( size);
return p; --> p:类型int * , 与返回类型不匹配
}
正确: int* RequestMemory( int size) --> 返回类型--int*
{
int *p = (int *)malloc( size);
return p; --> p:类型int * , 与返回类型匹配
}
例子:
不需要传递参数,与不需要返回结果
错误: void fun( void )
{
......
if()
{
return 1; //由于返回类型是void, 但是返回一个结果,报错
}
.....
}
正确: void fun( void )
{
......
if()
{
return ; //由于返回类型是void, 所以直接使用return就可以退出
}
.....
}
二.实参与形参
函数调用中的参数,被称为实参,即 arguments
函数定义中的参数,被称为形参,即 parameters
实参与形参的关系:
实参于形参的类型和个数必须一一对应。
形参的值由实参初始化。
形参与实参位于不同的内存区域,彼此独立。
实参于形参的类型和个数必须一一对应。
例子:
int add( int a, int b) //函数定义, num1,num2是形参
{
a++;
return a+b;
}
int main()
{
int a=1,b=2;
int retval = add( a ,b); //函数调用, a,b 是实参
printf("返回的结果:%d\r\n",retval);
}
调用add完成后,main函数中的a是1
练习:
实现一个传递2个值,把2个值交换的函数,并且在main函数调用,执行完毕后在main函数中打印出来.
void fun( int *a, int *b)
{
int t;
t = *a; //a指针指向的内存空间中的数据赋值t
*a = *b; //b指针指向的内存空间中的数据赋值给a指针指向的内存空间
*b = t;
}
void fun1( int a, int b)
{
int t;
t = a;
a = b;
b = t;
}
int main()
{
int a=1, b=2;
fun( &a, &b);
printf("a=%d b=%d\n",a,b); //输出结果:a=2,b=1, 发生交换
fun1( a, b);
printf("a=%d b=%d\n",a,b); //输出结果:a=2,b=1, 没有发生交换
}
函数名 : 可以代表函数的内存地址
函数指针: 指向与保存代码的内存空间的指针,可以使用该指针进行调用函数。
语法:
返回类型 (*指针名)( 参数类型1, 参数类型2, 参数类型3 ... );
void fun( int a, int b);
根据函数名写出对应函数指针的方法:
① 去掉函数名,参数列表的参数名[ 保留参数类型] void ( int, int);
② 添加指针的变量名,但是一定要使用圆括号 void (*p)( int ,int);
函数: int fun( int a, int b);
函数指针: int (*p)( int, int);
指向 返回值int类型,参数列表中2个参数,分别int,int的函数
函数: void fun( void (*p)(int ,int), int a, int b);
函数指针: void (*p)( void (*)(int ,int), int, int);
函数指针: void *(*start_routine) (void *)
函数: void* fun(void *arg);
三.回调函数:
函数实现方不调用该函数,而由函数接口提供方间接调用的函数,称为回调函数。
例子:
int Compare1( int num1, int num2)
{
printf("使用if语句判断大小\r\n");
if( num1 > num2)
return num1;
else
return num2;
}
int Compare2( int num1, int num2)
{
printf("使用三目运算符判断大小\r\n");
return num1>num2?num1:num2;
}
void Compare( int (*p)( int ,int), int num1, int num2);
{
printf( "回调函数的执行\r\n");
p( num1, num2);
}
int main()
{
int a =1, a=2;
Compare( Compare1, a, b);
Compare( Compare2, a, b);
}
函数调用的流程
函数调用时,进程的上下文会切换到被调函数,当被调函数执行完毕之后再切换回去
函数调用时代码的执行流程
使用对应函数,称为函数调用.
语法:
变量 = 函数名( 参数1, 参数2, ... );
例子:
int add( int num1, int num2) //函数定义
{
return num1+num2;
}
int main()
{
int a=1,b=2;
int retval = add( a, b); //函数调用
printf("返回的结果:%d\r\n",retval);
}
局部变量与栈内存
·局部变量概念:凡是被一对花括号包含的变量,称为局部变量
·局部变量特点:
某一函数内部的局部变量,存储在该函数特定的栈内存中
局部变量只能在该函数内可见,在该函数外部不可见
当该函数退出后,局部变量所占的内存立即被系统回收,因此局部变量也称为临时变量。
函数的形参虽然不被花括号所包含,但依然属于该函数的局部变量、
·栈内存特点:
每当一个函数被调用时,系统将自动分配一段栈内存给该函数,用于存放其局部变量
每当一个函数退出时,系统将自动回收其栈内存
系统为函数分配栈内存时,遵循从上(高地址)往下(低地址)分配的原则
int max(int x,int y) // 变量 x 和 y 存储在max()函数的栈中
{
int z; // 变量 z 存储在max()函数的栈中
z = x>y ? x:y;
return z; // 函数退出后,栈中的x、y 和 z 被系统回收
}
int main(void)
{
int a = 1; // 变量 a 存储在main()函数的栈中
int b = 2; // 变量 b 存储在main()函数的栈中
int m; //变量 m 存储在main()函数的栈中,未赋值因此其值为随机值
m = max(a, b);
}
函数调用时代码的执行流程
技术要点:
栈内存相对而言是比较小的,不适合用来分配尺寸太大的变量
return 之后不可再访问函数的局部变量,因此返回一个局部变量的地址通常是错误的