310 likes | 472 Views
面向对象程序设计. 山东师范大学信息科学与工程学院 刘弘. 第三章 指针和引用. 3.1 指针 3.2 引用 3.3 指针和引用的区别 3.4 指向数组的指针 3.5 结构. 3.1 指针. 在计算机中,所有的数据都是存放在存储器中的。一般把存储器中的一个字节称为一个内存单元。为了正确地访问这些内存单元,必须为每个内存单元编上号。根据一个内存单元的编号即可找到该内存单元。内存单元的编号也叫做地址。既然根据内存单元的编号或地址就可以找到所需的内存单元,所以把这个地址称为指针。 对于一个内存单元来说,单元的地址即为指针,其中存放的数据是单元的内容。.
E N D
面向对象程序设计 山东师范大学信息科学与工程学院 刘弘
第三章 指针和引用 3.1 指针 3.2 引用 3.3 指针和引用的区别 3.4 指向数组的指针 3.5 结构
3.1 指针 在计算机中,所有的数据都是存放在存储器中的。一般把存储器中的一个字节称为一个内存单元。为了正确地访问这些内存单元,必须为每个内存单元编上号。根据一个内存单元的编号即可找到该内存单元。内存单元的编号也叫做地址。既然根据内存单元的编号或地址就可以找到所需的内存单元,所以把这个地址称为指针。 对于一个内存单元来说,单元的地址即为指针,其中存放的数据是单元的内容。
在C++语言中,允许用一个变量来存放指针,这种变量称为指针变量。因此,一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。在C++语言中,允许用一个变量来存放指针,这种变量称为指针变量。因此,一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。 一个指针是一个地址,是一个常量。而一个指针变量却可以被赋予不同的指针值,是变量。 通常把指针变量简称为指针,但指针变量和指针的意义是不一样的。
011A K 011B P 011C 011A …… C char C=‘K’; char *p=&C;
指针定义:<类型> *<指针名1>, *<指针名2>,…; 例: int *ip1,ip2; char *pc; double *dp1,dp2; char (*pa)[3];//指向一维数组的指针 ip1是一个指向整型变量的指针变量,而ip2则是一个整型变量,而不是指针。
指针的赋值 任何一种类型的指针所赋的值都是内存地址值。一般变量、数组元素、结构成员等其地址值都表示为变量名前加运算符&. int *ip1,ip2; ip1=&ip2; int a[10],*p=a; int b[2][3],(*p)[3]; p=b;//p指向二维数组的第0行
下面的定义以及对两个指针pi和pi2的赋值都是合法的。下面的定义以及对两个指针pi和pi2的赋值都是合法的。 int ival=1024; int *pi=0; //pi被初始化为没有指向任何对象 int *pi2=&ival; //pi2被初始化为ival的地址 pi=pi2; //ok:pi和pi2现在都指向ival pi2=0; //现在pi2没有指向任何对象 指针不能持有非地址值。例如,下面的赋值将导致编译错误: pi=ival; //错误:pi被赋以int值ival
指针不能被初始化或赋值为其它类型对象的地址值。例如,已知如下定义:指针不能被初始化或赋值为其它类型对象的地址值。例如,已知如下定义: double dval; double *pd=&dval; 那么,下面两条语句都会引起编译时刻错误: pi=pd; //无效的类型赋值:int *<=double * pi=&dval;
3.1.2 指针的运算 (1)取地址运算符& 取地址运算符&是单目运算符,其结合性为自右至左,其功能是取变量的地址。前面介绍指针变量赋值中,我们已经了解并使用了&运算符。 (2)取内容运算符* 取内容运算符*是单目运算符,其结合性为自右至左,用来表示取指针变量所指的变量的内容。
注意:指针运算符*和指针变量说明中的指针说明符*不是一回事。在指针变量说明中,“*”是类型说明符,而表达式中出现的“*”则是一个运算符,用以表示取指针变量所指的变量的内容。注意:指针运算符*和指针变量说明中的指针说明符*不是一回事。在指针变量说明中,“*”是类型说明符,而表达式中出现的“*”则是一个运算符,用以表示取指针变量所指的变量的内容。 void main(){ int a=5,*p=&a; cout<<*p; }
指针变量的运算 (1)赋值运算 ①指针变量初始化赋值。 ②把一个变量的地址赋予指向相同数据类型的指针变量。例如: inta,*pa; pa=&a; ③把一个指针变量的值赋予指向相同类型变量的另一个指针变量。例如: inta,*pa=&a,*pb; pb=pa;//把a的地址赋予指针变量pb
④把数组的首地址赋予指向数组的指针变量。例如:④把数组的首地址赋予指向数组的指针变量。例如: inta[5],*pa; pa=a;//数组名表示数组的首地址,故可赋予指向数组的指针变量pa ⑤把字符串的首地址赋予指向字符类型的指针变量。例如: char*pc; pc="Clanguage";或用初始化赋值的方法写为:char*pc="CLanguage"; ⑥把函数的入口地址赋予指向函数的指针变量。例如: int(*pf)(); pf=f;//f为函数名
(2)地址加减算术运算 对于指向数组的指针变量,可以加上或减去一个整数n。设pa是指向数组a的指针变量,则pa+n,pa-n,pa++,++pa,pa--,--pa运算都是合法的。指针变量加或减一个整数n的意义是把指针指向的当前位置(指向某数组元素)向前或向后移动n个位置。应该注意,数组指针变量向前或向后移动一个位置和地址加1或减1在概念上是不同的。因为数组可以有不同的类型,各种类型的数组元素所占的字节长度是不同的。如指针变量加1,即向后移动1个位置表示指针变量指向下一个数据元素的首地址。而不是在原地址基础上加1。
两指针变量相减 两指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数。实际上是两个指针值(地址)相减之差再除以该数组元素的长度(字节数)。例如pf1和pf2是指向同一浮点数组的两个指针变量,设pf1的值为2010H,pf2的值为2000H,而浮点数组每个元素占4个字节,所以pf1-pf2的结果为(2010H-2000H)/4=4,表示pf1和pf2之间相差4个元素。两个指针变量不能进行加法运算。
两指针变量进行关系运算 • 指向同一数组的两指针变量进行关系运算可表示它们所指数组元素之间的关系。例如: • pf1==pf2表示pf1和pf2指向同一数组元素 • pf1>pf2表示pf1处于高地址位置 • pf1<pf2表示pf2处于低地址位置
例3.1 #include <iostream.h> void main() { int a=10,b=20,s,t,*pa,*pb; pa=&a; pb=&b; s=*pa+*pb; t=*pa**pb; cout<<"s="<<s<<endl<<"t="<<t<<endl; }
3.1.3指针的应用及注意的问题 指针的应用——传递参数 例3.3 # include <iostream.h> void example(int *a1,int &b1,int c1) { *a1*=3;//等价于 *a1=*a1*3 ++b1; ++c1; } void main() { int b,c,d=6; int *a=&d; b=7; c=10; example(a,b,c);//分别是传址,引用和传值调用 cout <<"*a="<<*a<<endl; cout <<"b="<<b<<endl; cout <<"c="<<c<<endl; }
3.2 引用 引用(reference)又称别名(alias),它可以用作对象的另一个名字。通过引用我们可以间接的操纵对象,使用方式类似于指针,但是不需要指针的语法。在实际应用中,引用主要被用作函数的形式参数。
<类型>&<引用名>(<变量名>); 或者 <类型>&<引用名>=<变量名>; 引用类型用类型标识符和一个取地址操作符来定义,引用必须被初始化。 例: int a=3; //int &m(a); int &m=a; m=m+5;
例: int ival=1024; int &refval=ival; //refval是一个指向ival的引用 int &refval2; //错误:引用必须被初始化为指向一个对象 虽然引用也可以被用作一种指针,但是相对指针那样用一个对象的地址来初始化引用却是错误的。 int ival=1024; int &refval=&ival; //错误:refval是int类型,不是int* int *pi=&ival; int *&refptr=pi; //ok:refptr是一个指针的引用 一旦引用已经定义,它就不能再指向其他的对象(这是它为什么必须被初始化的原因)。
每个引用的定义都必须以取地址操作符开始 int ival=1024,ival2=2048; //定义两个int类型的对象 int &rval=ival,rval2=ival2; //定义一个引用和一个对象 int ival3=1024,*pi=&ival3,&ri=ival3; //定义一个对象、一个指针和一个引用 int &rval3=ival3,&rval4=ival2; //定义两个引用
#include <iostream.h> void main() { int val(5);//val的初值为5 int &refv=val; refv=refv+5; cout<<val<<endl; int *p=&refv,val1(refv);//vall是整型变量,初值为refv的值。 cout<<*p<<"\t"<<val1<<endl; }
3.3 指针与引用的区别 1.在任何情况下都不能使用指向空值的引用。一个引用必须总是指向某些对象。因此如果使用一个变量并让它指向一个对象,某些时候也可能不指向任何对象,这时应该把变量声明为指针,因为这样可以赋空值给该变量。 如果变量肯定指向一个对象,例如当你的设计不允许变量为空时,你就可以把变量声明为引用。
2.指针与引用的另一个重要的不同是指针可以被重新赋值以指向另一个不同的对象。但是引用则总是指向在初始化时被指定的对象,以后不能改变。2.指针与引用的另一个重要的不同是指针可以被重新赋值以指向另一个不同的对象。但是引用则总是指向在初始化时被指定的对象,以后不能改变。 • #include <iostream.h> • void main() • { • char s1='N'; • char s2='C'; • char &rs = s1; // rs引用 s1 • char *ps = &s1; // ps 指向 s1 • rs = s2; // rs仍旧引用s1,但是s1的值现在是'C' • ps = &s2; // ps现在指向s2,s1没有改变 • cout<<"rs="<<rs<<endl; • cout<<"ps="<<*ps<<endl; • }
3.4指向数组的指针 在一个指针变量中存放一个数组或一个函数的首地址有何意义呢?因为数组或函数都是连续存放的。通过访问指针变量取得了数组或函数的首地址,也就找到了该数组或函数。这样一来,凡是出现数组,函数的地方都可以用一个指针变量来表示,只要该指针变量中赋予数组或函数的首地址即可。这样做,将会使程序的概念十分清楚。
[例3.8] #include <iostream.h> int main() { int ia[9]={0,1,1,3,5,8,13,21}; int *pbegin=ia; int *pend=ia+9; while (pbegin!=pend) { cout<<*pbegin<<' '; ++pbegin; } }
3.4.2多维数组的指针变量 二维数组指针变量说明的一般形式为: 类型说明符(*指针变量名)[长度] 其中“类型说明符”为所指数组的数据类型。“*”表示其后的变量是指针类型, “长度”表示二维数组分解为多个一维数组时,一维数组的长度,也就是二维数组的列数。应注意“(*指针变量名)”两边的括号不可少,如缺少括号则表示是指针数组意义就完全不同了。
[例3.11] #include <iostream.h> void main() { static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11}; int(*p)[4]; int i,j; p=a; for(i=0;i<3;i++) for(j=0;j<4;j++) cout<<*(*(p+i)+j)<<' '; cout<<endl; }
二维数组的指针表示 int b[2][5]; b[i][j] *(*(b+i)+j) i=0,1; j=0,1,2,3,4; b+i:行数组;
可以隐含指定数组的大小 #include <iostream.h> void main() { static int b[][3]={{1,2,3},{4},{5,6}}; b[0][2]=7; b[1][2]=8; cout<<**b<<"\t"<<**(b+1)<<"\t"<< *(*(b+1)+2)<<endl; cout<<b[0][2]+b[1][2]<<endl; }