C语言——函数的基本语法,调用机制和注意事项

函数

文章目录

一.函数的定义

基本语法

image-20221023143055588

(1)形参列表:表示函数的输入
(2)函数中的语句:表示为了实现某一功能代码块
(3)函数可以有返回值,也可以没有, 如果没有返回值,返回类型 声明为 void 。

二.头文件

1.需求:在不同的文件中,需要去调用其它文件的定义的函数

2.基本概念:

(1)头文件是扩展名为 .h 的文件,包含了 C 函数声明和宏定义,被多个源文件中引用共享。有两种类型的头文件:程序员编写的头文件和C标准库自带的头文件

(2)在程序中要使用头文件,需要使用 C 预处理指令 #include 来引用它。前面我们已经看过 stdio.h 头文件,它是C标准库自带的头文件

(3)#include叫做文件包含命令,用来引入对应的头文件(.h文件)。#include 也是C语言预处理命令的一种。

(4)#include 的处理过程很简单,就是将头文件的内容插入到该命令所在的位置,从而把头文件和当前源文件连接成一个源文件,这与复制粘贴的效果相同。但是我们不会直接在源文件中复制头文件的内容,因为这么做很容易出错,特别在程序是由多个源文件组成的时候

(5)建议把所有的常量、宏、系统全局变量和函数原型写在头文件中,在需要的时候随时引用这些头文件

3.工作原理

image-20221024195613570

image-20221024195745240

4.文件的注意事项和细节说明

(1)引用头文件相当于复制头文件的内容

(2)源文件的名字 可以不和头文件一样,但是为了好管理,一般头文件名和源文件名一样

(3)C 语言中 include <> 与include ""的区别

image-20221024202604579

(4)一个 #include 命令只能包含一个头文件,多个头文件需要多个 #include 命令

(5)同一个头文件如果被多次引入,多次引入的效果和一次引入的效果相同,因为头文件在代码层面有防止重复引入的机制

(6)在一个被包含的文件(.c)中又可以包含另一个文件头文件(.h)

(7)不管是标准头文件,还是自定义头文件,都只能包含变量和函数的声明,不能包含定义,否则在多次引入时会引起重复定义错误(!!!)

三.函数调用机制

image-20221024203103441

函数调用规则:

1.当调用(执行)一个函数时,就会开辟一个独立的空间(栈)

2.每个真空间是相互独立

3.当函数执行完毕后,会返回调用函数位置,继续执行

4.如果函数有返回值,则将返回值赋给接收的变量

5.当一个函数返回后,该函数对应的栈空间也就销毁

举例说明

image-20221023235749165

四.函数的递归调用

(1)基本介绍

一个函数在函数体内又调用了本身,我们称为递归调用

(2)递归执行的流程和机制

image-20221024150110834
#include <stdio.h>
int test(int n){
	if(n>2){
		test(n-1);
	}
	printf("\nn=%d",n);
}

int main(){
	test(4);
}
image-20221024150247695

(3)函数递归需要遵守的重要原则:

  • 执行一个函数时,就创建一个新的受保护的独立空间(新函数栈)
  • 函数的局部变量是独立的,不会相互影响
  • 递归必须向退出递归的条件逼近,否则就是无限递归,死龟了:)
  • 当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返给谁

(4)练习

题1:斐波那契数

请使用递归的方式,求出斐波那契数1,1,2,3,5,8,13…

给你一个整数n,求出它的斐波那契数是多少?

#include <stdio.h>
int fbn(int n){
	if(n==1 || n==2){
		return 1;
	}else{
		return fbn(n-1)+fbn(n-2);
	}
}
int main(){
	int res = fbn(7);
	printf("\nres=%d",res);
	getchar();

}
题2:求函数值

已知 f(1)=3; f(n) = 2*f(n-1)+1;

请使用递归的思想编程,求出 f(n)的值?

#include <stdio.h>
int f(int n){
	if(n==1){
		return 3;
	}else{
		return 2*f(n-1)+1;
	}
}
int main(){
	//已知 f(1)=3; f(n) = 2*f(n-1)+1; 
	//请使用递归的思想编程,求出 f(n)的值
	int res2 = f(2);
	printf("\nres2=%d",res2);
	getchar();
}
题3:猴子吃桃子问题

