目录
一.什么是函数
在计算机科学中,子程序(英语Subroutine, procedure,function,routine, method,subprogram, callable unit), 是一个大型程序中的某部分代码,由一 个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。
一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
二.函数的分类
1.库函数
(1).为什么会有库函数?
- 我们知道在我们学习C语言编程的时候,总是在一个代码编写完成之后迫不及待的想知道结果,想 把这个结果打印到我们的屏幕上看看。这个时候我们会频繁的使用一个功能:将信息按照一定的格 式打印到屏幕上(printf)。
- 在编程的过程中我们会频繁的做一些字符串的拷贝工作(strcpy)。
- 在编程是我们也计算,总是会计算n的k次方这样的运算(pow)。 像上面我们描述的基础功能,它们不是业务性的代码。我们在开发的过程中每个程序员都可能用的到, 为了支持可移植性和提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员 进行软件开发。
(2).c语言常见的库函数
- IO函数
- 字符串操作函数
- 字符操作函数
- 内存操作函数
- 时间/日期函数
- 数学函数
- 其他库函数
(3).如何学习库函数?
首先在这里推荐一个网站——www.cplusplus.com
我们在这里选择在右上角的“Legacy version”切换为旧版
我们可以选择Reference栏目查找不同头文件下的库函数,也可以在上方的搜索栏内查找想要了解的库函数
例如strlen函数
我们可以通过函数主体来初步了解函数的使用方法,也可以通过下面的注释来了解函数的作用。
后面也有对应的例子供我们进一步的理解。
当然不止是www.cplusplus.com,还有其他网站供我们学习
http://en.cppreference.com(英文版)
http://zh.cppreference.com(中文版)
(4).库函数的使用
- 使用库函数一定要包含#include对应的头文件
2.自定义函数
自定义函数和库函数一样,有函数名,返回值类型和函数参数。 但是不一样的是这些都是我们自己来设计。
(1).自定义函数的组成
ret_type fun_name(para1, * )
{
statement;//语句项
}
ret_type 返回类型
fun_name 函数名
para1 函数参数
(2).自定义函数的使用
函数的参数
实际参数(实参)
真实传给函数的参数,叫实参。 实参可以是:常量、变量、表达式、函数等。 无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形 参。
形式参数(形参)
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内 存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
首先我们先举一个简单的例子
#include <stdio.h>
int get_max(int x, int y)
{
return (x>y)?(x):(y);
}
int main()
{
int num1 = 10;
int num2 = 20;
int max = get_max(num1, num2);
printf("max = %d\n", max);
return 0;
}
在这个自定义函数中,num1,num2作为函数的实参,x,y作为形参临时拷贝num1,num2。 而在这个自定义函数的语句项中,根据返回类型返回了一个整形为x,y中的最大值(即num1,num2中的最大值)赋值给主函数中的max。
如此,我们便能对自定义函数以及函数的参数有了一定的理解。
注意:
- 当自定义函数返回类型为void时,该自定义函数没有返回值,而其他类型则是决定自定义函数返回值的类型,而返回值取决于语句项中的return。
- 自定义函数中函数参数可有可无。 当定义自定义函数时函数参数部分为空,在使用该自定义函数时可以传入参数,但没有作用
#include<stdio.h>
print_haha()
{
printf("haha");
}
int main()
{
int i=0
print_haha(i);
return 0;
}
而当定义自定义函数时函数参数部分为void时,在使用该自定义函数时不能传入参数,否则会 报错。
#include<stdio.h>
print_haha(void)
{
printf("haha");
}
int main()
{
print_haha();
return 0;
}
三.函数的调用
1.分类
(1).传值调用
实参传递给形参,函数的形参和实参分别占有不同的内存块,这是形参是实参的一份临时拷贝,对形参的修改不会影响实参。
上面自定义函数中所给的函数便是一个很好的例子
#include <stdio.h>
int get_max(int x, int y)
{
return (x>y)?(x):(y);
}
int main()
{
int num1 = 10;
int num2 = 20;
int max = get_max(num1, num2);
printf("max = %d\n", max);
return 0;
}
(2).传址调用
a.传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
b.这种传参方式可以让函数和函数外边的变量建立起真的联系,也就是函数内部可以直接操作函数外部的变量。
例如如果想要通过函数交换两个数的值
int main()
{
int num1 = 1;
int num2 = 2;
Swap(num1, num2); printf("Swap1::num1 = %d num2 = %d\n", num1, num2); return 0;
}
如果使用传值调用
void Swap1(int x, int y)
{
int tmp = 0;
tmp = x;
x = y;
y = tmp;
}
被交换的是作为形参的x y,而作为实参的num1 num2不受形参变化的影响,无法完成交换
这时便要使用传址调用
void Swap2(int *px, int *py)
{
int tmp = 0;
tmp = *px;
*px = *py;
*py = tmp;
}
将地址传入后,便能够直接对num1 num2所在地址中的值进行交换,从而完成num1 num2的交换
2.其他
传参时顺序为从右向左。
四.函数的嵌套调用和链式访问
1.函数的嵌套调用
函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的。
函数可以嵌套调用
void new_line()
{
printf("hehe\n");
}
void three_line()
{
int i=0;
for(i=0;i<3;i++)
{
new_line();
}
}
int main()
{
three_line();
return 0;
}
但是不能嵌套定义
int main()
{
int Add(int x,int y)
{
return x+y:
}
return 0;
}
2.函数的链式访问
由于函数具有返回值,所以可以将一个函数作为另一个函数的输入参数
例如
#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
由于printf()函数的返回值为打印元素的个数,而传参的顺序为自右向左
所以最后打印的结果为“4321”
五.函数的声明与定义
1.函数的声明
告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数 声明决定不了。
2.函数的定义
指函数的具体实现,交待函数的功能实现。
3.声明与定义的联系及注意事项
(1).函数的声明一般出现在函数的使用之前。要满足先声明后使用。
(2).函数的声明一般要放在头文件中的。
好处:模块化开发(分工)、代码的隐藏
多次定义:为避免因失误导致的头文件的多次定义,我们可以使用以下代码
#ifndef __ADD_H__
#define __ADD_H__
int Add(int x,int y);
#endif
(3).函数的定义要放在源文件中
(4).函数的定义也是一种特殊的声明