这一节我们介绍函数,我们这里的函数和数学上的函数的意思一样么?答案是否定的。 有的编程语言比如Java就把函数成为方法,所以我们这里所要讨论的 函数实际上就是一个解决一般问题的过程,这个可以借助黑盒模型进行理解,现在函数就是一个黑盒,当我们向里面传入数据的时候,黑盒处理之后给出我们结果。
黑盒模型是不是很抽象?用鼠标只能画成酱紫了(偷笑)。
对应于黑盒模型,我们的函数可以传入0个或多个参数,然后返回一个结果,注意函数的出口只有一个那就是return语句,尽管在函数体中可能有多处出现return,但是我们要知道,函数最终返回到调用它的地方,所以出口只有一个。
函数的标准写法是什么呢?
我们有两种方式表示函数
1.先声明后实现
这里提一下main()函数,顾名思义,main()函数是程序的主函数,也就是说,我们的程序,从main()函数开始执行,所以也称为入口函数。
函数的标准写法:
返回类型 函数名(参类型 [参数名],参类型 [参数名],...);//[表示可有可无]
int hello(int n);或者int hello(int);
我们可以在main函数中调用函数A,但是函数A必须在main函数之前声明,不然main函数就认为不存在函数A,因为程序的编译过程是从上而下的。
我们来看一段代码(Let's look at the wrong code...)
#include<iostream>
#include<string>
using namespace std;
int hello(int n);
int main(){
hello(5);
return 0;
}
Paste_Image.png
执行的时候报错,错误提示是说在main函数中引用了无法解析的符号,这是为什么呢?因为,尽管你尽管声明了hello函数,告诉main函数有个叫hello的函数存在,但是,这个函数真的存在么?当main函数按照名字去寻找的时候,发现不认识这个函数,也就是说这个函数没有定义。就像我们使用变量一样,你声明了一个变量,不给它赋值是不能直接拿来用的。
int n;
n = n+1;//这是不合法的,因为我们还没有给变量n赋初值
为了能使main函数成功调用hello函数我们要给hello函数一个定义
比如我们这样定义
int hello(int n){
for(int i =0;i<n;i++){
cout<<"hello world"<<endl;
}
return 0;
}
我们定义了hello函数,就是输出n遍"hello world" ,当然可以有不同的定义,这也就是黑盒模型的本质,盒子里面可以是任何东西。
把这个定义加入到刚刚的例子中试一下
#include<iostream>
#include<string>
using namespace std;
int hello(int n);
int main(){
hello(5);
return 0;
}
int hello(int n){
for (int i = 0; i < n; i++){
cout << "hello world" << endl;
}
return 0;
}
Paste_Image.png
great!
这样我们的main函数就成功调用了hello函数,并且输入的数据是5,得到的结果是 屏幕上输出5行"hello world" 是不是很简单呀,快编写你的第一个函数吧(当然不包括main函数啦,嘿嘿,因为每个程序都要有main函数)
2.同时声明、实现
简单的思考一下,为了能够让main函数成功调用我们的函数A,我们要把函数的声明放在main之前,所以实现部分也要在main之前。
返回类型 函数名称(参数类型 参数名称,参数类型 参数名称...){
函数体
}
#include<iostream>
using namespace std;
int A(int n){
int result=1;
while (n)
result *= n--;
return result;
}
int main(){
cout << A(5) << endl;
return 0;
}
Paste_Image.png
这里函数的声明和实现放在了一起,但是必须要在调用它的函数之前。这个函数A的功能是计算n的阶乘。
以上实例都是main函数调用外部函数,那么函数之间能够互相调用呢?答案是肯定的。
3.函数之间的调用
这里只要记住一条,就是无论调用哪个函数,所被调用函数必须在调用者函数之前声明。
int A(){
do something ...
}
int B(){
A();
}
这里的函数B就调用了函数A
有的人要问,那函数A能不能调用函数B呢,答案也是肯定的。但是在A之前要先声明B看下面的例子
#include<iostream>
using namespace std;
void B();
void A(){
cout << "A" << endl;
B();
}
void B(){
cout << "B" << endl;
A();
}
int main(){
A();
return 0;
}
这里我们main函数调用了A,A又调用了B,B又调用了A,A又调用了B,...,没错,这将会一直调用下去,也就构成了死循环。
Paste_Image.png因为函数一直在调用,所以程序没法终止,截图为部分。那么我们有必要两个函数之间互相调用么,答案也是肯定的,因为我们外加一些条件就能够很好的利用他们了,看下例
#include<iostream>
using namespace std;
static int n = 10;
void B();
void A(){
if (n < 0)
return;
n--;
cout << "A" << endl;
B();
}
void B(){
cout << "B" << endl;
A();
}
int main(){
A();
return 0;
}
Paste_Image.png
既然相互调用会构成死循环,我们就在函数里加入返回条件,若满足条件则直接返回,不在调用。这样就能达到我们的目的了。
4.返回值类型
既然函数都要有返回类型,那么返回类型有哪些呢?
void
int
bool
char
string
float
...
没错只要能作为数据类型的都可以作为函数的返回类型,
void表示返回为空,就是可以不返回,或者直接return;
为什么要设置返回类型呢? 因为函数的输出结果大都会有类型,为了能够在调用处正确的给变量赋值,所以要写明函数的返回值类型
5.形式参数(形参)
什么是形式参数呢?形参就是传入到我们的黑盒(函数)的参数,在函数声明和定义的时候使用的,形参没有具体的数值,只有数据类型,当我们调用这个函数的时候,我们用实参传入,从而经过函数得到结果,实参与形参对应,实参表示参数不仅有数据类型,而且有具体的数值。
#include<iostream>
using namespace std;
int A(int n){
return n*2;
}
int main(){
A(5);
return 0;
}
Paste_Image.png
这个图很好的反映了形参和实参的区别。
形参出现在函数定义中,在整个函数体都可用,离开函数不能使用
实参出现在主调函数中,进入被调函数后也不能使用
函数调用时,主调函数把实参的值传递给被调函数的形参,从而完成从主调函数向被调函数的数据传送。
函数的基本问题就讲到这里,以后会经常用到各种函数。
网友评论