马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
函数
1.函数是一段可以重复实行的代码。
它可以继承差别的参数,
完成对应的使用。
下面的例子就是一个函数- int plus(int n) {
- return n;
- }
复制代码 上面的代码声明确一个函数plus()。
2.函数声明的语法有以下几点,必要注意。
- 返回值范例。
函数声明时,
起首必要给出返回值的范例,
上例是int,
表现函数plus()返回一个整数。
- 参数。
函数名背面的圆括号内里,
必要声明参数的范例和参数名,
plus(int n)表现这个函数有一个整数参数n。
- 函数体。
函数体要写在大括号内里,
背面(即大括号外貌)不必要加分号。
大括号的起始位置,
可以跟函数名在同一行,
也可以另起一行。
- return语句。
return语句给出函数的返回值,
步调运行到这一行,
就会跳出函数体,
竣事函数的调用。
如果函数没有返回值,
可以省略return语句,
大概写成return;。
3.调用函数时,
只要在函数名背面加上圆括号就可以了,
现实的参数放在圆括号内里,
就像下面如许。- int a = plus(13);
- // a 等于 14
复制代码 4.函数调用时,
参数个数必须与界说内里的参数个数同等(逐一对应),
参数过多或过少都会报错。- int plus(int n) {
- return n + 1;
- }
- plus(2, 2); // 报错
- plus(); // 报错
复制代码 上面示例中,函数plus()只能继承一个参数,传入两个参数或不传参数,都会报错。
5.函数必须声明后使用,
否则会报错。
也就是说,
肯定要在使用plus()之前,声明这个函数。
如果像下面如许写,编译时会报错。- int a = plus(13);
- int plus(int n) {
- return n + 1;
- }
复制代码 上面示例中,在调用plus_one()之后,才声明这个函数,编译就会报错。
6.C 语言尺度规定,
函数只能声明在源码文件的顶层,
不能声明在其他函数内部。
7.没有返回值的函数,
使用void关键字表现返回值的范例。
没有参数的函数,
声明时要用void关键字表现参数范例。- void myFunc(void) {
- // ...
- }
复制代码 上面的myFunc()函数,
既没有返回值,
调用时也不必要参数。
8.函数可以调用自身,
这就叫做递归(recursion)。
下面是斐波那契数列的例子。- unsigned long Fibonacci(unsigned n) {
- if (n > 2)
- return Fibonacci(n - 1) + Fibonacci(n - 2);
- else
- return 1;
- }
复制代码 上面示例中,
函数Fibonacci()调用了自身,
如许做可以简化算法。
9.main()
C 语言规定,
main()是步调的入口函数,
即全部的步调肯定要包罗一个main()函数。
步调总是从这个函数开始实行,
如果没有该函数,
步调就无法启动。
其他函数都是通过它引入步调的。
main()的写法与其他函数一样,
要给出返回值的范例和参数的范例,
就像下面如许。- int main(void) {
- printf("Hello World\n");
- return 0;
- }
复制代码 上面示例中,
末了的return 0;表现函数竣事运行,返回0。
11.C 语言约定,
返回值0表现函数运行乐成,
如果返回其他非零整数,
就表现运行失败,
代码出了题目。
体系根据main()的返回值,
作为整个步调的返回值,
确定步调是否运行乐成。
正常环境下,
如果main()内里省略return 0这一行,
编译器会主动加上,
即main()的默认返回值为0。
以是,写成下面如许,
效果完全一样。- int main(void) {
- printf("Hello World\n");
- }
复制代码 由于 C 语言只会对main()函数默认添加返回值,
对其他函数不会如许做,
发起总是保存return语句
12.参数的传值引用
如果函数的参数是一个变量,
那么调用时,
传入的是这个变量的值的拷贝,
而不是变量自己。- void increment(int a) {
- a++;
- }
- int i = 10;
- increment(i);
- printf("%d\n", i); // 10
复制代码 上面示例中,
调用increment(i)以后,
变量i自己不会发生厘革,
还是即是10。
由于传入函数的是i的拷贝,
而不是i自己,
拷贝的厘革,
影响不到原始变量。
这就叫做“传值引用(单向值转达)”。
另有一种方法是是双向转达(也叫所在转达)下面会解说
以是,
如果参数变量发生厘革,
最好把它作为返回值传出来。- int increment(int a) {
- a++;
- return a;
- }
- int i = 10;
- i = increment(i);
- printf("%d\n", i); // 11
复制代码 再看下面的例子,Swap()函数用来交换两个变量的值,由于传值引用,下面的写法不会收效。- void Swap(int x, int y) {
- int temp;
- temp = x;
- x = y;
- y = temp;
- }
- int a = 1;
- int b = 2;
- Swap(a, b); // 无效
复制代码 上面的写法不会产生交换变量值的效果,
由于传入的变量是原始变量a和b的拷贝,
不管函数内部怎么使用,
都影响不了原始变量。
13.如果想要传入变量自己,
有一个办法,
就是传入变量的所在(所在转达是双向的)。- void Swap(int* x, int* y) {
- int temp;
- temp = *x;
- *x = *y;
- *y = temp;
- }
- int a = 1;
- int b = 2;
- Swap(&a, &b);
复制代码 上面示例中,
通过传入变量x和y的所在,
函数内部就可以直接使用该所在,
从而实现交换两个变量的值。
固然跟传参无关,
这里特别注意下,
函数不要返回内部变量的指针。- int* f(void) {
- int i;
- // ...
- return &i;
- }
复制代码 上面示例中,
函数返回内部变量i的指针,
这种写法是错的。
由于当函数竣事运行时,
内部变量就消散了,
这时指向内部变量i的内存所在就是无效的,
再去使用这个所在好坏常伤害的。
14.函数指针
函数自己就是一段内存内里的代码,
C 语言答应通过指针获取函数。- void print(int a) {
- printf("%d\n", a);
- }
- void (*print_ptr)(int) = &print;
复制代码 上面示例中,
变量print_ptr是一个函数指针,
它指向函数print()的所在。
函数print()的所在可以用&print得到。
注意,
(*print_ptr)肯定要写在圆括号内里,
否则函数参数(int)的优先级高于*,
整个式子就会酿成void* print_ptr(int)。
有了函数指针,
通过它也可以调用函数。- (*print_ptr)(10);
- // 等同于
- print(10);
复制代码 比力特别的是,
C 语言还规定,
函数名自己就是指向函数代码的指针,
通过函数名就能获取函数所在。
也就是说,
print和&print是一回事。- if (print == &print) // true
复制代码 因此,上面代码的print_ptr等同于print。- void (*print_ptr)(int) = &print;
- // 或
- void (*print_ptr)(int) = print;
- if (print_ptr == print) // true
复制代码 以是,对于恣意函数,
都有五种调用函数的写法。- // 写法一
- print(10)
- // 写法二
- (*print)(10)
- // 写法三
- (&print)(10)
- // 写法四
- (*print_ptr)(10)
- // 写法五
- print_ptr(10)
复制代码 为了轻便易读,
一样平常环境下,
函数名前面都不加*和&。
15.这种特性的一个应用是,
如果一个函数的参数或返回值,
也是一个函数,
那么函数原型可以写成下面如许。- int compute(int (*myfunc)(int), int, int);
复制代码 上面示例可以清楚地表明,
函数compute()的第一个参数也是一个函数。
16.函数原型
前面说过,
函数必须先声明,后使用。
由于步调总是先运行main()函数,
导致全部其他函数都必须在main()函数之前声明。- void func1(void) {
- }
- void func2(void) {
- }
- int main(void) {
- func1();
- func2();
- return 0;
- }
复制代码 上面代码中,
main()函数必须在末了声明,
否则编译时会产生告诫,
找不到func1()或func2()的声明。
但是,
main()是整个步调的入口,
也是紧张逻辑,
放在最前面比力好。
另一方面,
对于函数较多的步调,
包管每个函数的序次精确,
会变得很贫苦。
C 语言提供的办理方法是,
只要在步调开头处给出函数原型,
函数就可以先使用、后声明。
所谓函数原型,
就是提前告诉编译器,
每个函数的返回范例和参数范例。
其他信息都不必要,
也不消包罗函数体,
具体的函数实现可以背面再补上。- int twice(int);
- int main(int num) {
- return twice(num);
- }
- int twice(int num) {
- return 2 * num;
- }
复制代码 上面示例中,
函数twice()的实现是放在main()背面,
但是代船埠部先给出了函数原型,
以是可以精确编译。
只要提前给出函数原型,
函数具体的实现放在那里,
就不紧张了。
17.函数原型包罗参数名也可以,
固然如许对于编译器是多余的,
但是阅读代码的时间,
大概有助于明确函数的意图。- int twice(int);
- // 等同于
- int twice(int num);
复制代码 上面示例中,
twice函数的参数名num,
无论是否出如今原型内里,
都是可以的。
注意,
函数原型必须以分号末端。
一样平常来说,
每个源码文件的头部,
都会给出当前脚本使用的全部函数的原型。
18.函数阐明符
C 语言提供了一些函数阐明符,
让函数用法更加明确。
(1)extern 阐明符
对于多文件的项目,
源码文件会用到其他文件声明的函数。
这时,当前文件内里,
必要给出外部函数的原型,
并用extern阐明该函数的界说来自其他文件。- extern int foo(int arg1, char arg2);
- int main(void) {
- int a = foo(2, 3);
- // ...
- return 0;
- }
复制代码 上面示例中,
函数foo()界说在其他文件,
extern告诉编译器当前文件不包罗该函数的界说。
不外,
由于函数原型默认就是extern,
以是这里不加extern,
效果是一样的。
(2)static 阐明符
默认环境下,
每次调用函数时,
函数的内部变量都会重新初始化,
不会保存上一次运行的值。
static阐明符可以改变这种举动。
static用于函数内部声明变量时,
表现该变量只必要初始化一次,
不必要在每次调用时都举行初始化。
也就是说,
它的值在两次调用之间保持稳固。- #include <stdio.h>
- void counter(void) {
- static int count = 1; // 只初始化一次
- printf("%d\n", count);
- count++;
- }
- int main(void) {
- counter(); // 1
- counter(); // 2
- counter(); // 3
- counter(); // 4
- }
复制代码 上面示例中,
函数counter()的内部变量count,
使用static阐明符修饰,
表明这个变量只初始化一次,
以后每次调用时都会使用上一次的值,
造成递增的效果。
注意,
static修饰的变量初始化时,
只能赋值为常量,
不能赋值为变量。- int i = 3;
- static int j = i; // 错误
复制代码 上面示例中,
j属于静态变量,
初始化时不能赋值为另一个变量i。
别的,
在块作用域中,
static声明的变量有默认值0。- static int foo;
- // 等同于
- static int foo = 0;
复制代码 static可以用来修饰函数自己。- static int Twice(int num) {
- int result = num * 2;
- return(result);
- }
复制代码 上面示例中,
static关键字表现该函数只能在当前文件里使用,
如果没有这个关键字,
其他文件也可以使用这个函数(通过声明函数原型)。
static也可以用在参数内里,
修饰参数数组。- int sum_array(int a[static 3], int n) {
- // ...
- }
复制代码 上面示例中,static对步调举动不会有任何影响,
只是用来告诉编译器
该数组长度至少为3,
某些环境下可以加快步调运行速率。
别的,
必要注意的是,
对于多维数组的参数,
static仅可用于第一维的阐明。
(3)const 阐明符
函数参数内里的const阐明符,
表现函数内部不得修改该参数变量。上面示例中,
函数f()的参数是一个指针p,
函数内部大概会改掉它所指向的值*p,
从而影响到函数外部。
为了克制这种环境,
可以在声明函数时,
在指针参数前面加上const阐明符,
告诉编译器,
函数内部不能修改该参数所指向的值。- void f(const int* p) {
- *p = 0; // 该行报错
- }
复制代码 上面示例中,声明函数时,
const指定不能修改指针p指向的值,
以是*p = 0就会报错。
但是上面这种写法,
只限定修改p所指向的值,
而p自己的所在是可以修改的。- void f(const int* p) {
- int x = 13;
- p = &x; // 允许修改
- }
复制代码 上面示例中,
p自己是可以修改,
const只限定*p不能修改。
如果想限定修改p,
可以把const放在p前面。- void f(int* const p) {
- int x = 13;
- p = &x; // 该行报错
- }
复制代码 如果想同时限定修改p和*p,
必要使用两个const。- void f(const int* const p) {
- // ...
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金 |