### 函数
定义:函数是一组一起执行一个任务的语句,每个C程序至少有一个函数,即主函数main(),所有简单的程序都可以定义其他额外的函数。
C 语言中的函数定义的一般形式如下
~~~
return_type function_name( parameter list )
{
body of the function
}
~~~
在 C 语言中,函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:
* **返回类型:**一个函数可以返回一个值。**return\_type**是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return\_type 是关键字**void**。
* **函数名称**:这是函数的实际名称。函数名和参数列表一起构成了函数签名。
* **参数**:参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
* **函数主体**:函数主体包含一组定义函数执行任务的语句
### 调用函数
创建 C 函数时,会定义函数做什么,然后通过调用函数来完成已定义的任务。
当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。
调用函数时,传递所需参数,如果函数返回一个值,则可以存储返回值。例如:
```
#include <stdio.h>
/* 函数声明 */
int max(int num1, int num2);
int main ()
{
/* 局部变量定义 */
int a = 100;
int b = 200;
int ret;
/* 调用函数来获取最大值 */
ret = max(a, b);
printf( "Max value is : %d\n", ret );
return 0;
}
/* 函数返回两个数中较大的那个数 */
int max(int num1, int num2)
{
/* 局部变量声明 */
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
```
把 max() 函数和 main() 函数放一块,编译源代码。当运行最后的可执行文件时,会产生下列结果:
~~~
Max value is : 200
~~~
* [ ] **知识点:函数调用时需注意先后函数存在的先后顺序**
比如A函数调用B函数,则B函数的声明一定要在A函数的前面,否则会出现报错:B函数找不到标识符。
如正常代码如下:
```
#include "stdafx.h"
#include <iostream>
int func(void)
{
printf("函数");
return -1;
}
int func(void* pathName, int a)
{
printf("函数");
return -1;
}
int main()
{
func();
}
```
如果我们将func函数移到main函数后面,即
```
#include "stdafx.h"
#include <iostream>
int main()
{
func();
}
int func(void)
{
printf("函数");
return -1;
}
int func(void* pathName, int a)
{
printf("函数");
return -1;
}
```
运行就会报错如下:
![](https://img.kancloud.cn/87/15/871595418c3ed2be2bec5c8934a2ff1f_1500x38.png)
原因如下:在C语言里面,程序加载过程是由上至下来进行加载,到加载到main函数时没有找到func函数(此时func函数还没有被加载到内存,会认为func函数没有,不存在),而Java中为啥可以呢?因为Java是面向对象的,它对于整个class文件,会整个加载到内存,它不会分为上下。
* [ ] **为什么C语言这样设计?**
因为C语言是以函数为基础,它不像Java一样以类为基础,类作为一个对象,所有的方法都可以写在类中。C程序是以每一个函数组成的,当设计一个应用程序之后,它会产生很高的耦合,所以C语言中的众多的头文件就相当于每一个接口,这些头文件不会参与编译,真正参与编译的是这些头文件实现的C文件,头文件的存在就是为了解决程序的耦合问题。
* [ ] **解决方案**:
* 第一种方案就是,将func定义在main函数前面,就是刚开始正确的代码
* 第二种方案就是,编写头文件,将func函数声明在该头文件中,切记只有函数的声明,没有函数的实现,类似于Java中的接口,具体步骤:右面解决方案资源管理器中找到源文件,右键,添加,新建项,如图所示
![](https://img.kancloud.cn/40/2c/402c09b0c43e3bfd289ed6f7d620e857_794x266.png)
![](https://img.kancloud.cn/1d/62/1d6246228f7a6bfdc5b7449c5344d92b_941x653.png)
func.h如下
```
int func(void);
int func(void* pathName, int a);
```
引用头文件如下:
![](https://img.kancloud.cn/59/c6/59c61554d582818cd4398e22c89a47d5_689x201.png)
**注意:如果是自定义的头文件,是双引号,系统的自带的头文件则是尖括号**
* [ ] **#include 指令**
`#include`指令主要有两种书写格式. 第一种格式用于属于C语言自身库的头文件:
```
[#include指令(格式1)] #include <文件名>
```
第二种格式用于所有其他头文件,也包含任何自己编写的文件:
```
[#include指令(格式2)] #include "文件名"
```
这两种格式间的细微差异在于编译器定位头文件的方式。下面是大多数编译器遵循的规则。
* `#include <文件名>`:搜寻系统头文件所在的目录(或多个目录)。(例如,在UNIX系统中,通常把系统头文件保存在目录/usr/include中。)
* `#include "文件名"`:先搜寻当前目录,然后搜寻系统头文件所在的目录(或多个目录),通常可以改变搜寻头文件的位置,这种改变经常利用诸如-I路径这样的命令选项来实现。
这样如下代码
```
#include "stdafx.h"
#include <iostream>
#include "func.h"
int main()
{
func();
}
int func(void)
{
printf("函数");
return -1;
}
int func(void* pathName, int a)
{
printf("函数");
return -1;
}
```
再次运行就不会报错