C语言函数详解

2025-09-07 17:56:17

函数

c语言 面向过程(函数)定义返回值函数调用:

函数声明:局部变量:全局变量:static局部变量(静态变量)const变量static全局变量

递归函数: 自己(间接或直接)调用自己.函数指针:main 函数变长参数

c语言 面向过程(函数)

函数:把一部分特殊功能的代码封装成的过程模块. 作用:方便c语言的调用,并且函数是实现过程的一个部分 c语言的基本单位—函数.

定义

格式: 返回值类型 函数(参数列表,参数列表,…){ 函数体 } 注意:参数列表不是必须的,可以不传入参数. 函数中不可以再定义函数,但是可以调用函数. 函数参数:(类似于-定义变量) 形参:在定义或声明函数时的参数叫形参,形式参数调用前不占用内存空间,在实际调用时才开辟变量的内存空间.形参保存在栈.所以可以理解成局部变量. 实参:也叫做实际参数,占用内存空间,在函数调用的时候使用的参数.(所有形参都是实参的拷贝)

返回值

函数的返回值是返回给调用者,告诉调用者结果。 返回值值和返回值类型有关系,和return后面的类型无关,并且只可以返回一个返回值,不可以返回多个。 如果没有返回值,必须写void返回值类型,函数遇到return就结束。

函数调用:

格式: 返回值变量 = 函数名(实际参数); 函数分类:

库函数 自定义函数带参函数 无参函数数学函数 abs-求绝对值 pow-x的y次方 atof 目录函数 进程函数 诊断函数 操作函数

函数声明:

函数在使用前,需要告诉编译器,函数的形参,和返回值, 函数的声明就是直接写函数头,加分号. 例如: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局部变量(静态变量)

静态变量—长生不老药. 样式: static 类型 变量名 = 初始化值; 生命周期:不会因为函数结束而释放内存空间.从第一次调用函数时的变量定义,直到程序结束为止. 作用域:作用域还是在局部,不会发生改变 注意:只申请一次内存空间,只会初始化一次.

const变量

const变量是常变量.不可以修改的变量.两者都需要初始化 const修饰的局部变量生命周期和作用域不发生改变. 很多时候会定义const形参,说明形参是不可以修改的.

static全局变量

生命周期:不变,还是从程序开始到程序结束 作用域:限定在当前文件中.只可以在当前文件中使用.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 函数

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;

}