C语言函数(一):基础知识

1.函数的概念

在数学上函数的概念就是:对于集合A中的每一个元素,按照某种确定的法则,都能在集合B中找到一个唯一确定的元素与之对应,那么这种对应关系就称为从集合A到集合B的函数。
在C语言中函数的概念和数学上函数的概念差不多,在C语言中,**函数就是一个完成某项特定的任务的一小段代码。**这段代码是有特定的写法和调用方法的。
在C语言中我们一般会看到两种函数

  • 库函数
  • 自定义函数

2.库函数

2.1.标准库和头文件

C语言标准中规定了C语言的各种语法规则,C语言并不提供库函数。C语言的国际标准ANSI C规定了一些常用的函数的标准,被称为标准库,而不同的编译厂商根据这个规则给出了函数的实现,被称为库函数。
比如:printf()和scanf()……,库函数也是函数,但是它们不需要我们编写代码用以实现其功能,我们只需直接使用就行了,
各种编译器的库函数实现内部可能有些许的差异,但是函数名和效果是一样的,这些库函数根据功能的划分,都在不同的头文件中进行了声明。
库函数相关头文件

2.2.库函数使用方法

库函数学习和查看的工具有很多,比如:
c/c++官方链接:网站
比如sqrt()的使用方法:
在这里插入图片描述
在这些参考网站中,库函数文档的一般格式:

  1. 函数原型
  2. 函数功能介绍
  3. 参数和返回类型说明
  4. 代码举例
  5. 代码输出
  6. 相关知识链接

3.自定义函数

自定义函数非常重要,它的书写给程序员写代码提供了更多的创造性

3.1.函数的语法形式

形式如下:

ret_type fun_name(形式参数){

}
  • ret_type是函数的返回类型,有时返回类型可以是void,表示什么都不返回
  • fun_name是函数的函数名,一般来说,起名都要有意义
  • 括号中放的是形式参数,有时也可以是void,表示没有参数传进来
  • {}括起来的是函数体,就是完成计算的过程

我们可以将函数比作工厂,工厂加工原材料使其变成产品,而函数也是加工形式参数,变为结果进行输出
在这里插入图片描述

3.2.函数举例

写一个加法函数,完成两个变量的加法操作

#include<stdio.h>
int add(int x, int y) {
	return x + y;
}
int main() {
	int x = 10;
	int y = 23;
	int result = add(x, y);
	printf("%d\n", result);//输出33
	return 0;
}

这里自定义函数add完成了加法操作,而在main函数中调用了这个函数并传了2个值用于计算。

  • 参数的个数也是自定义的,根据实际情况来确定,可以有0个参数,也可以有许多个参数

4.形参和实参

在函数调用过程中,把函数分为实参和形参
在这里插入图片描述

4.1.实参

在上面代码中 int result = add(x, y);中的x和y就是实参,当我们调用add函数时,实际传递给函数的参数就是这个x和y,所谓实参就是指真实传递给函数的参数

4.2.形参

在上面代码中 int add(int x, int y){……}中的x和y称为形式参数,简称形参。
为什么叫形式参数呢,这是因为如果不去调用add函数的话,add函数的参数x和y只是在形式上存在,而不是存在与地址中的,只有调用过程中传递过来了值,才向内存申请空间,所以这个过程被称为:实例化

4.3.实参和形参的关系

虽然实参是传递给形参的,它们之间是有联系的,但是形参和实参是各自独立的内存单元

在代码中打印实参和形参的地址:

#include<stdio.h>
int add(int x, int y) {
	printf("形参x为:%p 形参y为:%p\n", &x, &y);
	return x + y;
}
int main() {
	int x = 10;
	int y = 23;
	printf("实参x为:%p 实参y为:%p\n", &x, &y);
	int result = add(x, y);
	printf("%d\n", result);//输出33
	return 0;
}

在这里插入图片描述
所以,形参是实参的一份临时拷贝

5.return语句

return语句的注意事项:

  • return后面可以是一个数值也可以是一个表达式,如果是表达式则先执行表达式,再返回表达式的结果。
  • 可以直接写return,这种写法适用于函数返回值类型是void的时候
  • return返回值和返回类型不一致,系统会自动将返回结果强制转换为返回类型
  • return语句执行后,函数就彻底返回,后面的代码不再执行
  • 如果函数中存在if等分支语句,则要保证每种情况下都要有return返回,否则会出现编译错误

6.数组作为函数参数

再使用函数解决问题的时候,难免会将数组作为参数传递给函数,在函数内部对数组进行操作
比如:

