This is an (most of Chinese Cpl teacher) untold story of the function in plain C.
C语言的函数,我们并不陌生。
要学习生物体,就得先学习生命最基础的表现形式——细胞。
同样,因为C是面向过程的,函数就是程序的细胞。我们学习C语言,总错过不了她。
细胞有细胞膜、细胞壁opt、细胞质、细胞器、细胞核。
那么,函数有啥内容值得学习?
首先我们要明确函数书写的两大基本概念:函数的声明(declaration)和函数的定义(definition)
函数的声明确定了函数的形态,特征。这个形态特征决定函数名称(一个合法的C标识符),和函数参数列表。
我们声明一个函数:
int add(a, b); // 声明后面必加分号!
另一种声明方式,在这种声明方式中,我们明确了参数列表内各参数的类型:
int add(int a, int b); // 注意要加分号!
我们将上面那个函数声明成外部的:
extern int add(int a, int b); // 这里也要加分号!
再来看函数的定义:函数的声明确定了函数执行什么样的运算过程。
我们定义那个声明好的add函数:
int add(int a, int b)
{
return a + b;
}
同时,函数的定义也可以与函数的声明写在一起:
extern int add(a, b) // 还没明确说明参数a,b的类型呢!
int a; // 此时我们也可以事后加以说明。
int b; // 要有分号哦!
{
return a + b;
}
那么,大家有没有被我一套大道理、官话讲晕掉了呢?
好了!In summarize:
如果函数在定义处之前被调用(Invoke)那么,这个函数需要在调用处(invocation)之前被声明。
换句话讲,我让张三做一件叫做add的事情(这是声明)。
到底张三怎样做add这件事呢?我告诉他,把我给你的a加上我给你的b,然后还给我(这些是定义)。
如果我先说:张三哪,你去做add(a, b);
等到张三拿到我给他的a b(实际参数):x = add (1, 2); 时候就问了:领导,add这件事,我怎么去实施啊?
当然我是一个负责任的领导,不会这样说:笨呐!自己动动脑子啊!养你这么多年,钞票都喂猪啦?(如果我真的这样说,编译器会给我使脸色:找不到函数add的参照。)
我会耐心说道:
int add(int a, int b) // add这件事呢,你首先拿好我给你的俩宝贝,最后你要还我一个int类型的宝贝。
{
return a + b; // 具体来讲,你要把宝贝a和宝贝b加起来,还给我,就是这样啦。
}
这种情况的代码如下(完整的可执行的):
#include <stdio.h>
int add(int, int);
int main()
{
printf("%d\n", add(1,1));
return 0;
}
int add(int a, int b)
{
return a + b;
}
复制代码
换一种情况:我一口气说:
张三你去做add这件事,等你拿到俩宝贝,最后你要还我一个int型的宝贝,你需要把宝贝a和宝贝b加起来还给我,do you get it?
这种情况就是声明定义在一起,那么写成如下代码(完整的可执行的):
接下来,我们再谈一个比较高大上的内容,
那就是,不定参数函数(Variadic functions)。
典型的不定参数函数就是众所周知的printf函数和scanf函数。
我们来看看printf怎么使用的:int a = 1, b = 2, c = 3; printf("%d,%d,%d", a, b, c);
再来看看printf怎么声明的:printf(const char * restrict, ...);
printf函数的第一个参数restrict实际是一个参数检查列表,这个参数指向的字符串内让打印多少个int就得打印多少个int。
在实际的程序编写过程中,你想让她打印几个int就写几个%d,写1000个%d都行,printf就傻傻地打印1000个int。
这是一项超级棒的语法啊!我认为其好玩性仅次于vb的可选函数参数和函数参数默认值语法:
Declare Function Bar(a As Integer, Optional b As Integer = 1) As Integer
想象一下我们如何利用它?
对了,做一个求和函数:
大概是这样:sum(1,2,3)得出6; sum(1,2,3,4,5)得出15.
代码如下:
#include <stdio.h>
#include <stdarg.h> // 包含允许使用不定参函数的头文件。
int sum(int count, ...) // 参数count代表要求几个数的和。不确定的参数列表使用 “...” 代替。