由于有C语言基础和java基础,只写了C++函数的部分介绍。
1.函数的基础
一个典型的函数应该包括:返回值类型、函数名字、0个或者多个函数参数。格式为:返回值类型 函数名(参数1,...,...)
int returnInt(int a); //返回int型的函数,函数名为returnInt,参数类型int,参数名字 a
int returnInt2(int a);
int *returnPoint(int *a); //返回int型指针
int &returnRefrence(int &b); //返回int型引用
函数参数在声明时可以省略参数名,但是不能省略参数类型。如:
void fx(int);
在上面的函数声明中,void是返回的类型,表示无返回值,在函数的内部可以不用加return语句。int表示参数的类型,值得注意的是,这个只是在声明的时候可以省略参数名。编写的时候还是要写出它的参数名,方便调用,如:
void fx(int a){...}
在函数中,a就是它传递的参数,这个函数就是上面声明的fx函数。
2.局部对象
对象是有生命周期的,对象的生命周期是程序执行过程中该对象存在的一段时间。在函数中创建的参数,作用域都在该函数中,离开该函数,这个参数就会失效。我们的形参就是函数中的自动对象,自动对象是只存在于块执行期间,离开这个函数就会失效。
我们可以在函数中设置静态变量来获取拥有贯穿函数生命周期的变量。也就是局部静态变量。只需要在变量的申明前面加上static,例如
static int cc;
在函数中声明的cc,就是局部静态变量,它会在调用该函数时初始化,并且知道程序终止才会销毁,即使对象所在的函数结束也不会对它有影响。
3.分离式编译
(这部分是按照C++ primer写的,本人没有做)
为了允许编写程序时按照逻辑关系将其分开,把函数的代码存在其它源文件中,C++语言支持分离式编译。分离式编译允许我们把程序分割到几个文件中去,每个文件独立编译。例如,假设fact函数的定义位于一个fact.cc的文件中。它的声明位于Chapter6.h的头文件中。显然与其它所用的fact函数的文件一样。fact.cc应该包含Chapter6.h头文件。另外,在名为factMain.cc的文件中创建main函数,mian函数将调用fact函数,要生成可执行文件必须告诉编译器我们的代码在哪里。编译过程如下:
$ CC factMain.cc fact.cc # generates factMin.exe or a.out
$ CC factMain.cc fact.cc -o main # genrates main or main.exe
CC是编译器名字,$是系统提示符,#后面是命令行的注释语句。
4.参数传递和返回
参数传递包括值传递,址传递和引用传递,其中址传递和引用传递是可以在函数内部该传递实参的值。若想限定不改变,可以在形参前加const修饰,使用址传递和引用传递的优点是,避免了大型对象拷贝的开销。函数的返回类型是指针和引用时,拥有他们自身的特性。代码如下:
#include<stdlib.h>
#include<iostream>
using namespace std;
int *returnPoint(int *a);
int &returnRefrence(int &b);
int returnInt(int a);
int returnInt2(int a);
void returnInt3(int); //省略形参名的声明。
int main() {
int a = 1;
int b = 2;
int &bb = b;
returnInt3(2.5); //会产生类型转换为int型
int d = returnInt(a);
cout << "returnInt a:" << d << endl;
int e = returnInt2(a);
cout << "returnInt2 a:" << e << endl;
auto re = returnPoint(&a);
cout << "re:"<<re << endl; //此时re是地址,需要加*才能输出返回的指向
cout << "*re:" << *re << endl;
*returnPoint(&a) = 200; //此时a的值已经改变为200
cout << "a:" << a << endl;
cout<< "b:" << returnRefrence(bb) << endl;
returnRefrence(bb) = 233; //返回是引用,所以可以赋值,与返回是指针类似
cout << "after_change b:" << b << endl;
system("pause");
}
int returnInt(int a) {
a = 12;
return a;
}
int returnInt2(int a) {
int c = a+10;
return c;
}
int *returnPoint(int *a) {
*a = 111;
return a;
}
int &returnRefrence(int &b) {
b = 22;
return b;
}
void returnInt3(int a) {
cout << "nihao :"<<a << endl;
}
5.数组与函数
由于数组有两个特性:
1.不允许拷贝和赋值
int a[] ={0,1,2}
int a2[] = a; //错误的,不能拷贝
2.使用数组时会转换为指针。
它的两个特性在使用数组作为参数传递时,只能作为指针处理,指向的是数组首个对象。如果直接传递数组,我们不知道数组的确切长度,所以调用者应该提供额外信息。以下是三种处理数组的方式:
使用标记指定数组长度:
void printStr(const char *cp){
if(cp){ //1.cp不是空指针
while(*cp){ //cp的指向不是空字符
cout<<*cp++;
}
}
}
使用标准库规范:(调用方式printStr(begin(j),end(j)),j是int数组 )
void printStr(const int *beg,const int *end){
//通过传入的数组首指针和尾指针来处理
while(beg!=end){
cout<<*beg++<endl;
}
}
显式传递一个表示数组大小的参数:(比较简单,不举例了)。