函数是什么?为什么要引入函数?
C语言中存在一个所谓的主函数,主函数是程序的入口
程序是实现具体逻辑功能的代码程序,在程序设计的过程中会存在一些反复被使用的逻辑单元
函数是用来封装具有某种功能逻辑的代码程序的模块,所以C语言提供了一个功能,允许我们将常用的代码以固定的格式封装(包装)成一个独立的模块,只要知道这个模块的名字就可以重复使用它,这个模块就叫做函数(Function)。
函数的优点:
使程序变得更简短而清晰
有利于程序维护
可以提高程序开发的效率
提高了代码的重用性
int num=10,num1=11,sum=0;
sum=num+num1;
函数的分类:
函数的来源:
第一类:C语言标准函数
C语言中提供的常用函数接口
第二类:第三方库函数
有第三方厂商提供,此类接口一般是第三方根据设计需求提供的接口
第三类:自定义函数
开发人员自行设计
根据函数头:
有参无返
有参有返
无参有返
无参无返
函数的原型:
int printf(const char *format, …);
函数的定义格式:
注意:函数的定义可以在主函数的上面也可以在主函数的下面
ReturnType FunctionName( parameter, parameter,.......)
{
function body;
return ReturnVale;
}
函数头:
ReturnType FunctionName( DataType parameter, DataType parameter,…)
ReturnType :返回值类型
决定了函数返回值的数据类型,同时也是函数的对外输出
可以为任意数据类型,但注意,一般不会采用数组作为返回值
FunctionName :合法标识符
数字字母下划线
数字不能做开头
不能和关键字重名
不能和C语言库函数重名
( ):形参标识,即使没有形参也不能省略括号
parameter:形参列表
形参列表中对形参的个数一般不做限定可以为0,也可以为多个
形参特点:形参不占据空间,只有在接收实参的时候才会分配空间
形参:形参指的是在定以函数的时候括号中声明的形式参数
实参:实参是在调用函数的时候传递给函数的实际参数
形参和实参的关系:
形参和实参存在传递关系,形参用来接收函数调用传递的实际参数,具有不可逆性
实参 --- 形参传递
注意事项:
1、定以函数的时候形参不会被分配空间,只有在函数调用的时候才会通过实参
为形参分配空间,函数调用结束,空间释放
2、函数定义的时候声明的形参决定了实际参数传递的顺序、类型、个数
3、若实参和形参的数据类型不匹配,编译器会进行隐式转换,将实际参数的类型
隐式转换为形参的数据类型
函数体:
{}:一般{}括起来的为上面一条控制语句或者函数的逻辑单元,从{开始到}结束
function body;
函数体中是实现功能逻辑的代码程序
返回值:
return ReturnVale;
可以是表达式,可以是数据
函数的输出,同时也决定了函数退出操作
C语言程序的基本单位 函数
函数定义需要考虑以下几个问题:
1、函数是否有输出
有输出必须有返回值
判断返回数据的类型
2、函数是否有输入
先确定是否有输入
在确定输入数据的类型
在确定输入数据的数量
3、函数名尽量和函数的功能贴近
当函数定义在主函数上的时候,可以直接调用
当定义在函数下面的时候需要先声明后调用
函数声明:
ReturnType FunctionName(形参列表);
提示:在声明函数的时候,可以省略形参名
声明的位置一般在主函数和头文件之间
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//int Add(int a,int b);
int Add(int ,int );
int main()
{
printf("%d\n",Add(5,5));
return 0;
}
int Add(int a,int b)
{
return a+b;
}
函数的调用:
ReturnType var= FunctionName(实参列表);
#include <stdlib.h>
#include <time.h>
int Add(int a,int b)
{
return a+b;
}
int main()
{
printf("%d\n",Add(5,5));
return 0;
}
有参无返:
void FunctionName( parameter, parameter,.......)
{
function body;
}
有参有返
ReturnType FunctionName( parameter, parameter,.......)
{
function body;
return ReturnVale;
}
无参有返
ReturnType FunctionName()
{
function body;
return ReturnVale;
}
无参无返
void FunctionName()
{
function body;
}
注意:函数不能嵌套定义,但是能够嵌套调用
编译一个函数可以排序任意个元素数组的顺序
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void sort(int *array,int num)
{
int i=0,j=0,tmp=0;
for(i=0;i<num;i++)
{
for(j=0;j<num-1-i;j++)
{
if(array[j]>array[j+1])
{
tmp=array[j];
array[j]=array[j+1];
array[j+1]=tmp;
}
}
}
for(i=0;i<num;i++)
{
printf("array[%d]=%d ",i,array[i]);
}
printf("\n");
}
int main()
{
int i=0;
time_t times=0;
int num[20]={0};
times=time(NULL);
srand(times);
for(i=0;i<20;i++)
{
num[i]=rand()%100;
}
for(i=0;i<20;i++)
{
printf("num[%d]=%d ",i,num[i]);
}
printf("\n");
sort(num,20);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int sum(int small,int big)
{
int i=0,sum=0;
for(i=small;i<=big;i++)
{
sum+=i;
}
return sum;
}
int main()
{
int num=0;
num=sum(1,100);
printf("num=%d\n",num);
return 0;
}
定义两个函数,计算1! + 2! + 3! + … + (n-1)! + n!的和。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
unsigned long Factorial(int n)
{
int i=0,sum=0,s=1;
for(i=1;i<=n;i++)
{
s*=i;
sum+=s;
}
return sum;
}
int main()
{
unsigned long num=0,sum=0;
scanf("%ld",&num);
sum=Factorial(num);
printf("sum=%ld\n",sum);
return 0;
}
参数传递的方式:
值传递:
值传递指的是将实参的值传到形参的地址空间(形参在接收实际参数的时候会被分配空间),结束后会释放空间,即结果被释放
这种方式使用变量、常量、数组元素作为函数参数,实际是将实参的值复制到形参相应的存储单元中,即形参和实参分别占用不同的存储单元,这种传递方式称为“参数的值传递”或者“函数的传值调用”。
值传递的特点是单向传递,即主调函数调用时给形参分配存储单元,把实参的值传递给形参,在调用结束后,形参的存储单元被释放,而形参值的任何变化都不会影响到实参的值,实参的存储单元仍保留并维持数值不变。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void swap(int a,int b)
{
int tmp=0;
tmp=a;
a=b;
b=tmp;
printf("a=%d\tb=%d\n",a,b);
}
int main()
{
int m=10,n=20;
swap(m,n);
printf("m=%d\tn=%d\n",m,n);
return 0;
}
地址传递:
地址传递指的是将实参的地址传递给形参,在函数中通过操作实参的地址达到操作实参的目的
这种方式使用数组名或者指针作为函数参数,传递的是该数组的首地址或指针的值,而形参接收到的是地址,即指向实参的存储单元,形参和实参占用相同的存储单元,这种传递方式称为“参数的地址传递”。
地址传递的特点是形参并不存在存储空间,编译系统不为形参数组分配内存。数组名或指针就是一组连续空间的首地址。因此在数组名或指针作函数参数时所进行的传送只是地址传送,形参在取得该首地址之后,与实参共同拥有一段内存空间,形参的变化也就是实参的变化。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void swap(int *a,int *b)
{
int tmp=0;
tmp=*a;
*a=*b;
*b=tmp;
printf("a=%p\tb=%p\n",a,b);
printf("*a=%d\t*b=%d\n",*a,*b);
}
int main()
{
int m=10,n=20;
printf("&m=%p\t&n=%p\n",&m,&n);
swap(&m,&n);
printf("m=%d\tn=%d\n",m,n);
return 0;
}
变量的作用域:
变量的分类:
全局变量:定义在所有函数外部的变量
局部变量:定义在任意函数内部的变量
全局变量和局部变量能否重名:
可以重名,在局部内,局部变量有效
作用域:指的是变量有效的范围
全局变量:作用域是整个模块
局部变量:作用域是被定义的函数内部
生命周期:指的是变量存活的时间
变量的一般在定义之后开始有效,直到函数结束或者程序结束
全局变量:从定义到程序结束
局部变量:从定义到函数结束
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//int Add(int a,int b);
int Add(int ,int );
int main()
{
printf("%d\n",Add(5,5));
return 0;
}
int Add(int a,int b)
{
int sum=a+b;
return sum;
}