C++函数
文章目录
1.基本工作
- 提供函数的定义,及实现
- 提供函数的原型 //必须的,为了提高编译器的执行效率!可以省略函数名,或者直接将函数定义放在main前
//作用
//1.编译器能够正确的处理函数返回值
//2.编译器能够检查使用的参数数目是否正确
//3.编译器检查使用的参数类型是否正确
- 调用函数
2.函数种类
- 有返回值函数
//C++不能直接返回数组,只能返回整型,浮点型,char,string型,指针,对象,结构,返回类型不一致将发生强制类型转换!!
- 无返回值函数,即void
3.函数参数传递
- 按值传递
//
double max(int a){
return a;
}
int b=10;
max(b);//调用时,按值传递,该函数将创建一个临时变量a,初始化为10,进行传入,操作的只是b的副本,对b无法修改,使用引用传递,有修改的风险,可设置为const常量引用!!
double max(const int &a){
return a;
}
max(b);
- 引用传递
3.1传入数组参数
传入方法:
//方法一:传入数组名
int sum(int arr[],int n);//表示传入n长度的数组参数
//调用
int a1[]={2,4,5,7,3};
sum(a1,5);//这里函数名相当于一个指向数组的指针
//方法二:传入数组指针
int sum(int *arr,int n);//表示传入n长度的数组参数,这里输入的sizeof arr只是一个指针长度8字节
//调用
int a1[]={2,4,5,7,3};
sum(a1,5);//这里函数名相当于一个指向数组的指针
//方法三:传入数组两个区间指针
int sum(int *begin,int *end){
int total;
for(int *p=begin;p!=end;p++){
total+=*p;
}
return total;
}
int a1[]={1,2,3,5,6,7,8,9,10};
sum(a1+1,a1+8);//传入1~8区间的数组
//方法四:传入二维数组
int sum(int (*arr)[4],int n);//表示传入一个指向4个元素的数组指针
//or
int sum(int arr[][4],int n);
int a1[3][4]={{1,2,3,4},{35,5,7,8},{5,7,8,9}};
//解释,这里传入一个数组,只是将数组的地址和数组长度传入,并没有传入具体的数组内容!!,意味着,实际操作的就是数组本身!!!这跟传入引用和指针效果都是一样的,千万要注意到底要不要修改传入的原本数据值,可以使用const修饰
int sum(const int *arr,int n);
//实例
#include <iostream>
#include <string>
using namespace std;
double max(int arr[],int n){
cout<<sizeof arr<<"\n";
int total;
for (int i=0;i<n;i++){
total+=arr[i];
}
cout<<total<<"\n";
return total;
}
int main(){
int a1[10]={1,2,454,65,4,2,6,3,2};
cout<<sizeof a1<<"\n";
max(a1,10);
max(a1,2);
max(a1+5,5); //可以选择性传入数组段
}//打印结果
/* 40 //数组全部长度a1为40字节
8 //传入数组指针长度为8字节
539
8
3
8
13 */
3.2传入结构参数
//结构体作为参数,传入可以视为单值变量,可以按值传递,或者引用传递,不同的是,结构名不代表地址,必须使用 &结构名,作为结构对象的引用
//直接值传递
struct book{
char b_name[20];
char b_author[10];
float b_price;
};
book total_price(book b1,book b2){
book t;
t.b_price=b1.b_price+b2.b_price;
return t;
}
book p1={"C++","yang",21.3};
book p2={"java","xu",23.32};
cout<<total_price(p1,p2).b_price;
//输出44.62
//结构体一般采用,引用传递,节省时间和空间的消耗
book total_price(const book &b1,const book &b2){
book t;
t.b_price=b1.b_price+b2.b_price;
return t;
}
//或者使用传递指针参数
book total_price(const book *b1,const book *b2){
book t;
t.b_price=b1->b_price+b2->b_price;//这时只能使用指针间接成员运算符->访问
return t;
}
book p1={"C++","yang",21.3};
book p2={"java","xu",23.32};
cout<<total_price(&p1,&p2).b_price;//将地址传递给指针参数
3.3传入类–对象参数
3.4传入函数指针参数
3.5传入字符串参数
//方法一:直接传入一个string类引用对象
int m_num(const string &s);
string s1="yangmfddmmdfmm";
m_num(s1);
//方法二:传入字符串首地址
char m1[15]="gsdgdmgdmdgmgm";
char *m2="gsdmgmdmdmsmsdmf";
int m_num(const char *c){
cout<<*c;
return 0;
}
m_num(m1);
m_num(m2);
4.函数的递归操作
4.1含有一个递归调用的递归
//形如:
void recursion(argument1){
statements1
if(test)
recursion(argument2)
statements2
}
//表示函数自己调用自己,这样将无限循环下去,必须将递归调用置于一个边界条件下,为false时,递归调用结束
//只要if为true时,调用recursion,都会执行statements1,不会执行statements2,
//只要if为false时,就会执行statements2,然后结束,并将控制权返回给前一个调用!!
//因此,如果recursion调用了5次,则statements1执行了5次,之后statements2与函数调用相反的顺序执行5次,从而调用结束!!!
//实例
void test(int n){
cout<<"this level n="<<n<<"\t"<<&n<<"\n";
if(n>0)
test(n-1);
cout<<"this rather level n="<<n<<"\t"<<&n<<"\n";
}
int main(){
test(4);
}
//输出:
/*
this level n=4 0x71fe30
this level n=3 0x71fdf0
this level n=2 0x71fdb0
this level n=1 0x71fd70
this level n=0 0x71fd30
this rather level n=0 0x71fd30 //可以看出每次调用函数都会创建占用不同的内存
this rather level n=1 0x71fd70 //但是同一次调用,函数内的变量占用相同首地址的内存
this rather level n=2 0x71fdb0
this rather level n=3 0x71fdf0
this rather level n=4 0x71fe30
*/
4.2包含多个递归调用的递归
//主要采用分而治之的思想,将一个大问题逐渐分解成两到三个小相同的问题,再细分,直到能解决问题为止
//如:汉诺塔的问题,将n块铁饼,在保证不扰乱高低顺序情况下,将n块通过塔p2,移动至塔p3
void move(char c1,char c2){
cout<<c1<<"->"<<c2<<"\n";
}
void hanoi(int n,char one,char two,char three){//大问题是将n块从塔1借助塔2,移到塔3
if(n==1){
move(one,three);
}else{
hanoi(n-1,one,three,two);//小问题是先将n-1块从塔1借助,塔3移到塔2
move(one,three); //移动塔1剩余的一块
hanoi(n-1,two,one,three);//再将n-1块从塔2借助塔1,移动到塔3 ,大问题就解决了!
}
}
int main(){
hanoi(3,'A','B','C');
}//输出如下:
/* A->C
A->B
C->B
A->C
B->A
B->C
A->C
*/
//缺点:由于调用一次产生2个调用,2个产生4个,4个产生8个,n次调用产生2^n个,成指数级增长,可见时间及空间的消耗是巨大的!!