嵌入式学习Day3-4(2024.03.13-14)
C语言函数
函数定义
全局变量和局部变量
全局变量 | 局部变量 | 静态局部变量 | |
---|---|---|---|
作用域 | 定义于函数外,同一文件中的任何位置都可使用 | 定义于函数内,函数体内使用 | 函数体内使用 |
生命周期 | 定义时分配空间,main函数结束时系统回收空间 | 定义时分配空间,函数调用结束时系统回收空间 | 在函数内定义,函数调用后随main结束而被回收 |
初始值 | 0 | 随机 | 0 |
#include<stdio.h>
int a=10; //全局变量
/*对全局变量操作*/
void f_a(){
a++;
printf("a = %d \n",a);
}
/*对局部变量操作*/
void f_b(){
int b=10;
b++;
printf("b = %d \n",b);
}
int main(void){
f_a(); //全局变量生命周期随main函数,会一直加
f_a();
f_a();
printf("=============================================\n");
f_b();//局部变量生命周期随函数调用,每次都为11
f_b();
f_b();
}
#include<stdio.h>
/*对静态局部变量操作*/
void f_b(){
static int b=10;
b++;
printf("b = %d \n",b);
}
int main(void){
f_b();//静态局部变量生命周期随函数调用,main函数结束后才回收
f_b();
f_b();
}
函数参数传递
值传递
#include<stdio.h>
//值传递,形参为具体类型
void f_b(int value){
value++; //值传递,不会改变实参的值,相当于函数内定义了一个局部变量value,将实参值赋给局部变量value
printf("value = %d \n",value);
return ;
}
int main(void){
int value1=10;
f_b(value1);//value1 为实参,值传递时并不会被改变,形参value接受实参vlaue1的值
printf("vlaue1 = %d \n",value1);
return 0;
}
地址传递
#include<stdio.h>
//地址传递,形参为地址类型
void f_b(int *value){
*value+=1; //地址传递,传递变量地址,通过对指针的操作,直接改变地址指向的内存的值
return ;
}
int main(void){
int value1=10;
f_b(&value1);//参数为value1的地址,通过指针改变value1的值
printf("vlaue1 = %d \n",value1);
return 0;
}
数组参数
/*数组作为参数时实际上传的是参数首地址*/
void fun(int []){
//statement
}
void fun1(int *p){
//statement
}
int main(){
int a[10]={0};
fun(a);
fun1(a); //数组名为首地址,数组名可看作一个指针变量
}
函数参数总结
不管是值传递还是参数传递,其本质都是形参与实参之间值的复制。不同之处在于值传递,参数传递后形参和实参就没有联系了,对形参的操作不会影响实参。但是,地址传递传递的是实参地址,实参和形参指向同一个地址,通过对指针的操作,形参和实参都可以通过地址修改同一个内存地址中的值
指针函数
指针函数是一个函数,返回值为一个地址
定义: type * fun(type a,type b…)
返回值是地址时要注意,若返回的地址是函数内的局部变量应该使用static 修饰变量,否则会存在野指针问题==》函数调用完后,局部变量被系统回收,但是却返回了局部变量的地址,此时该地址不合法。
#include<stdio.h>
int * fun_a(){
int a[10]={0};
return a; //野指针
}
int main(){
int * p=fun_a();
}
#include<stdio.h>
int * fun_a(){
static int a[10]={0};
return a; //使用static修改局部变量的生命周期后编译不报错
}
int main(){
int * p=fun_a();
printf("%d \n",sizeof(p));
}
函数指针
函数指针本质上是一个指针,保存函数的地址。通过函数指针可以调用我们需要的函数
定义: 函数返回值数据类型 (*指针变量名)(类型1 参数1,类型2 参数2…);
(1)函数名代表函数的首地址(联系数组,数组指针)
(2)定义函数指针时可以省略参数
#include<stdio.h>
/*函数指针*/
void fun_a(int v1,char * v2){
printf("调用函数fun_a()\n");
printf("输入的参数是 v1= %d ,v2= %s \n",v1,v2);
return ;
}
int main(){
char buf[20]="hello world";
void (*p)(int,char *)=fun_a; //将函数地址赋值给函数指针
fun_a(1998,buf); //通过函数名调用函数
printf("=========================================================\n");
p(2024,buf); //通过函数指针调用函数
printf("打印函数名和函数指针指向的地址 &fun_a=%p &p=%p\n",fun_a,p);
}
root@wangjudealy:/learn# gcc 0314.c
root@wangjudealy:/learn# ./a.out
调用函数fun_a()
输入的参数是 v1= 1998 ,v2= hello world
=========================================================
调用函数fun_a()
输入的参数是 v1= 2024 ,v2= hello world
打印函数名和函数指针指向的地址 &fun_a=0x56109500a189 &p=0x56109500a189
回调函数
将函数指针作为参数传递给另一个函数,并在另一个函数体内通过函数指针调用函数。
#include<stdio.h>
/*数组指针*/
void fun_a(int v1,char * v2){
printf("调用函数fun_a()\n");
printf("输入的参数是 v1= %d ,v2= %s \n",v1,v2);
return ;
}
void fun_b(void (*q)(int,char *)){
printf("调用函数fun_b()\n");
q(2024,"hello");//通过函数指针参数调用函数
}
int main(){
fun_b(fun_a);
}
root@wangjudealy:/learn# gcc 0314.c
root@wangjudealy:/learn# ./a.out
调用函数fun_b()
调用函数fun_a()
输入的参数是 v1= 2024 ,v2= hello
递归函数
在函数体中调用函数自己
一般递归函数要设置一个条件,作为结束递归的条件
#include<stdio.h>
/*求阶乘函数*/
int t=0;
int fun_a(int num){
if(num>1){
printf("递归 %d 次,num=%d\n",++t,num);
return num*fun_a(num-1); //此处使用num*fun_a(--num)会少循环一次
}
else {
printf("最后一次递归\n");
return 1; //递归出口 ==》满足条件时不在递归
}
}
int main(){
int p = fun_a(4);
printf("%d \n",p);
return 0;
}