写一个函数将一个整型数组的内容全部置为-1,再写一个函数打印数组的内容

void set_arr(int arr[], int sz) {
	for (int i = 0; i < sz; i++) {
		arr[i] = -1;
	}
}
void printf_arr(int arr[], int sz) {
	for (int i = 0; i < sz; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
}
int main() {
	int arr[] = { 1,2,3,4,5 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf_arr(arr, sz);
	set_arr(arr, sz);//将数组元素置为1
	printf_arr(arr, sz);//打印数组
	return  0;
}

在这里插入图片描述

数组传参的几个重要知识点:

  • 函数的形式参数和实际参数个数要匹配
  • 函数的实参是数组,形参也可以是数组
  • 形参如果是一维数组,数组的大小可以不写
  • 形参如果是二维数组,行可以省略,列不能省略
  • 数组传参,形参是不会创建新的数组的
  • 形参操作的数组和实参的数组是同一个数组,也就是说两个数组是同一个数组,地址是一样的
void set_arr(int arr[], int sz) {
	for (int i = 0; i < sz; i++) {
		arr[i] = -1;
	}
}
void printf_arr(int arr[], int sz) {
	for (int i = 0; i < sz; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
	printf("地址:%p", &arr[0]);

}
int main() {
	int arr[] = { 1,2,3,4,5 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("地址:%p", & arr[0]);
	//printf_arr(arr, sz);
	printf("\n");
	set_arr(arr, sz);//将数组元素置为1
	printf_arr(arr, sz);//打印数组
	return  0;
}

在这里插入图片描述

7.嵌套调用和链式访问

7.1.嵌套调用

嵌套调用就是函数之间的互相调用,也正是因为函数之间有效的互相调用,最后才能写出相对大型的程序

计算某年某月有多少天
is_leap_year():根据年份确定是否是闰年
get_days_of_month():调用is_leap_year()确定是闰年后,再根据月计算天数

int  is_leap_year(int y) {
	if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)) return 1;
	else
		return 0;
}
int get_days_of_month(int y, int m) {
	int arr[] = {0,31,28,31,30,31,30,31,31,30,31,30 };//在数组前加一个0,这样每个天数就可以和月份以及下标对应
	int day = arr[m];
	if (is_leap_year(y) == 1 && m == 2) {
		day += 1;
	}
	return day;
}

int main() {
	printf("请输入年份:>");
	int year = 0;
	scanf("%d", &year);
	printf("\n请输入月份:>");
	int month = 0;
	scanf("%d", &month);
	printf("\n该月份有%d天\n", get_days_of_month(year, month));
	return 0;
}

在这里插入图片描述
其中就在get_days_of_month()函数中嵌套了函数is_leap_year()

7.2.链式访问

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

#include<string.h>
int main() {
	int len = strlen("abcdef");
	printf("%d\n", len);//输出6
	return 0;
}

可以改为:

#include<string.h>
int main() {
	printf("%d\n", strlen("abcdef"));//输出6
	return 0;
}

链式访问一定程度上降低了代码的书写量,但如果过长的链式访问就有可读性降低的风险了

8.函数的声明和定义

8.1.单个文件

一般在使用函数的时候,直接将函数写出来就可以使用了,像上面的代码,直接将自定义函数放在主函数的上面就可以了,但是如果我们将自定义函数放在主函数的下面,程序就会弹出警告。

#include<stdio.h>

int main() {
	int x = 10;
	int y = 23;
	printf("实参x为:%p 实参y为:%p\n", &x, &y);
	int result = add(x, y);
	printf("%d\n", result);//输出33
	return 0;
}
int add(int x, int y) {
	printf("形参x为:%p 形参y为:%p\n", &x, &y);
	return x + y;
}

在这里插入图片描述
但如果直接运行代码也不会报错,依然能够执行。
所以将自定义函数写在主函数的上面就叫做函数的定义
其实解决方法就是函数的声明
在这里插入图片描述
上述箭头指向就是函数的声明,其实函数的定义也是一种特殊的函数的声明。
函数的调用一定要满足:先声明,再使用

8.2.多个文件

一般在企业中写代码时,代码量很多,不会将所有代码放在一个文件中;我们往往会根据程序的功能,将代码拆分放在多个文件中
一般情况下:函数的声明,类型的声明放在头文(.h)中,函数的实现时放在源文件(.c)中.

写一个简单的加法计算器

在这里插入图片描述

/考研势在必行/
  • 37
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值