C语言中的函数使用

本文详细介绍了C语言中的函数概念,包括库函数的使用和查找,自定义函数的定义与调用,形参与实参的区别,return语句的应用,以及嵌套调用和链式访问的概念。同时讨论了函数声明和定义在单文件和多文件项目中的实践。
摘要由CSDN通过智能技术生成

目录

函数概念

库函数

自定义函数

嵌套调用和链式访问

函数的声明和定义


一、函数概念

函数(function),也叫子程序,在C语言中是完成某项特定任务的一小段代码。通过对同一个函数的调用,大大提高了软件的开发效率。

在C语言中,函数一般分为两类:

  • 库函数
  • 自定义函数

二、库函数

C语言本身并不提供库函数,C语言的国际标准ANSIC规定了一些常用函数标准,成为标准库,不同的编译器厂商根据ANSIC提供的标准给出了一系列的函数的实现。这些函数就被称为库函数。

例如我们平时使用的"printf""scanf"都是库函数,那么要怎么查看库函数到底有哪些呢?怎么查看其是否使用呢?在这里提供给大家两个网站:

库函数的种类和个数很多,大家可以在后续的学习中慢慢接触,这里就不再一一介绍。

三、自定义函数

(一)自定义函数介绍

既然库函数是编译器厂商实现的函数,那么我们自己实现的函数就是自定义函数。自定义函数的结构如下:

ret_type fun_name(形式参数)
{

}
  • ret_type是函数的返回类型,比如“int”就表示返回一个整形。返回类型也可以是void,表示什么都不返回(返回一个空值)
  • fun_name是函数名。为了方便我们调用函数,我们一般命名地有意义一些。
  • 小括号里面是函数的参数,当函数被调用时,就会把程序中的字符带入参数中。参数可以是void,也可以没有参数。如果有参数要明确规定参数的类型和名字以及参数个数。
  • {}里面的内容被称为函数体,也就是完成计算的过程。

我们可以来看看下面这段代码:

#include<stdio.h>
int Add(int x,int y)
{
	return x + y;
}

int main()
{
	int a = 0;
	int b = 0;
	scanf("%d%d", &a, &b);
	int r = Add(a, b);
		printf("%d", r);

	return 0;
}

在这里我们定义了一个函数:Add,返回类型整型,参数个数两个分别是x,y。由于我这里要做加法运算,所以我把名字命名为Add,这样更有助于理解。

(二)形参和实参

依旧是这段代码,我们可以看到在函数的定义中我们给了两个参数x,y。当我调用函数时,真正代入函数的是a,b。那么x,y就是形参,a,b就是实参。

相当于数学中的一个函数f(x),f(x)后面的表达式由x作为参数,这个参数就是形参,而如果我们要求某一点的函数值代入的x值就是实参。

那为什么会有这种名称呢?我们来探讨一下实质。在函数定义阶段,我们只是定义函数,并没有使用,这个函数里的参数只存在于代码中,并没有运行,既然没有运行,那么这个参数就不会申请内存,因此称作形参。而当调用函数后,函数运行,需要申请内存,因此才被称为实参。

(三)return语句

return就是返回的意思,在函数的设计中,我们常常需要一个返回值。

  • return后面可以是一个数值,如“return 0”,也可以是一个表达式,例如上面代码中的“return x+y”,如果是返回一个表达式,则是先执行表达式,再返回表达式的结果。
  • return后面也可以无任何东西,直接写作“return”,一般用于返回类型是“void”的情况。
  • 一般情况下,return的返回值类型和函数的返回值类型一致,如果不一致,系统会自动将返回值隐式转换为函数的返回类型。
  • return语句执行后,函数就彻底返回,后面的代码不再执行。
  • 如果函数中存在分支语句,则要保证每种情况、每个分支都要有return返回,否则会出现编译错误。

(四)数组作函数参数

既然数组是一种数据类型,在使用函数时难免会将数组传递给函数。我们来举个例子,写一个函数将整型数组的内容全部置换为1,然后打印数组的内容,那么大概的思路应该是这样的:

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    int sz = sizeof(arr)/sizeof(arr[0]);
	set_arr(arr,sz);//设置数组内容为1
	printf_arr(arr,sz);//打印数组内容
	return 0;
}

那么在这里我们就要定义两个函数,一个是“set_arr”,一个是“print_arr”,我们先来看第一个函数:对于给数组依次赋值,应该把每一个元素都取出来单独赋值,因此我们可以这样:

void set_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 1;i < sz;i++)
	{
		arr[i] = 1;
	}
}
void print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 1;i < sz;i++)
	{
		printf("%d", arr[i]);
	}
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	set_arr(arr, sz);
	print_arr(arr, sz);
	return 0;
}

注意:

  • 函数形参实参要一致,形参是数组实参也要是数组。
  • 形参如果是一维数组,数组大小可以省略,如果是二维数组,行可以省略,列不能省略。
  • 数组传参,形参是不会创建新数组的。
  • 形参操作的数组和实参的数组是同一个数组。

四、嵌套调用和链式访问

(一)嵌套调用

