C函数
函数 即封装功能的容器
-
定义函数的基本格式:
return_type function_name( parameter list ) { body of the function }
-
**返回类型:**一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 void。
-
**函数名称:**这是函数的实际名称。函数名和参数列表一起构成了函数签名。
-
**参数列表:**参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数 即void 不填默认为void。
-
**函数主体:**函数主体包含一组定义函数执行任务的语句。
-
如果需要返回值 则在函数最后加入 return 返回值 ; return 会结束整个函数
-
不需要 则在 返回值类型处填入 void(空类型 )
-
函数需要被运行则需要 在入口 调用 才会被执行
局部变量:(栈区)
栈区系统自动申请和释放
定义时被称为入栈
释放时被称为出栈
在指定作用域 才能够起作用
- 例如
for(int i=0;i<10;i++){
则 i 只有在for循环内才能够被访问
在外 如果没有定义i则i不能被使用
}
在函数中定义的 变量 在其他函数中也不可以直接被使用
全局变量: (栈区)
在函数体外定义 该方法定义的变量可以被 定义位置 以下的 函数访问程序结束时才被释放
!全局变量和局部变量重名时 程序使用最近的变量值
静态变量(处于静态全局区)
静态全局区的变量只会被定义一次 整个程序结束后才会被释放
static int a=b
实验:
int main(void) {
for (size_t i = 0; i < 10; i++)
{
static int a = 10;
a++;
printf("%d\n", a);
}
return 0;
}
结果
可以看出a只被定义了1次 程序不停止则该变量不会被释放
函数的声明
函数需要 先声明函数 再调用即:
void hello_world(void);
int main(void) {
hello_world();
return 0;
}
void hello_world(void) {
printf("hello_world");
}
如果main前方不添加void hello_world(void);的话 则会提示函数未定义
地址
地址: 在定义变量 数组 函数等时系统会给他们分配内存区域(地址) 把这个数据放在这个地址上
取地址 &:&a
取a的地址编号
定义一个指针*: char *a;
不一定是char 还可能是 其他类型
指针变量:存储地址的变量
整型变量:存储整数的变量
地址传递
将变量的地址作为参数传递,传递过去的任何操作都会映射到源地址
void change_num(int *b) {
*b = 100;
}
int main(void) {
int a = 1;
change_num(&a);
printf("%d\n", a);
return 0;
}
结果:
结论:当地址被传递时 对地址的值进行修改,该修改作用于源于数据
传递数组
void print_arr(int a[],int len) {
for (size_t i = 0; i <len; i++)
{
printf("%d\n", a[i]);
}
}
int main(void) {
int b[] = { 1,2,3,654,6,4,98,465,4,64 };
int c[30] = { 1,65,54,531,56,456,564,654,6,4598,7,89, };
print_arr(b,sizeof(b)/sizeof(b[0]));
print_arr(c,30);
return 0;
}
函数的递归
在一个函数中 重复的调用函数本身
利用递归求阶乘
int recursion_fun(int a)
{
if (a == 1) {
return a;
}
return a*recursion_fun(a-1);
}
int main(void) {
printf("%d",recursion_fun(11));
return 0;
}
结果
静态变量实验:
void demo_static(void) {
static int a = 10;
if (a!=0)
{
a--;
demo_static();
}
printf("%d\n", a);
}
int main(void) {
demo_static();
return 0;
}
结果:
结论: 因为static在程序运行时只能够被定义一次 即第一次被定义时地址已经被确定 在每一次递归调用时操作的都是 a原来的地址 当a被等于0时 递归结束 函数以此退出并打印 全是0是因为在递归后输出 而不是在递归前输出 当退出时a已经等于0所以每一层的函数打印访问的都是0
猴子偷桃递归
int fun1(int apple) {
static int day = 1;
//apple = 1
//猴子吃桃
//有桃子若干 猴子每天吃一半的桃子+1个
// (n/2)-1= -((n/2)-1)/2-1
//第十天剩一个
//需要一个统计天数
//1 (1+1)*2 ((1+1)*2+1)*2
if (day == 10) {
return apple;
}
day++;
fun1((apple+1)*2);
}//
int main(void) {
printf("%d", fun1(1));
return 0;
}
结果
函数指针
函数指针是指向函数的指针变量。
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。
函数指针可以像一般函数一样,用于调用函数、传递参数。
函数指针变量的声明:
typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型
例子:
#include <stdio.h>
int add(int a, int b,int c) {
return a+b+c;
}
double max(double a, double b) {
return a > b ? a : b;
}
int main(void) {
// 返回类型 指针名 第一个参数类型 第二个参数类型 第三个参数类型 方法名称 &可以不用
int (*p) ( int, int, int) = & add;
printf("sum:%d\n", p(1,3,5));
double (*p2)(double, double) = max;
printf("sum:%.2lf\n", p2(1, 5));
return 0;
}
回调函数
函数指针作为某个函数的参数
即函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。
定义格式:
function_name(typedef1 (*fun_ptr)(typedef2 name2,typedef3 name3 ,...),...)
//typedef1 为函数返回类型
//typedef2 形参1变量类型
//typedef3 形参2变量类型
//*fun_ptr 为函数指针名称
//传递方式 function_name2为函数名称 且不能够带() 否则报错
function_name(function_name2)
#include <stdio.h>
void do_something(int a, int b, int (*add_num)(int a, int b)) {
printf("%d",add_num(a, b));
}
int get_num_sum(int a, int b) {
return a + b;
}
int main(void) {
do_something(3, 9, get_num_sum);
return 0;
}
结果:
结论 回调函数即函数指针变种 直接将函数传递给 其他函数 做参数
在被传递的函数中 可以直接使用 该函数指针 即相当于调用该方法