目录
函数返回两个及以上的值(通过引用 / 指针 / 全局变量实现)
//引用调用(实现两个变量的交换)
1.用值调用的方式(无法实现,函数无法更改a,b所在地址的值)
#include<iostream>
using namespace std;
void swap(int a,int b);
int main(){
int a=1,b=2;
cout<<"a:"<<a<<" b:"<<b<<endl;
swap(a,b);
cout<<"a:"<<a<<" b:"<<b<<endl;
return 0;
}
void swap(int a,int b){
int temp;
temp=a;
a=b;
b=temp;
}
2.用指针方式
#include<iostream>
void swap(int *a,int *b);
using namespace std;
int main(){
int a=1,b=2;
cout<<"a:"<<a<<" b:"<<b<<endl;
swap(&a,&b);
cout<<"a:"<<a<<" b:"<<b<<endl;
return 0;
}
void swap(int *a,int *b){
int temp;
temp=*a;
*a=*b;
*b=temp;
}
3.用引用调用方式实现
#include<iostream>
using namespace std;
void swap(int &a,int &b);
int main(){
int a=1,b=2;
cout<<"a:"<<a<<" b:"<<b<<endl;
swap(a,b);
cout<<"a:"<<a<<" b:"<<b<<endl;
return 0;
}
void swap(int &a,int &b){
int temp;
temp=a;
a=b;
b=temp;
}
拓:引用(&)变量
//引用(&)变量
#include<iostream>
using namespace std;
int main(){
int j=0,k=10;
int &i=j; //变量i成为变量j的别名
cout<<"i:"<<i<<" j:"<<j<<endl;
cout<<&i<<" "<<&j<<endl;
i=k; //变量i获得变量k的值
k=12;
cout<<"i:"<<i<<" j:"<<j<<" k:"<<k<<endl;
cout<<&i<<" "<<&k<<endl; //证明 i=k 没有让变量i成为变量k的别名
return 0;
}
函数返回两个及以上的值(通过引用 / 指针 / 全局变量实现)
引用 调用
#include<iostream>
using namespace std;
void extremum(const int a[],int n,int &max,int &min);
int main(){
int max,min;
int a[]={12,34,56,7,3,99,67,45,3,80};
extremum(a,sizeof(a)/sizeof(a[0]),max,min);
cout<<"max="<<max<<" min="<<min<<endl;
return 0;
}
void extremum(const int a[],int n,int &max,int &min){
max=min=a[0];
for(int i=0;i<n;i++){
if(max<a[i]) max=a[i];
if(min>a[i]) min=a[i];
}
}
指针-法一
#include<iostream>
using namespace std;
int main(){
int *max,*min; //这个方法不能用函数(反正我不会),(具体原因分析在下面)
//麻烦且没必要
int a[]={12,34,56,7,3,99,67,45,3,80};
max=&a[0];
min=&a[0];
for(int i=0;i<sizeof(a)/sizeof(a[0]);i++){
if(*max<a[i]) max=&a[i]; //将max变为a[i]的别名
if(*min>a[i]) min=&a[i];
}
cout<<"max="<<*max<<" min="<<*min<<endl;
return 0;
}
/*****引用函数造成错误(无法输出)*****
#include<iostream>
void extremum(int a[],int n,int *max,int *min);
using namespace std;
int main(){
int *max,*min;
int a[]={12,34,56,7,3,99,67,45,3,80};
extremum(a,sizeof(a)/sizeof(a[0]),max,min);
cout<<"max="<<*max<<" min="<<*min<<endl; //无法输出
return 0;
}
void extremum(int a[],int n,int *max,int *min){
max=&a[0];
min=&a[0];
for(int i=0;i<n;i++){
if(*max<a[i]) max=&a[i]; //将max变为a[i]的别名
if(*min>a[i]) min=&a[i];
}
}
***************************************/
/*****原因分析*****/
//在extremum函数中sizeof(a)=4,主函数中sizeof(a)=40,
//反正它应该是发生了啥不为我所知的变化就是不行
#include<iostream>
using namespace std;
int main(){
int *a;
*a=8; //指针不能直接指向整数
cout<<*a<<endl; //无法输出
return 0;
}
#include<iostream>
using namespace std;
int main(){
int *a,i=8;
*a=i;
cout<<*a<<endl; //输出8
return 0;
}
指针-法二
#include<iostream>
void extremum(int a[],int n,int *max,int *min);
using namespace std;
int main(){
int a[]={12,34,56,7,3,99,67,45,3,80};
int max,min;
extremum(a,sizeof(a)/sizeof(a[0]),&max,&min); //通过引用(&)将整型int变为指针带入到函数中
cout<<"max="<<max<<" min="<<min<<endl;
return 0;
}
void extremum(int a[],int n,int *max,int *min){
*max=*min=a[0];
for(int i=0;i<n;i++){
if(*max<a[i]) *max=a[i];
if(*min>a[i]) *min=a[i];
}
}
指针-法三
#include<iostream>
int max,min;
void extremum(int a[],int n);
int main(){
int a[]={12,34,56,7,3,99,67,45,3,80};
extremum(a,sizeof(a)/sizeof(a[0]));
std::cout<<"max="<<max<<" min="<<min<<std::endl;
return 0;
}
void extremum(int a[],int n){
int *p;
max=min=*a; //对于数组a,*a的就是指向a数组中的第一个数
for(p=a+1;p<a+n;p++){ //p=a+n的意思是指针p指向数组a的最后一位的后一位
//从a+1即a数组中第二个数开始,因为max和min的初始化值为a[0]
if(max<*p) max=*p;
if(min>*p) min=*p;
}
}
全局变量
#include<iostream>
int _max,_min; //不能命名为 max(min) , max 和标准库的 std::max 同名了
void extremum(int a[],int n);
using namespace std; //就是有这个的时候,全局变量定义中不能有max和min
int main(){
int a[]={12,34,56,7,3,99,67,45,3,80};
extremum(a,sizeof(a)/sizeof(a[0]));
cout<<"max="<<_max<<" min="<<_min<<endl;
return 0;
}
void extremum(int a[],int n){
_max=_min=a[0];
for(int i=0;i<n;i++){
if(_max<a[i]) _max=a[i];
if(_min>a[i]) _min=a[i];
}
}
独立(常)引用
/* 非参数的独立引用很少使用,因为它们很容易混淆并会破坏程序的结构。
常(独立)引用(const 类型 &引用名=变量名;) */
#include <iostream>
using namespace std;
int main()
{
int j,k;
const int &i=j; //(独立)常引用,变量i成为变量j的一个别名
j=10;
cout<<"j="<<j<<" i="<<i<<endl; //输出 j=10 i=10
k=20;
//i=k; //错误,不允许通过常引用修改变量的值!
j=k; //通过j间接修改是可以的!
cout<<"j="<<j<<" i="<<i<<endl; //输出 j=20 i=20
}
//返回引用
//实例:利用返回引用创建有界数组
#include<iostream>
int &put(int i); //将一个值放入数组中
int get(int i); //从数组中获得一个值
int error=-1; //不能使用const修饰符,因为它是返回引用的返回值(错误情况)
const int MAX=10; //定义最大数组长度(数组的最大下标为MAX-1)
int a[MAX];
using namespace std;
int main(){
put(0)=5;
put(2)=20;
put(9)=1314;
cout<<a[0];
cout<<a[2]<<endl;
cout<<a[9]<<endl;
//下面有意产生错误
put(MAX+2)=6; //数组越界
int i=get(MAX+2); //数组越界
return 0;
}
int &put(int i){
if(i>=0&&i<MAX){
return a[i];
}
else{
cout<<"边界错误(put)"<<endl;
return error;
}
}
int get(int i){
if(i>=0&&i<MAX){
return a[i];
}
else{
cout<<"边界错误(get)"<<endl;
return error;
}
}
不要返回局部变量引用!!!(虽然编译可以通过)
#include <iostream>
int &func();
using namespace std;
int main() {
cout<<(func()=5)<<func()<<endl; //输出520
}
int &func() {
int x=20; //局部变量
return x; //编译可以通过,但不能使用!!
//warning C4172: returning address of local variable or temporary
}
引用变量概念
/*
1.引用变量定义时必须进行初始化。
在程序中对引用的存取都是对它所引用的变量的存取。也不能再指向别的变量!
2.引用与指针不同:
指针的内容或值是某一变量的内存单元地址,
而引用则与初始化它的变量具有相同的内存单元地址。
3.返回引用必须保证返回的引用变量有合法的内存空间,并且不在函数的运行栈中。
一般只能返回全局变量和静态变量。
4.使用const常引用的目的就是提高性能(不需要制作数据的副本)。
使用引用参数而不加const就应该认为该参数将被修改!
5.当函数需要返回多于1个值,或希望修改实参的值时必须使用引用调用。
6.如果条件允许,就应将引用形参声明为const形参,
这样可以避免无意间修改数据而导致编程错误,
此外使用const形参使得函数能够接受const和非const实参,否则只能处理非const数据。
eg.
#include<iostream>
void func(const int &i);
using namespace std;
int main(){
int a=1314;
func(a);
return 0;
}
void func(const int &i){
cout<<i<<endl;
}
7.对比总结:
void func1(int n){
//可以修改n,但值不会返回调用者
} //可用值或变量调用
void func2(int &n){
//可以修改n,值会返回调用者
} //只能用同类型的变量调用该函数
void func3(const int &n){
//根本就不允许修改n
} //可用值或变量调用
//func1/2/3具体如下
#include<iostream>
int func1(int n);
using namespace std;
int main(){
cout<<"4!="<<func1(4)<<endl;
int n=5;
cout<<"5!="<<func1(n)<<endl;
return 0;
}
int func1(int n){ //可用值或变量n调用,2个n(形参和实参)的地址是不一样的!
int fac;
for(fac=1;n>0;n--){
fac*=n;
}
return fac;
} //可以修改n,但值不会返回调用者
#include<iostream>
int func2(int &n);
using namespace std;
int main(){
//cout<<"4!="<<func2(4)<<endl; 错误,只能同类型调用
int n=5,fac=func2(n);
cout<<n<<"!="<<fac<<endl; //输出 0!=120
cout<<&n<<endl;
return 0;
}
int func2(int &n){ //只能用同类型的变量调用该函数
cout<<&n<<endl; //func2的n和main的n的(实参地址传递给形参)地址一致!
int fac;
for(fac=1;n>0;n--){
fac*=n;
}
return fac;
} //可修改n,修改后的值会返回调用者
#include<iostream>
int func3(const int &n);
using namespace std;
int main(){
cout<<"4!="<<func3(4)<<endl;
int n=5,fac=func3(n);
cout<<n<<"!="<<fac<<endl;
return 0;
}
int func3(const int &n){ //可用值或变量调用
int fac=1;
for(int i=n;i>0;i--){ //func2的n和main的n的(实参地址传递给形参)地址当然也一致!
fac*=i;
}
return fac;
} //根本就不允许修改n
拓:实参和形参
/*
1、值传递
实参是变量,表达式等值。
find(int x){}
y= find(z);
上面的例子中,z是实参,x是形参。x变z不变。
在值传递过程中,实参和形参位于内存中两个不同地址中,
实参先自己复制一次拷贝,再把拷贝复制给形参。
所以,在值传递过程中,形参的变化不会对实参有任何的影响。
2、地址传递(也称引用传递)
实参是指针。
在函数调用的时候,实参传递给你的是指针地址,地址一样也就意味着实参和形参是一样的,
当你的形参发生改变时,实参也会发生改变。
find(int &x){}
y= find(z);
上面的例子中,z是实参,x是形参。z随x而改变。
3、const引用传递
find(const int &x){}
y= find(z);
上面的例子中,z是实参,x是形参。z不随x而改变。
(const引用和值传递不一样)在值传递中要进行两次拷贝,浪费内存资源是相当可耻的,
const的出现有效避免了这种情况的出现,只需拷贝一次就够了。 */