函数的调用大大的提高了效率,但是如果想在不同函数中实现某种功能,就要写很多次重复的代码,那么这个时候我们就可以把能实现这个功能的函数调用进来,在一个函数中调用另一个函数就叫做嵌套调用。话不多说,我们直接来个例子说明一下,如下:

假设现在需要我们计算某年某月有多少天,如果要用函数实现,我们总体需要两个函数:

  • 根据年份确定是否是闰年,我们定义为year函数
  • 根据月份确定有多少天,我们定义为month函数

我们可以先写一下确定闰年的函数:

int year(int y)
{
	if ((y % 4 = 0) && (y % 100 != 0) || (y % 400 = 0))
		return 1;
	else
		return 0;
}

接下来就是判断月份的函数,这个时候怎么把一年12个月的天数写进程序里呢?那就要用到我们的数组了,但是大家注意要数组的下标,第一个数下标是0,为了与月份对应,我们可以在数组最前面添加0,这样就一一对应了,参考代码如下:

int month(int y,int m)
{
	int days[] = { 0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
	int day = days[m];
	if (year(y)&& m == 2)//调用了year函数
		day += 1;
	return day;
}

大家可以看到这个函数中调用了year函数来判断2月有多少天,这就是函数的嵌套调用。那剩下的就是我们的主函数部分了,如下:

int main()
{
	int y = 0;
	int m = 0;
	scanf("%d %d", &y, &m);
	int d = month(y, m);
	printf("%d", d);
	return 0;
}

我们来浅浅分析一下我们这里用了哪些嵌套调用:

  • year函数无调用
  • month函数调用了year函数
  • main函数调用了scanf、printf、month函数

(二)链式访问

链式访问,就是将一个函数的执行结果作为另外一个函数的参数,由此把几个函数串起来,比如:

#include<stdio.h>
#include<string.h>
int main()
{
	printf("%d", strlen("abcdef"));
	return 0;
}

将函数strlen的返回结果作为printf函数的参数,这就是链式访问。

这里给大家一道思考题,请看代码:

#include<stdio.h>
int main()
{
    printf("%d",printf("%d",printf("%d",43)));
    return 0;
}

 这段代码的输出结果是什么呢?那如果改成这样:

#include<stdio.h>
int main()
{
    printf("%d ",printf("%d ",printf("%d ",43)));
    return 0;
}

输出结果又是什么呢?我们在文尾揭晓答案! 

五、函数的声明和定义

(一)单个文件中函数的声明和定义

假如我们要判断某一年是否为闰年,我们可以这样用函数:

int year(int y)
{
	if ((y % 4==0)&& (y % 100 != 0) || (y % 400==0))
		return 1;
	else
		return 0;
}

int main()
{
	int y = 0;
	scanf("%d", &y);
	int r = year(y);
	if (r == 1)
		printf("是闰年");
	else
		printf("不是闰年");
	return 0;
}

那么上面我们对函数year的定义就叫函数定义。在一项大工程中,我们难免会遇到程序写了一半需要一个新函数的情况。这时候如果返回第一行写函数显然不太可能,这时候我们就需要把函数放在后面,那我们不妨试试,看看会发生什么结果:

int main()
{
	int y = 0;
	scanf("%d", &y);
	int r = year(y);
	if (r == 1)
		printf("是闰年");
	else
		printf("不是闰年");
	return 0;
}

int year(int y)
{
	if ((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0))
		return 1;
	else
		return 0;
}

 走起来我们可以看到编译器报错。这是因为,编译器编译时,是从上往下编译,由于编译到year时,year未定义,便不会继续编译下去,因此即使后面有函数他也不会调用。

这时候如果我们在前面加上一句:

int year(int y);

程序便可以正常运行,那么这句话起到的作用就是声明作用,相当于提醒编译器我有这个函数,就在后面,这时候函数就可以被调用了。 

(二)多个文件中函数的声明和定义

企业在写代码时,代码较多需要分工完成,往往会将代码拆分为多个文件。一般情况下,函数的声明和函数类型声明放在头文件(.h文件)中,函数的实现放在源文件(.c文件)中,例如我们实现加法函数,可以这样写:

add.c:

//函数的定义
int Add(int x ,int y )
{
    return x+y;
}

add.h:

//函数的声明
int Add(int x ,int y )

在正式文件中:

#include<stdio.h>
#include<add.h>
int main()
{
    //函数主体
    return 0;
}

这样看来几万行几十万行的代码也不是太不可思议了吧!


下面是对于文中问题的解答:

#include<stdio.h>
int main()
{
    printf("%d",printf("%d",printf("%d",43)));
    return 0;
}

这段代码的返回结果是4321,首先我们需要知道printf函数的返回类型,printf函数返回的是打印字符的个数 。这段代码中:

  • 第三个printf,打印43,两个字符,返回2
  • 第二个printf,打印2,一个字符,返回1
  • 第一个printf,打印1
#include<stdio.h>
int main()
{
    printf("%d ",printf("%d ",printf("%d ",43)));
    return 0;
}

对于这段代码,由于空格的存在,空格也算字符,因此打印结果是43 3 2,大家可以根据上文自行思考一下!

本期分享到此结束啦!再见!C语言小白,不定期更新C语言基础知识点。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值