C语言学习---函数

引入

关于函数,第一次听到这个名字应该是在数学学习时吧。而C语言中也有函数这一概念,不过此函数非彼函数。

函数的概念

函数的英语表达为function,这样我们就可以把函数理解成一个完成某项特定任务的一小段代码,这段代码在C语言中有着特定的写法和调用方法。

C语言的程序事实上是由无数个小的函数组合而成的,也就是说把一个大的任务分解成若干个较小的函数来完成。

函数的分类

(1)库函数

(2)自定义函数

库函数

库函数的概念

C语言标准中规定了C语言中的语法规则,但C语言并不提供库函数;C语言的国际标准ANSI C规定了一些常用的函数标准,称为标准库,不同的厂商根据C语言标准就给出了一系列函数的实现,这些函数称为库函数。

之前所学的printf、scanf都是库函数,这些函数都是现成的,学会后就可以直接使用。这些库函数在一定程度上提升了效率。

库函数的使用

库函数是在标准库中对应的头文件中声明的,所以库函数的使用,一定要包含对应的头文件,否则会出现一些问题。

自定义函数

函数的语法形式

函数的返回类型   函数名(形式参数){

}

{}括起来的是函数体

我们可以把函数联想成一个加工厂,工厂获得原材料通过加工得到产品。函数也是这样,函数获得参数,经过在函数内计算得出相关结果。

但是与工厂不同的是,工厂必须要有原材料才能有产品,而函数获得的参数可以是0个也可以是无数个。函数也可能没有计算结果,即没有返回值的情况。

由此我们可以对函数的语法有更深的理解 

(1)函数的返回类型:用来表示函数计算结果的类型,但有时函数的返回类型可以是void,表示什么都不返回。

(2)函数名:函数名就和每个人的名字一样,有了名字方便称呼和区别,函数有了名字就方便调用,所以在给函数起名字的时候要是有意义的名字。

(3)形式参数:函数的参数可以是void。如果有参数,都要交代清楚参数的名字,类型和个数。

(4)函数体:函数体就是完成计算的过程

上面提到了参数和返回类型为0的情况,以下是一个例子

形参和实参

函数中的参数分为实参和形参

实参:

实际参数就是真实传递给函数的参数

形参:

如果我们定义了一个函数,不去调用的话 ,函数中的参数只是形式上存在的,不会向内存申请空间。形参只有再被调用 的过程中为了存放实参传递过来的值。才会向内存中申请空间,这个过程就是形参的实例化。

实参与形参的关系:

实参和形参各自是独立的内存空间,实参和形参的传递通常是单向的值传递,即从实参传递到形参。但是也存在通过指针等方式实现“双向传递”的情况。

单向值传递

 当简单数据类型(如 int 、 float 等)作为实参传递给函数时,传递的是实参的值的副本。在函数内部对形参的修改不会影响到实参。例如:

#include <stdio.h>

void modifyValue(int num) {
    num = 100;
}

int main() {
    int a = 10;
    modifyValue(a);
    printf("a的值为:%d\n", a); 
    return 0;
}

上述代码中, main 函数中的 a 作为实参传递给 modifyValue 函数的形参 num ,在 modifyValue 函数中修改 num 的值为100,但不会影响 main 函数中 a 的值,输出仍为10。

指针实现“双向传递”的情况

当实参是指针类型时,传递的是指针变量的值(即地址) ,函数内部可以通过地址的访问和修改指针所指向的变量的值,从而达到修改实参的目的。例如:

#include <stdio.h>

void modifyValue(int *ptr) {
    *ptr = 100;
}

int main() {
    int a = 10;
    int *p = &a;
    modifyValue(p);
    printf("a的值为:%d\n", a); 
    return 0;
}

在main函数中定义了一个变量a和指向a的指针p,将p作为实参传递给所定义的函数,在函数内部通过指针ptr修改了a的值 

关于return的那些事

在函数中,我们会经常看到return语句,那你对return的了解有多少呢?

return语句的一般形式是

return  表达式   或者是   return  (表达式)

(1)return后面可以是一个数也可以是一个表达式,如果是表达式的话则会先执行表达式,再返回表达式的值

(2)return后面也可以啥也没有,直接写return,这样的一般是返回类型是void的情况

(3)return语句执行后,函数彻底返回,后面的代码不会执行,可以认为它有强制结束的作用。这里需要和break语句区分开

从以上对比可以看出,break 能直接跳出循环语句,而return则是直接结束整个主函数的运行,后面不会打印c和i的值。

(4)当return返回的值和函数返回类型不一致时,系统自动将返回的值隐式转换为函数的返回类型

(5)函数的返回类型如果不写,将自动默认为int类型

如: Add   (int   a,int  b)

我们在函数定义时没有写它的返回类型,那么它的返回类型将默认为int 类型

(6)如果有返回类型,但是没有写返回类型的值,那么函数的返回值是未知的 

(7)return语句可以有多个,可以在函数体的任何位置,但是每次调用函数时只能有一个return语句被执行,只能有一个返回值。

(8)return 0表示函数正常退出,即当return语句提供了一个返回值时,这个值就成为函数的返回值。return 1表示异常退出,返回主调函数处理,继续向下执行出现异常或需要提前停止时用return-1表示。

好了,以上就是关于return的知识点,可能不太全面,欢迎各位进行补充学习

数组做函数的参数

我们在用函数解决有关问题时,难免会碰到含有数组的情况,这就不可避免的会将数组作为参数传递给函数。那么我们要如何处理呢?

假设我们现在定义一个函数对数组进行处理,打印出数组中的所有元素,这样的函数应该怎样定义和使用呢?

 

这里出现了数组作为参数时一个常见的错误。我们在进行传递时,使用的是a[0],a[0]表示的是数组a中的第一个元素,它是一个int类型的值。而我们使用所定义的函数时,实际上是将一个int类型的值作为第一个参数传递给Print函数。

但是Print函数所期望的第一个参数是一个int类型的数组,这样的传递会导致类型不匹配,无法按照我们所预期的那样处理数组中的元素。

所以在数组传参时只传数组名即可(在C语言中,数组名在大多数情况下会被自动转换为指向数组首元素的指针)

这样就可以完成预期功能了!

关于一维数组的形参,我们可以省去数组的大小,这样也不会出错,例如:

这两种写法都是对的。

下面来总结一下有关数组传参的几个重要知识:

(1)函数的形参个数要与实参个数相匹配

(2)函数的实参是数组,形参也可以写成数组形式的

(3)如果形参是一维数组,数组的大小可以省略不写

(4)如果形参是二维数组,行可以省略,但是列不可以省略

(5)数组传参时,形参是不会创建新的数组的,形参操作的数组和实参是同一个数组

函数的嵌套调用和链式访问

嵌套调用

函数的嵌套调用就是函数之间的相互调用。就好比我们玩乐高一样,每一个函数就像是一块小小的零件,只有相互配合才能搭建出精美的乐高玩具。函数的嵌套调用也是如此,正是因为函数之间有效的相互调用最后才写出了大型的程序。不过需要注意的是,函数的定义不可以嵌套。

一个简单的例子,我们现在想知道某一年的某一月有多少天,每一月的天数几乎是固定的,但是2月是个例外,那么我们首先必须确定是闰年还是非闰年,然后再进行判断。 

#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int is_leap_year(int year) {
	if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) {
		return 1;
	}
	else {
		return 0;
	}
}
int days_of_month(int year,int month) {
	int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	int day = days[month];
	if (is_leap_year(year) && month == 2) {
		day += 1;
	}
	return day;

}
int main() {
	int month = 0, year = 0;
	int days = 0;
	scanf("%d%d", &year, &month);
	days = days_of_month(year, month);
	printf("%d", days);
	return 0;

}

 第一个函数,先判断是否是闰年

第二个函数就嵌套调用了第一个函数,得出想要的结果

链式访问

所谓的链式访问就是将一个函数的返回值作为另一个函数的参数,像链条一样将函数串起来 ,这就叫做函数的链式访问。

下面一printf函数为例,首先我门要知道printf函数返回的是什么。printf函数返回的是打印在屏幕上字符的个数

这里我们从后往前看,首先打印出来的是43,这是毋庸置疑的,因为这个时候打印在屏幕上的字符个数是2,所以第二个printf函数的返回值是2。到这里 屏幕上打印的字符个数就是1了,所以第一个printf函数的所接收到返回值为1,最终结果就是4321。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值