有一堆桃子,猴子第一天吃了其中的一半,并再多吃了一个!以后每天猴子都吃

其中的一半,然后再多吃一个。当到第十天时,想再吃时(还没吃),发现只有

1个桃子了。问题:最初共多少个桃子

#include <stdio.h>

int peach(int day){
	if(day==10){
		return 1;
	}else{
		return (peach(day+1)+1)*2;
	}
}
int main(){
	//分析:
	//1.day=10 有1个桃子
	//2.day=9 有(day10+1)*2=(1+1)*2=4
	//2.day=8 有(day9+1)*2=(4+1)*2=10
	int peachNum = peach(1);
	printf("\n 第一天有%d个桃子",peachNum);
	getchar();
	
}

五.函数使用注意事项和细节

(1) 函数的形参列表可以是多个。
(2) C语言传递参数可以是值传递(pass by value),也可以传递指针(a pointer passed by value)也叫引用传递。
(3) 函数的命名遵循标识符命名规范,首字母不能是数字,可以采用 驼峰法 或者 下 划线法 ,比如 getMax() get_max()。
(4)函数中的变量是局部的,函数外不生效【案例说明】
(5)基本数据类型默认是值传递的,即进行值拷贝。在函数内修改,不会影响到原来的值。【案例演示】
//基本数据类型是值传递,即进行值拷贝。在函数内修改,不会影响到原来的值
void f2(int n){
	n++;
	printf("\nf2中的n=%d",n);//n=10
}

void main(){
	//函数中的变量是局部的,函数外不生效
	//printf("num=%d",num);
	
	int n=9;
	f2(n);
	printf("\nmain函数中 n=%d",n);//9
	getchar();
}
(6)如果希望函数内的变量能修改函数外的变量,可以传入变量的地址&,函数内以指针的方式操作变量。从效果上看类似引用(即传递指针)【案例演示:】
//如果希望函数内的变量能修改函数外的变量,可以传入变量的地址&,函数内以

//指针的方式操作变量。从效果上看类似引用(即传递指针)【案例演示:】

void f3(int *p){
	(*p)++;//修改会对函数外的变量有影响
}

void main(){
	//函数中的变量是局部的,函数外不生效
	//printf("num=%d",num);
	
	int n=9;
	f3(&n);
	printf("\nmain函数中 n=%d",n);//10
	getchar();
}
(7)C语言 不支持函数重载
(8)C语言支持可变参数函数
#include <stdio.h>
#include <stdarg.h>

//说明
//num 表示传递的参数格式
//... 表示可以传递多个参数和num一致即可
int fun(int num,...)//可变函数,即参数的个数可以不确定,使用...表示
{
	int i,totalSum;//totalSum 一定初始化
	int val = 0;
	va_list v1; //v1实际是一个字符指针,从头文件可以找到
	va_start(v1,num);//使v1指向可变列表中第一个值,即num后的第一个参数
	printf("*v=%d\n",*v1);
	for(i=0;i<num;i++)
	{
		val =va_arg(v1,int); //该函数返回v1指向的值,并使v1向下移动一个int距离
		printf("val=%d\n",val);//val=10 val=30 val=60
		totalSum += val;
	}
	va_end(v1);//关闭v1指针,使其指向null
	return totalSum;
}

void main(){
	int res =fun(4,13,14,15,16);
	printf("和是=%d",res);
	getchar();
}
对指针指向的变量赋值的机制分析:

image-20221024194412528

六.函数参数的传递方式

(1)基本介绍

C语言传递参数可以是值传递(pass by value),也可以传递指针(a pointer passed by value)也叫传递地址或者 引用传递。

(2)两种传递方式

  • 值传递
  • 引用传递(传递指针,地址)

其实,不管是值传递还是引用传递,传递给函数的都是变量的副本,不同的是,值传递的是值的拷贝,引用传递的是地址的拷贝,一般来说,地址拷贝效率高,因为数据量小,而值拷贝决定拷贝的数据大小,数据越大,效率越低。

(3)使用特点

image-20221024205537095

image-20221024205555404

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值