这里写目录标题
1. 函数的概念
关于函数想必我们并不陌生,如y=kx+b
这就是数学中的一次函数,我们给定一个x
函数就会出来一个y
。
在C语言中的函数和数学中的函数类似,我们给定数据函数产生结果。
C语言其实是由一个又一个的函数组成的。如:main函数
2. 库函数
2.1 概念
库函数就是写好的函数,之前我们说过C语言程序是函数组成的,程序员要完成一个程序,就要用到很多函数,期中有的函数很简单 ,但又不可或缺,如果一个又一个写很费时间,但如果我早早的把这些简单的函数写好了,需要这些函数时,直接用就好了,这就节省了大量时间。
2.2 头文件
如何使用这些库函数呢?这个就需要包含你想要实用的函数头文件。
例如:printf的头文件<stdio.h>
2.3 如何学习
学习库函数要知道它的头文件、返回类型、参数类型、参数个数、作用等。
可以去以下网站详细学习:
C/C++官⽅的链接:https://zh.cppreference.com/w/c/header
cplusplus.com:https://legacy.cplusplus.com/reference/clibrary/
3. 自定义函数
3.1 概念
库函数虽然方便,但不能解决我们遇到的所有问题。于是自定义函数出现了,他给了程序员更大的自由度,让我们可以根据实际情况来编写需要的函数。
自定义函数的语法形式:
type name(参数)
{
函数体;
}
type
:是函数的返回类型,它可以是int、char、float等,也可以是void
这代表函数不需要返回值。
name
:是你写的函数的名字,它要起的有意义写,最好能够反映函数的功能。
()
:要表明函数的类型,以及函数的参数的个数。
{}
:内的是函数体它是你实现函数功能的地方。
例如:
#include <stdio.h>
int add(int x, int y)
{
int res = x + y;
return res;
}
int main()
{
int a = 1;
int b = 4;
int c = add(a, b);
printf("%d\n", c);
}
add函数
是我写的一个加法函数,int
是add的返回类型,这个函数有两个参数int y
和int x
。
3.2 函数的定义与声明
3.2.1 单文件
在只有一个.c
文件时
#include <stdio.h>
int add(int x, int y)
{
int res = x + y;
return res;
}
int main()
{
int a = 1;
int b = 4;
int c = add(a, b);
printf("%d\n", c);
}
以上代码第3
行到第7
行是函数add的定义。当函数在调用前定义了,就不需要再声明了,因为函数的定义是一种特殊的声明。
如果函数定义在,函数调用的后面,如:
#include <stdio.h>
int main()
{
int a = 1;
int b = 4;
int c = add(a, b);
printf("%d\n", c);
}
int add(int x, int y)
{
int res = x + y;
return res;
}
就会产生报错,add函数未定义。
这是因为,函数定义在了函数调用的后面,而前面又没有函数的声明,才产生的报错。
这要在程序的开头加上函数的声明既可以了:
#include <stdio.h>
int add(int x, int y);
int main()
{
int a = 1;
int b = 4;
int c = add(a, b);
printf("%d\n", c);
}
int add(int x, int y)
{
int res = x + y;
return res;
}
代码的第2
行就是add函数
的声明。
注意:函数的声明要有,函数的返回类型、函数名、函数的参数类型、函数的参数个数。
3.2.2 多文件
在以后的学习工作中我们不可能在一个.c
文件中把所以的代码写完,这样既不高效,也不利于我们以后的修改。我们就需要使用多个文件来完成程序。
这是一个简单的例子,我把函数的定义放在了add.c
文件中
把函数的声明放在了add.h
文件中
当我要使用add函数
时,我只需要包含add.h
这个头文件,就可以使用这个函数,像库函数一样。
3.3 实参
我们在调用函数时,实际传递个函数的参数,就是实参,如
int c = add(a, b);
这里的a
和b
就是实参。
3.4 形参
形参就是在函数被调用时才会像内存申请空间的参数,它在函数没被调用时是不存在的,只有函数被调用时才会生成变量,如:
int add(int x, int y)
{
int res = x + y;
return res;
}
这里的int x
和int y
就是add函数的形式参数,简称实参。
3.5 实参与形参的关系
- 函数在传参的时候,并不是真的把实参传过去,而是复制一份实参的值给形参,也就是说形参是实参的一份临时拷贝,实参的值是不会改变的。
- 形参和实参的名字可以相同
4. 函数的嵌套调用和链式访问
4.1 嵌套调用
嵌套调用就是函数调用函数如:
#include <stdio.h>
void sett(int arr[10]);
void print(int arr[10]);
void sett(int arr[10])
{
int i = 0;
for (i = 0; i < 10; ++i)
{
arr[i] = i;
}
print(arr);
}
void print(int arr[10])
{
int i = 0;
for (i = 0; i < 10; ++i)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[10] = { 0 };
sett(arr);
return 0;
}
我调用sett函数
来重新给arr数组
赋值,在sett函数
中我又调用了print函数
来打印数组arr
。
4.2 链式访问
函数的链式访问基于的是函数的返回值,如:
#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
以上代码为什么结果会是4321
,首先我们要知道printf函数的返回值是它打印的字符个数,然后再理解代码。
第一层
printf要打印的是第二层
printf的返回值,第二层
printf要打印的是第三层
printf函数的返回值,第三层
printf打印43,它打印了2个字符,返回2;所以第二层
printf打印2,返回1;第一层
printf打印1。所以最终打印4321.
5. static和extern
5.1 用法
static
修饰局部变量static
修饰全局变量static
修饰函数extern
声明外部符号
5.2 举例理解
static
修饰局部变量:我们之前说过局部变量的生命周期是其所在的局部区域,出了它所在的局部区域就会销毁。而经过static
修饰的局部变量,除了其所在的局部范围不会销毁,其生命周期是整个程序,即当整个程序结束时它才会销毁。
#include <stdio.h>
int sxe(int x)
{
x = x + 1;
return x;
}
int main()
{
int a = 1;
int b = sxe(a);
int c = sxe(a);
printf("%d\n", b);
printf("%d\n", c);
return 0;
}
改变生命周期的实质,其实是改变了局部变量的储存位置。正常情况下局部变量放在内存的栈区,而static
修饰的局部变量放在了内存的静态区。
extern
声明外部符号:在一个.c
文件定义的全局变量,想要在另一个.c
文件中使用,就要用extern
声明。
int a.c
int a = 6;
这是一个.c
文件中的全局变量,只要在另一文件合理声明,就可使用。
test.c
#include <stdio.h>
extern int a;
int main()
{
printf("%d", a);
return 0;
}
static
修饰全局变量:全局变量是具有外部连接属性的,也就是说在一个.c
文件定义的全局变量,在另一个.c
文件只要声明后就可以使用,经过static
修饰后的全局变量,会使其外部连接属性改为内部连接属性,即只能在定义的.c
文件内部使用。
static int a = 6;
static
修饰函数:函数是具有外部连接属性的,也就是说在一个.c
文件定义的函数,在另一个.c
文件只要声明后就可以使用,经过static
修饰后的函数,会使其外部连接属性改为内部连接属性,即只能在定义的.c
文件内部使用。
static int add(int x, int y)
{
int res = x + y;
return res;
}
6. 数组传参
在进行函数传参时我们难免会碰到数组传参,数组传参具有一些特别的点
- 数组传参传的是数组首元素的的地址
- 数组传参时形参不会创建新数组
- 形参的数组和实参的数组是同一个
- 可以把形参的数组名写成实参数组名
- 形参是一维数组则数组大小可以不写
- 形参是二维数组,则行可以不写,但列要写
7. return语句
return
意为返回,他是函数的结束表示,当程序运行到return语句
时,无论以后是否还有语句,都会立刻结束函数。