面向对象的分析与设计 实验报告一
一.变量的储存类别
auto static register extern
auto变量
函数中的局部变量,如不专门声明为static存储类别,都是动态地分配存储空间的,数据存储在动态存储区中。函数中的形参和在函数中定义的变量(包括在复合语句中定义的变量),都属此类,在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。这类局部变量称为自动变量。自动变量用关键字auto作存储类别的声明。
int f(int a) /*定义f函数,a为参数*/ { auto int b,c=3; /*定义b,c自动变量*/ }
用static声明局部变量
有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,这时就应该指定局部变量为“静态局部变量”,用关键字static进行声明。
float test(int a) { auto int b=0; static float c=0.5; cout<<"b = "<<b<<" c="<<c<<endl; //当中定义的c 就是静态变量, //在函数调用结束后不消失,而保留原值 c++; return(a+b+c); } int main(void) { int a=2,i; for(i=0;i<3;i++){ cout<<test(a)<<endl; } return 0; }
1)静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,占动态存储空间,函数调用结束后即释放。
2)静态局部变量在编译时赋初值,即只赋初值一次;而对自动变量赋初值是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。
3)如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。而对自动变量来说,如果不赋初值则它的值是一个不确定的值。
register变量
为了提高效率,允许将局部变量得值放在CPU中的寄存器中,这种变量叫“寄存器变量”,用关键字register作声明。
int fac(int n) { register int i,f=1; for(i=1;i<=n;i++) f=f*i; return(f); } int main(void) { int i; for(i=0;i<=5;i++) cout<<i<<"!="<<fac(i)<<endl; return 0; }
1) 只有局部自动变量和形式参数可以作为寄存器变量;
2)一个计算机系统中的寄存器数目有限,不能定义任意多个寄存器变量;
3)局部静态变量不能定义为寄存器变量。
用extern声明外部变量
外部变量(即全局变量)是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件终了。如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量作“外部变量声明”。表示该变量是一个已经定义的外部变量。有了此声明,就可以从“声明”处起,合法地使用该外部变量。
int max(int x,int y) { int z; z=x>y?x:y; return(z); } int main(void) { extern A,B; //A,B是是在函数的外部定义的, //它的作用域为从变量定义处开始, //到本程序文件的末尾。 cout<<max(A,B)<<endl; return 0; } int A=13,B=-8;
二.作用域
(1) 全局变量:
全局变量是在所有函数体的外部定义的,程序的所在部分(甚至其它文件中的代码)都可以使用。全局变量不受作用域的影响(也就是说,全局变量的生命期一直到程序的结束)。如果在一个文件中使用extern关键字来声明另一个文件中存在的全局变量,那么这个文件可以使用这个数据。
(2) 局部变量:
局部变量出现在一个作用域内,它们是局限于一个函数的。局部变量经常被称为自动变量,因为它们在进入作用域时自动生成,离开作用域时自动消失。关键字auto可以显式地说明这个问题,但是局部变量默认为auto,所以没有必要声明为auto。
#include<iostream> using namespace std; int b = 0; //b为全局变量 int max(int x,int y) { b = 9; int z; //z 为局部变量 默认为auto 仅在函数体内的作用域 z =x>y?x:y; return z; } int main() { int a = b; int j =1; cout<<a++<<endl; { int j = 8; // j 只在{}中有用 cout<<j<<endl; } cout<<j<<endl; cout<<"a与b的最大值"<<max(a,b)<<endl; cout<<"a与b的最大值(b在函数max中改变了)"<<max(a,b)<<endl; return 0; }
三.参数的类型
值传递,指针传递和引用传递
1、值传递:形参是实参的拷贝,改变函数形参的值并不会影响外部实参的值,这是最常用的一种传参方法,也是最简单的一种传参方法,只需要传递参数,返回值那是return考虑的;
void swap1(int a,int b)
2、指针传递:指针传递参数从本质上来说也是值传递,它传递的是一个地址。【值传递过程中,被调函数的形参作为被调函数的局部变量来处理,即在函数内的栈中开辟内存空间以存放由主调函数放进来的实参的值,从而成了实参的一个副本(记住这个,函数内参数的是实参的副本)】。由于指针传递的是外部实参的地址,当被调函数的形参值发生改变时,自然外部实参值也发生改变。
void swap2(int *a,int *b)
3、引用传递:被调函数的形参虽然也作为局部变量在栈中开辟了内存空间,但是栈中存放的是由主调函数放进的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中实参变量(实参和形参通过引用,合二为一,说白点就是:一个人,有两个名字那种;后面想会详细说)。因此,形参的任何改动都会直接影响到实参。
void swap3(int &a,int &b)
#include<iostream> using namespace std; //值传递 void swap1(int a,int b) { int temp; temp = a; a = b; b = temp; } //引用传递 void swap2(int &a,int &b) { int temp; temp = a; a = b; b = temp; } //指针传递 void swap3(int *a,int *b) { int temp; temp = *a; *a = *b; *b = temp; } int main() { int a = 1,b = 2; cout<<"现在 a 和 b的值 为"<<a<<" "<<b<<endl; swap1(a,b); cout<<"经过swap1()值传递参数函数后a,b的值分别为"<<a<<" "<<b<<endl; cout<<"现在 a 和 b的值 为"<<a<<" "<<b<<endl; swap2(a,b); cout<<"经过swap2()引用传递参数函数后a,b的值分别为"<<a<<" "<<b<<endl; cout<<"现在 a 和 b的值 为"<<a<<" "<<b<<endl; swap3(&a,&b); cout<<"经过swap3()指针传递参数函数后a,b的值分别为"<<a<<" "<<b<<endl; return 0; }