变量的作用域
在C++程序中,我们所定义的函数名、变量名等名字,都由作用域来划分其可见范围。作用域指,在程序中用花括号括起来的代码块。在所有函数体之外定义的对象拥有全局作用域,为全局变量,在程序的任何地方都可访问。在花括号内定义的名字拥有块作用域,为局部变量,只在该块内部以及嵌套在块中的子块内可访问。通常,名字在作用域的有限区间内可见,从名字定义的位置开始,到名字所在的(最内层)作用域的结尾为止。
以下代码对程序的作用域做了说明:
#include<iostream>
#include<string>
using namespace std;
int a=5; // 变量a定义于所有花括号之外,拥有全局作用域,在整个程序范围内都可以访问
// swap拥有全局作用域
// 形参为在函数的形参列表中声明的局部变量,拥有块作用域,为局部变量,当前代码块内可用
void swap(int &v1, int &v2)
{
int temp = v2; // 定义在块内的局部变量,仅在块内可访问
v2 = v1;
v1 = temp;
}
int main()
{
a=10; // 在当前作用域内访问全局变量a
swap(a,6); // swap在整个程序范围内可调用
}
怎样执行函数?
我们通过调用运算符来执行函数。调用运算符是一对圆括号,它作用于一个表达式,该表达式是函数或指向函数的指针;圆括号之内是实参列表,我们用实参初始化函数的形参,即,将实参的值拷贝给形参(参数类型为非引用,如果为引用则是将形参和和实参对象进行绑定)。调用表达式的类型是函数的返回值类型。
int ri(int w, int n)
{
cout<<"调用执行函数"<<endl;
}
int main()
{
int a=6;
int b=9;
ri(a,b); // 调用运算符作用于函数表达式
}
函数调用时发生了什么?
在main函数中,当程序运行到函数调用语句时:
首先,用实参初始化形参
其次,代码将进入被调用函数内执行
然后,遇到return语句时函数结束执行
最后,程序从被调函数转到主调函数继续执行,返回return语句中的值(若函数有返回值),函数的返回值用于初始化调用表达式的结果。并将被调函数运行时为局部对象申请的内存资源销毁(局部静态对象除外)。
参数传递
函数调用时,实参对形参进行初始化的机理与变量的初始化一样。如果形参是引用类型,它将绑定到对应的实参上;否则,将实参的值拷贝后赋值给形参。
- 非引用传递
值传递:
将实参的值拷贝给形参后,实参和形参是相互独立的对象。形参的改变不会使实参改变。实参和形参本质上讲只是一个为变量赋值的操作,初始值被拷贝给对象,此时,对变量的改动不会影响初始值,也就是实参。所以,此交换函数并不能实现变量的交换。
//交换两个变量的值
void ti(int u1,int u2)
{
int d=u1;
u1=u2;
u2=d;
}
int main()
{
int a=6;
int b=9;
ti(a,b);
cout<<"a="<<a<<endl<<"b="<<b<<endl;
}
输出结果:
指针传递:
函数的形参类型为指针类型时,其本质还是值传递,拷贝的是指针变量。拷贝之后,两个指针变量是不同的指针变量,但它们所指的是同一个内存空间。
case1: 虽然形参是指针类型,实参对形参的初始化也传递的是mm和nn的地址值,交换函数内部虽然交换的是mm和nn的地址值,但并未交换mm和nn所指向的对象的值。
void swap1(int *r1, int *r2)
{
int *u = r1;
r1 = r2;
r2 = u;
}
int main()
{
int mm = 6;
int nn = 10;
swap1(&mm, &nn);
cout << "mm=" << mm << endl << "nn=" << nn << endl;
}
输出结果:
case2: 那么,我们可以直接用被初始化后的形参,通过解引用访问mmm和nnn的值,并直接对其值进行交换:
void swap2(int *r1, int *r2)
{
int u = *r1;
*r1 = *r2;
*r2 = u;
}
int main()
{
int mmm = 6;
int nnn = 10;
swap2(&mmm, &nnn);
cout << "mmm=" << mmm << endl << "nnn=" << nnn << endl;
}
输出结果:
2. 引用传递
当形参是引用类型时,实参对形参的初始化实则是实参绑定了形参,形参是实参的别名,对形参的改变也就是对实参的改变。
void swap3(int &r1, int &r2)
{
int u = r1;
r1 = r2;
r2 = u;
}
int main()
{
int mmmm = 6;
int nnnn = 10;
swap2(&mmmm, &nnnn);
cout << "mmmm=" << mmmm << endl << "nnnn=" << nnnn << endl;
}
输出结果: