函数:把一部分特殊功能的代码封装成的过程模块.
作用:方便c语言的调用,并且函数是实现过程的一个部分
c语言的基本单位—函数.
格式: 返回值类型 函数(参数列表,参数列表,…){ 函数体 }
注意:参数列表不是必须的,可以不传入参数.
函数中不可以再定义函数,但是可以调用函数.
函数参数:(类似于-定义变量)
形参:在定义或声明函数时的参数叫形参,形式参数调用前不占用内存空间,在实际调用时才开辟变量的内存空间.形参保存在栈.所以可以理解成局部变量.
实参:也叫做实际参数,占用内存空间,在函数调用的时候使用的参数.(所有形参都是实参的拷贝)
函数的返回值是返回给调用者,告诉调用者结果。
返回值值和返回值类型有关系,和return后面的类型无关,并且只可以返回一个返回值,不可以返回多个。
如果没有返回值,必须写void返回值类型,函数遇到return就结束。
格式: 返回值变量 = 函数名(实际参数);
函数分类:
函数在使用前,需要告诉编译器,函数的形参,和返回值,
函数的声明就是直接写函数头,加分号.
例如:int add(int ,int );
上例中,函数参数只有形参类型,没有形参名,这种方式叫哑元.
#include
double er(double , int arr[10]); \\返回值为double的er函数声明
//函数的声明以及定义
void fun(int m)
{
printf("拿着%d块钱,酱油花了4块钱,剩下%d块钱\n", m, m - 4);
printf("拿着钱往回走,需要给我结果了....\n");
m = 200;
m = max(10, 20, 30);
}
/*
写一个函数,用来得到三个数中的最大值
*/
int max(int x, int y, int z)
{
if (x > y)
{
if (x > z)
{
return x;
}
else
{
return z;
}
}
else
{
if (y > z)
{
return y;
}
else
{
return z;
}
}
}
/*
函数: int add(int x,int y);
作用: 计算两个函数的和
参数: x 第一个加数
y 第二个加数
返回值: 返回两个数的和
*/
int add(int x, int y)
{
return x + y;
}
int main()
{
int x = 10;
int y = add(10,20); //add的函数调用
printf("x + y= %d\n", add(100, 20));
y = max(10, 20, 30); //函数求最大值的调用
//er(10, 20);
printf("y = %d\n", y);
return 0;
}
//函数er的定义
double er(double x, int arr)
{
return 0.0;
}
作用域:在局部,在大括号范围之内,超过范围其他地方不可识别
生命周期:定义时开始到函数大括号结束
作用域:在任何地方都可以识别和使用
生命周期:程序运行到程序结束
静态变量—长生不老药.
样式: static 类型 变量名 = 初始化值;
生命周期:不会因为函数结束而释放内存空间.从第一次调用函数时的变量定义,直到程序结束为止.
作用域:作用域还是在局部,不会发生改变
注意:只申请一次内存空间,只会初始化一次.
const变量是常变量.不可以修改的变量.两者都需要初始化
const修饰的局部变量生命周期和作用域不发生改变.
很多时候会定义const形参,说明形参是不可以修改的.
生命周期:不变,还是从程序开始到程序结束
作用域:限定在当前文件中.只可以在当前文件中使用.c_day15.c的文件中使用.
#include
#include
static int x = 123; //static全局变量
void fun(const int xx) //形参就是局部变量
{
static int danny = 12;//只申请一次内存空间,只会初始化一次
//xx = 12;
printf("danny = %d\n", danny++);
return ;
}
//拷贝了x和y的地址,没有拷贝x和y的值.通过地址修改了内存空间
void pfun(int* xx,int* xy)
{
int temp = *xx;
*xx = *xy;
*xy = temp;
printf("内部 x = %d,y = %d\n",*xx,*xy);
}
void pMalloc(int** p)
{
*p = (int*)malloc(sizeof(int));
}
//指针函数.一个普通函数,返回指针.
int* pReturn(int* p)
{
p = (int*)malloc(sizeof(int));
return p;
}
//数组当做函数参数时,
int Pfun(int arr[],int size)
{
arr[1] = 123;
printf("sizeof(arr) =%d\n", sizeof(arr));
arr[size - 1] = 10;
return 0;
}
int main()
{
int danny = 12;
fun(10);
fun(10);
printf("x = %d", danny);
int x = 12;
int y = 123;
int* px = &x;
int* py = &y;
pfun(px, py);
printf("外面x = %d, y = %d", x, y);
int* pNull = NULL;
pMalloc(&pNull);
*pNull = 1234;
int *p = NULL;
int *pp = pReturn(p);
*pp = 123;
int arr[10] = { 1, 2, 3, 4, 54, 5, 6 };
Pfun(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
弊端: 内存消耗比较多.每次函数调用都会压栈,消耗内存空间
好处:可读性好,代码简洁.
递归满足两个条件:
- 必须有返回(结束条件)
- 一定要有通配公式. 1 1 2 3 5
#include
#include
//递归函数实例
int Fun(int x){ //参数压栈
printf("第%d次调用fun函数\n", x);
if (x < 5)
{
Fun(x+1);
}
printf("函数%d次返回\n", x);
return 0;
}
//斐波那契数列的第n项1 1 2 3 5
int fplq(int x)
{
if (x == 1 || x == 2)
{
return 1;
}
else
{
return fplq(x - 1) + fplq(x - 2);
}
}
int main()
{
Fun(1); //调用递归示例函数,查看递归的执行顺序
printf("x = %d",fplq(5));
return 0;
}
函数指针:一个指针指向于函数
格式:返回值类型 (*指针名)(参数列表);
typedef 返回值类型 (*指针名)(参数列表); typedef 取别名 定义的是指针类型
注:一个函数名确定了函数的地址
main 函数结束后的调用:atexit()
先注册函数,在main函数结束后,会直接调用注册后的函数
注册:告诉才做系统有这样的一个函数,需要调用
当main函数结束后,操作系统自动调用注册的函数,叫回调
void (__clrcall* _Function)(void x) 这是一个函数指针 没有返回值的类型
main函数的参数 注: 有三个参数 第三个参数为环境变量值
格式:int main(int argv,char *argc[])
参数 :
int argv 说明函数参数的个数
char* argc[]参数列表,参数的实际内容,字符串数组 char* 就是字符串
main函数参数使用的三种方式:
- 直接拖拽文件到exe上,会把文件路径当作参数
- 在项目–>属性–>配置属性–>命令参数,直接设置,参数用空格隔开
- 在cmd中(控制台命令窗口),拖拽exe到cmd,然后空格添加参数
函数中的变长参数:函数的参数不确定,数量是可变的。
格式:返回值 函数名(第一个参数,…)
C语言中通过3个语句来处理变长参数
va_start(ap,v) //宏–>理解成函数 在头文件stdarg中
作用:做初始化处理,告诉编译器有变长参数来了
第一个参数ap:可变长参数列表的地址,相当于第一个参数,实际上是va_list变量
第二个参数v:确定的参数,一般为函数的第一个参数,一般就是count
va_arg(ap,t)
作用:得到变长参数的内容
第一个参数ap:实际就是va_list变量
第二个参数t:传入参数的类型
va_end(ap)
作用:结束变长参数,告诉编译器变长参数的处理结束了
第一个参数ap:实际就是va_list变量
va_list 是char*型
注:
#include
#include
#include
typedef int (*pFun)(int x, int y, int z); //函数指针 typedef 取别名 实际上别名为pFun 为函数指针类型
typedef int limitfly;
int f(int a, int b, int c)
{
return a + b + c;
}
int fun1()
{
printf("danny 老师在开车,此车四平八稳。");
}
int fun2()
{
printf("danny 老师即将开车,大家尽快上车。");
}
//计算所有数据的和 count 形参的个数
int add(int count, ...)
{
va_list vl; //用来存储所有的参数
int sum;
va_strat(vl,count); //初始化
for (int i = 0; i < count; i++)
{
int temp = va_arg(vl, int);
sum += temp;
}
va_end(vl);
return sum;
}
int main(int argv,char *argc[])
{
int(*arr)[10]; //数组指针
pFun px = f; //函数指针的使用 这里的px是函数指针 指向的是函数f 类型不一样的无法指向
int m = px(1, 2, 3);
printf("argv=%d\n", argv);
printf("argc[0]=%s\n", argc[0]);
int num = add(4,20,50,60,80);
printf("num=%d\n", num);
atexit(fun1);// 此处的fun1和fun2就是注册函数
atexit(fun2); //函数结束后 会以压栈的方式(即先进后出的原则)先后打印fun2和fun1
return 0;
}