C指针和引用实用_第1页
C指针和引用实用_第2页
C指针和引用实用_第3页
C指针和引用实用_第4页
C指针和引用实用_第5页
已阅读5页,还剩76页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

会计学1C指针和引用实用概述

指针是C++语言的重要概念,利用指针可以高效而简洁的处理数据,有些操作不借用指针是无法完成的(如直接访问内存地址、动态分配内存)。因此指针成为灵活编程的重要工具。但万事有利就有弊,在程序中不加节制的滥用指针将造成程序的数据流混乱,可读性下降等问题。所以在使用指针时要多一分小心。第1页/共81页预备知识

内存就是内部存储器,由存储单元组成。它的特点是存储单元是线性连续的。存储单元的最小单位是字节。···············

正如我们的住房都有门牌号码一样,为了访问内存中的某个存储单元,我们也要为它编号,这种编号称为内存地址。通过地址我们就能够访问该地址所标示的存储单元。········0123203地址内容45第2页/共81页

在程序中定义了一个变量,这个变量在内存中就要占用一定大小的空间,通常这个空间的大小就由这个变量的类型决定。变量在内存中总是占用几个连续的字节,开始字节的地址就是变量的地址。inti;

charch;

floatf1;

i=10;

ch=‘A’;

f1=3.14;3.14‘A’10地址变量2000200420052008ichf14字节1字节4字节第3页/共81页什么是指针

指针就是变量的地址。与此对应,在C++语言中使用一种专门的变量---指针变量来存放另一变量的地址。也就是说,指针变量是存放地址数据的变量,它的值应该是某个变量的地址。指针变量变量地址(指针)变量变量的值指向地址存入指针变量第4页/共81页

一般来说,指针变量只能存放某一种数据类型的变量地址,由此可以将指针变量划分为整型指针变量、实型指针变量、字符型指针变量等等。

整型指针变量只能存放整型变量的地址。

实型指针变量只能存放实型变量的地址。

字符型指针变量只能存放字符型变量的地址。

当把变量的地址存入指针变量后,我们就可以说这个指针指向了该变量。指针变量pi2000变量i变量i的值指向地址2000第5页/共81页指针的定义

指针定义的结构形式如下:

数据类型名*指针变量名如:int*ptr1,*ptr2;float*ptr3;char*ptr4;在定义指针时要注意以下几个问题:

1。指针变量名前面的星号“*”不能省略,如果写成

int*ptr1,ptr2;则ptr2被定义为整型变量而非指针变量。2。定义中的星号“*”表示所定义的变量是指针变量,但指针变量名是ptr1、ptr2,而非*ptr1、*ptr2。第6页/共81页3。指针变量只能指向定义时所规定类型的变量。如ptr1只能指向整型变量,ptr4只能指向字符型变量。4。定义指针变量后,并未确定该变量指向何处。也就是说变量的值是不确定的。在引用指针变量前,必须首先让它确定一个变量,这一点非常重要。第7页/共81页指针的赋值

指针的赋值运算就是把地址值赋值给指针变量。指针的赋值运算可以是以下几种方式:

1。使用取地址运算符&。如:

inti,a[5],*ptr;

ptr=&i;ptr=&a[1];2。把指针变量的值赋值给另一个指针变量。如:

inti,*ptr1=&i,*ptr2;ptr2=ptr1;可不可以把a赋值给ptr,即ptr=a;?可以!a即为数组的首地址。ptr=a;等价于ptr=&a[0];第8页/共81页3。给指针变量赋值为赋号常量NULL,如:

int*ptr;ptr=NULL;

实际上NULL是一个空指针,这样的指针不指向任何变量。为了避免指针变量的非法引用,我们一般要给没有被初始化的指针变量赋值为NULL作为标志。4。把指针变量赋值为0。如:int*ptr=0;

这里的0等价于NULL,值0是唯一能够直接赋值给指针变量的整数值。第9页/共81页&(取地址运算)和*(引用运算)

地址运算符&的作用是取变量的地址,如:&i表示求变量i的地址。

引用运算符*的作用是取指针所指向变量的内容,例如:*ptr表示求指针ptr所指向变量的内容。&运算和*运算是一对互逆运算。20003指针ptr2000iptr指向了i变量*ptr表示取所指向变量i的值,即3inti=3,*ptr;

ptr=&i;*ptr=15;?20002000i指针ptr*ptr=15等价于i=15,因此改变了变量i的值。15第10页/共81页例:

voidmain()

{charch=‘A’,*ch_ptr;

ch_ptr=&ch;

cout<<“ch=”<<ch<<endl;

cout<<“*ch_ptr=”<<*ch_ptr<<endl;

*ch_ptr=‘X’;

cout<<“ch=”<<ch<<endl;

cout<<“*ch_ptr=”<<*ch_ptr<<endl;

cout<<“ch的地址是”<<ch_ptr;输出结果ch=A*ch_ptr=Ach=X*ch_ptr=Xch的地址是0xFFF5第11页/共81页指针的+、-运算

指针可以加上或减去一个整数,指针的这种运算的意义和通常的数值的加减运算的意义不同。

指针的加减运算分为两种:一种是指针与整型值的加减运算,一种是指针与指针的减运算。structstudent{intnumber;charname[4];}student*pst;pst=pst+1;pst第12页/共81页指针运算是地址的运算(T*px)

一:px+n,px-n——将指针从当前位置向前或向后移动n个数据单位,而不是n个字节。这取决于指针所指向的数据类型(T)。

pxn的结果为:pxnsizeof(T)

二:指针与指针的加运算毫无意义。

三:指针与指针的减运算不同于简单的数值之间相减,它用来计算两指针位置之间的数据个数,而不是地址差。px-py的结果为:(px-py)/sizeof(T)

注意:px和py必须具有相同指针类型!

四:y=px++——y=(px++),注意优先级和结合顺序(*和++优先级相同且为左结合)

y=++px——y=(++px)

问题:y=px++和y=(px)++的意义

第13页/共81页int*ptr1,*ptr2;

inta[5]={2,4,6,8,10};

intx;

ptr1=&a[0];

ptr2=ptr1+3;

x=ptr2-ptr1;地址ptr1ptr2a数组108642200020042008200C20102000200C第14页/共81页指针的关系运算一:是对两个相同类型的指针的运算,如px<py,当px所指位置在py之前时,表达式的值为1,否则为0。二:px==py判断两个指针是否指向同一个存储单元三:px==0,px!=0用来判断px是否为空指针四:不同类型的指针以及指针和一般整数间的关系运算是无意义的第15页/共81页指针的类型转换

如果两个指针类型相同,那么可以把一个指针赋给另一个指针,否则必须用强制类型转换运算把赋值运算符右边指针的类型转换为赋值运算符左边指针的类型。已知:floata=5.6;

int*ptr_a;

求:如何让整型指针ptr_a指向浮点型变量a,如何通过指针ptr_a输出变量a的值?voidmain()

{floata=5.6;

int*ptr_a;

ptr_a=(int*)&a;

cout<<*(float*)ptr_a;

}第16页/共81页main()

{inti=3;

char*p1,temp;

p1=(char*)&i;

temp=*p1;

*p1=*(p1+1);

*(p1+1)=temp;

cout<<*(int*)p1;

}例:如何交换一个整型变量在内存单元里的高低字节的内容。0000001100000000高字节低字节0000000000000011高字节低字节输出结果:768第17页/共81页结构体类型的指针

也可以创建结构体类型的指针变量,其一般格式与创建基本类型的指针变量类似:

《存储类型》<结构名>*<指针变量>;

结构体类型的指针变量访问结构体中的成员的方法与一般的结构体变量不同,其一般格式如下:

<指针变量>-><成员>;第18页/共81页structperson{ charname[10];

unsignedage;

unsignedlongid;

floatsalary;

};

voidmain()

{ personper1,*per2=&per1;

strcpy(per2->name,"Mary");

per2->age=18;per2->id=20021001;

per2->salary=2250.0;

cout<<per2->name<<'\t'<<per2->age<<'\t‘

<<per2->id<<'\t‘<<per2->salary<<'\n';

}per1.id=20021001//(*per2).salary=2250.0第19页/共81页指针与数组的关系

声明了一个数组TYPEarray[n],则数组名称array就有了两重含义:第一,它代表整个数组,它的类型是TYPE[n];第二,它是一个指针,该指针的类型是TYPE*,该指针指向的类型是TYPE,也就是数组单元的类型,该指针指向的内存区就是数组第0号单元,该指针自己占有单独的内存区,注意它和数组第0号单元占据的内存区是不同的。该指针的值是不能修改的,即类似array++的表达式是错误的。

因此数组与指针有着密切关系,他们几乎可以互换,数组名就是一个常量指针。所以引用指针的概念,要表示数组元素除了可以用下标表示外,还可以用指针位移表示。第20页/共81页如:intarray[5]={1,2,3,4,5},*ptr;

ptr=array;

要求:输出数组array的各个元素值。下标法:

一:for(i=0;i<5;i++)

cout<<array[i];

二:for(i=0;i<5;i++)

cout<<ptr[i];位移法:

一:for(i=0;i<5;i++)

cout<<*(ptr+i);

二:for(i=0;i<5;i++)

cout<<*(array+i);

以上是一维数组元素的指针表示法,那么二维数组元素用指针如何表示呢?是否和一维数组一样?第21页/共81页如:inta[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

如何用指针表示a[0][1]?

最简单的方法:int*p=&a[0][0];则*(p+1)即表示a[0][1],很显然数组名a是一指针,那是不是*(a+1)就表示a[0][1]呢?

我们知道二维数组可以看成特殊的一维数组,这个特殊的一维数组的元素又是一个一维数组。即a[3][4]可看成数组长度为3的一维数组,而此一维数组的每个元素又是一个数组长度为4的一维数组。如下图所示:aa[0]a[1]a[2]a[0][0],a[0][1],a[0][2],a[0][3]第22页/共81页aa[0]a[1]a[2]a[0][0],a[0][1],a[0][2],a[0][3]

因此,数组名a代表这个特殊的一维数组的首地址,它指向第一个元素a[0],则a+1就指向a[1],即二维数组的第二行元素,这行元素占4个存储单元。我们称a为行指针,同理a+1、a+2也是行指针。显然*(a+1)不表示a[0][1]。

那么如何让指针真正指到每行上的列元素呢?即我们真正关心的二维数组的每一个元素。第23页/共81页aa[0]a[1]a[2]a[0][0],a[0][1],a[0][2],a[0][3]

注意:a[0]对二维数组a来说是元素名,但对一维数组{a[0][0],a[0][1],a[0][2],a[0][3]}来说却是数组名,此为它的双重身份。很显然a[0]就指向a[0][0],因此a[0]+1才指向a[0][1],我们称a[0]为列指针,同理a[1]、a[2]也是列指针。因此*(a[0]+1)就表示a[0][1]。

而a[0]用指针a可表示为*(a+0)即*a,a[1]表示为*(a+1)。第24页/共81页aa[0]a[1]a[2]a[0][0],a[0][1],a[0][2],a[0][3]问题一般化:&a[i][j]=a[i]+j=*(a+i)+j

相对应的元素是:a[i][j]=*(a[i]+j)=*(*(a+i)+j)

这就是二维数组元素的指针表示法。参考教材P149可以认为:在行指针前加*,可将行指针转换成列指针。第25页/共81页下面我们讨论行指针、列指针的定义方法。

已知:inta[3][4];

怎样定义列指针?输出a[i][j]?

很简单,只要注意把a的列指针表示方法赋给新的指针即可。如:int*p;

p=&a[0][0];或p=a[0];或p=*a;

cout<<*(p+4*i+j);

如何定义行指针呢?

问题稍微复杂,新的指针必须指向行,它由4个列元素组成,也就说这个指针应指向一个一维数组,如下定义:int(*p)[4];//见教材P155

p=a;或p=&a[0];

cout<<*(*(p+i)+j);

可以认为:在列指针前加&,可将列指针转换成行指针。第26页/共81页指针与字符串的关系

字符串在内存以字符数组存放,自然与指针相关联。定义一:chars[]=“ABC”;定义二:char*s=“ABC”;

s称之为字符指针变量,它指向字符串“ABC”,即s代表字符串“ABC”的首地址,亦即字符‘A’所在内存单元的地址。第27页/共81页

我们知道,字符串是不能直接赋值给字符数组的,要使用函数strcpy,但字符串可直接赋值给字符指针。

因此:char*s=“ABC”

;可等价为:

char*s;s=“ABC”

注意:s为指针,它的值只能为地址,语句s=“ABC”是表示把字符串“ABC”所在内存单元的地址赋给S,因此不可认为s的值为字符串“ABC”。

用指针表示的字符串输出同样可使用

cout<<指针变量名;

上例即cout<<s;第28页/共81页

例用指针实现字符串的拷贝(教材P150)voidmain(void){chars1[]="Iamastudent!"; //定义数组并初始化

char*s2="Youareastudent!";//定义指针并初始化

chars3[30],s4[30],s5[30];inti;char*p1=s3,*p2=s1; //定义指针并初始化

for(;*p1++=*p2++;); //s1拷贝给s3for(i=0;i<=strlen(s1);i++) s4[i]=s1[i]; //s1拷贝给s4strcpy(s5,s2); //s2拷贝给s5}第29页/共81页指针数组

我们先看一个指针定义

char*s[4];

由于[]

比*的优先级高(请参考P18),因此以上定义首先定义了一个数组长度为4的一维数组,而数组元素为字符指针。我们称之为指针数组。

(注意区分char(*s)[4]与指针数组对照,我们称它为数组指针)第30页/共81页

我们可以初始化这个字符指针数组,如:

char*s[4]={“open”,”new”,”save”,”saveas”};newsavesaveasopenS[0]S[1]S[2]S[3]

该指针数组元素指向不同的字符串,注意不要误认为字符串存放在该指针数组。顾名思义,指针数组只存放指针,因此该指针数组存储的实际上是各字符串的首地址。第31页/共81页

大家还注意到各字符串的长度可以不一样,这是字符指针数组的一大特点,和二维数组相比(思考如何用二维数组存放这几个字符串?),它大大节省了内存存储空间。(为什么?)

二维数组表示如下:

chars[4][8]={“open”,”new”,”save”,”saveas”};S[0]S[1]S[2]S[3]\0saevas\0\0\0\0evas\0\0\0\0\0wen\0\0\0\0nepo第32页/共81页例将若干个字符串按升序排序后输出(教材P152)voidmain(void){char*str[]={…}; //定义数组并初始化

char*p1; //定义指针

inti,j,k;//按升序排序(改进后的选择排序)for(i=0;i<=4;i++){ k=i; for(j=i+1;j<5;j++) if(strcmp(str[k],str[j])>0)k=j; //k记为当前最小字符串的位置

if(k!=i) {p1=str[k];str[k]=str[i];str[i]=p1;}//交换指针的指向,str[i]和str[k]均为指针

}}第33页/共81页指针与函数

指针可以用作函数参数,这在想通过调用函数来改变参数的值很重要。voidswap(int,int);

voidmain()

{intx1=100,x2=200;

cout<<“交换前x1=“<<x1<<“,x2=”<<x2<<endl;

swap(x1,x2);

cout<<“交换后x1=“<<x1<<“,x2=”<<x2;

}

voidswap(inta,intb)

{inttemp;

temp=a;a=b;b=temp;}100200x1x2x1=100,x2=200进入swap函数

x1,x2分别将值赋给a,btempab100200100200100temp=a;a=b;b=temp;a,b的交换不影响x1,x2退出swap,x1、x2未交换第34页/共81页voidswap(int*,int*);

voidmain()

{intx1=100,x2=200;

cout<<“交换前x1=“<<x1<<“,x2=”<<x2<<endl;

swap(&x1,&x2);

cout<<“交换后x1=“<<x1<<“,x2=”<<x2;

}

voidswap(int*p1,int*p2)

{inttemp;

temp=*p1;

*p1=*p2;

*p2=temp;

}100200x1x2x1=100,x2=200进入swap函数,分别将x1、x2的地址赋给p1,p2p1p2temp&x1&x2100200100temp=*p1;*p1=*p2;*p2=temp;swap函数执行过程中p1,p2的值没有变化,退出swap函数后,x1,x2的值交换。第35页/共81页

实际上,传址方式是一种特殊的传值方式。将指针变量的值传递给形参(当然形参也应该是指针变量),由于指针变量的值就是地址,所以这种传值方式就成为了传址方式。特别要注意,传值方式中形参的改变不会影响到实参的改变,这一点传址方式也不例外!上例中之所以能交换实参所指向的两个数,是因为在函数中交换的是形参所指向的变量的值,由于形参和实参指向同一个变量,因此实参指向变量最终交换,但实参的值却没有变化。第36页/共81页voidswap(int*,int*);

voidmain()

{intx1=100,x2=200,*pt1=&x1,*pt2=&x2;

cout<<“交换前x1=“<<x1<<“,x2=”<<x2<<endl;

swap(pt1,pt2);

cout<<“交换后x1=“<<x1<<“,x2=”<<x2;

}

voidswap(int*p1,int*p2)

{int*temp;

temp=p1;

p1=p2;

p2=temp;

}第37页/共81页intmax,min;

voidmax_min_value(int*p,intn)

{inti;

max=min=*p;

for(i=1,p++;i<n;i++,p++)

if(*p>max)max=*p;

elseif(*p<min)min=*p;

}

voidmain()

{intnumber[10],i;

for(i=0;i<10;i++)

cin>>number+i;

max_min_value(number,10);

cout<<“max=“<<max<<“min=”<<min;}例:从10个数中找出其中的最大值和最小值。第38页/共81页例:有一个班,3个学生各4门成绩,要求查找有成绩不及格的学生,并输出该学生的全部成绩。voidsearch(float*p,intm,intn)

{inti,j,flag;

for(i=0;i<m;i++)

{flag=0;

for(j=0;j<n;j++)

if(*(p+i*n+j)<60){flag=1;break;}

if(flag==1){printf(“\nNO.%dfails,hisscore:\n”,i);

for(j=0;j<n;j++)

printf(“%8.1f”,*(p+i*n+j));

}

}

}

main()

{floatscore[3][4]={......};

.......search(score[0],3,4);......}voidsearch(float(*p)[4],intm)

{inti,j,flag;

for(i=0;i<m;i++)

{flag=0;

for(j=0;j<4;j++)

if(*(*(p+i)+j)<60){flag=1;break;}

if(flag==1)

{cout<<“\nNO.”<<i<<“fails,hisscore:\n”;

for(j=0;j<4;j++)

cout<<*(*(p+i)+j);

}

}

}

main()

{floatscore[3][4]={......};

.......search(score,3);......}第39页/共81页例:制作一个简单的菜单。voidmenu(char*p[],intm)

{inti;

system(“cls”);

for(i=0;i<m;i++)

{cout<<p[i];

}

cout<<“\nEnterachoice:”;

}

main()

{char*p[4]={“Open”,”New”,”Save”,”Saveas”};

menu(p,4);

}第40页/共81页返回指针的函数voidstrcpy(char

s1[],chars2[])

{inti=0;

while(s2[i]!=‘\0’)

{s1[i]=s2[i];

i++;

}

s1[i]=‘\0’;

}char*strcpy(char

*s1,char*s2)

{inti=0;while(*(s2+i)!=‘\0’)

{*(s1+i)=*(s2+i);

i++;

}

s1[i]=‘\0’;

returns1;

}第41页/共81页注意:返回指针的函数,其函数体中的return语

句的参数必须为全局变量的指针、静态变量指针

或形参的指针(如果形参为指针类型或引用类型

的话),不能为局部变量指针。返回的是变量地址,必须保证函数返回后,这个变量仍然存在。要返回函数中局部变量的地址,应声明为静态的。char*string_name(intn){staticchar*string[]={“illegalstring”,“string1”,“string2”,“string3”}return(n<1||n>3)?string[0]:string[n];}第42页/共81页例将输入的一个字符串按逆序输出(教材P164)char*flip(char*ptr) //指针函数{char*p1,*p2,temp; p1=p2=ptr; //初始化指针变量,p1、p2指向字符串的起始

while(*p2++);//p2指向字符串结束符的后一个位置

p2=p2-2; //p2回退两个位置,指向字符串的最后一个字符

while(p1<p2){ //指针的比较和内容的交换

temp=*p2; *p2--=*p1; //从字符串的两边向中间进行交换 *p1++=temp; }returnptr; //返回指针}第43页/共81页例设计字符拷贝和拼接的函数(教材P165)char*copy(char*to,char*from) //字符拷贝指针函数{

char*p=to;

while(*to++=*from++)

; //内容拷贝

returnp; //返回指针}char*stringcat(char*to,char*from)//字符拼接指针函数{

char*p=to;

while(*to++)

;

//指针指向结束字符后一个字符

to--; //指针减1,指向结束字符

while(*to++=*from++)

; //内容拼接

returnp; //返回指针}第44页/共81页指向函数的指针

函数名实际上是完成函数任务的代码所在内存中的起始地址(函数入口地址),亦即函数名象数组名一样,本身就是一个指针,因此函数名也可作为函数的参数。

函数名作为实参很简单,直接使用函数名即可,但由于函数名本身就是一个指针,所以它作为形参时必须使用指针定义。

如:intmax(int,int);

则指向函数max的指针可定义为:

int(*max_ptr)(int,int);

注意与int*max_ptr(int,int)

区分,它是一个返回指针的函数。第45页/共81页

函数指针常用在所谓较简单的菜单驱动系统中,每一个菜单选项对应一个功能即一个函数,由于菜单不只一项,所以要用到指向函数的指针数组。如:

int(*function[3])(int,int);

使用指向函数的指针数组的一个限制是所有的指针都必须是同一个类型,指针指向的函数必须具有相同类型的返回值,并且它们的参数类型也相同。

对于上例如果有:intmax(int,int);

intmin(int,int);

intaverage(int,int);

则上例的指针数组可初始化为:

int(*function[3])(int,int)={max,min,average};

第46页/共81页二级指针voidmain()

{char*p1=“Nanjing”;

char**p2;

p2=&p1;

cout<<*p2<<endl;

}voidmain()

{inta[4]={1,2,3,4};

int(*p)[4],i;

p=&a;

for(i=0;i<4;i++)

cout<<(*p)[i]<<endl;

}第47页/共81页总结:如何判断指针类型?

要弄懂指针就要弄懂3个问题:指针的类型、指针所指向的类型、指针的值。int*p;int*int

float*p;float*float

int**p;int**int*

int(*p)[3]int(*)[3]int()[3]int[3]

int*p[3]指针数组

int(*p)()int(*)()int()

int*p()返回指针的函数第48页/共81页动态分配内存空间new运算符可以为所创建的指针变量动态地分配存储空间,而运算符delete则用于释放动态分配的存储空间。第49页/共81页

使用new运算符的一般格式为:

<指针变量>=new<类型>《(初始值)》;

<指针变量>=new<类型>[<表达式>];

第一种形式为<指针变量>所指向的数据分配大小为sizeof(<类型>)个字节的连续存储空间,初始值表示为所分配的存储空间指定初始值。第二种形式为<指针变量>所指向的数据分配指定大小的数组空间,<表达式>为整型变量或常量。第50页/共81页

对于上述两种情形,如果动态分配不成功,则new运算符返回NULL(0);如果成功分配,则new运算符返回所分配的存储空间的首地址,并将该地址赋给<指针变量>。使用delete的一般格式为:

delete <指针变量>;

delete[《<表达式>》]<指针变量>;

第一种格式为将动态分配给<指针变量>的内存空间归还给系统,第二种格式为将动态分配给<指针变量>的数组空间归还给系统。第51页/共81页#include<iostream.h>voidmain(){int*p1,*p2;float*p3;

p1=newint;*p1=2;cout<<*p1<<'\n';

p2=newint(4);*p2=6;cout<<*p2<<'\n';

p3=newfloat(5.2);cout<<*p3<<'\n';

deletep1;

deletep2;

deletep3;p1=newint(6);cout<<*p1<<'\n';deletep1;}一般动态分配第52页/共81页#include<iostream.h>#include<string.h>voidmain(){int*p4,n;char*p5;n=4;p4=newint[n];

//动态分配一维数组

for(inti=0;i<n;i++)p4[i]=2*i;for(i=0;i<n;i++)cout<<p4[i]<<'\t';

p5=newchar[10];strcpy(p5,"abcdefg"); cout<<p5<<'\n';delete[]p4;delete[]p5;}一维数组动态分配第53页/共81页#include<iostream.h>#include<string.h>voidmain(){int(*p6)[4];

p6=newint[2][4];for(inti=0;i<2;i++){for(intj=0;j<4;j++){p6[i][j]=i+j;cout<<p6[i][j]<<'\t';}cout<<'\n';}

delete[2]p6;}二维数组动态分配第54页/共81页

注意,在用new运算符为某个指针变量所指向的数据动态分配存储空间之后,必须用delete运算符撤消,否则该存储空间将一直被占用,直到关闭电脑。

用new和delete还可以为结构类型或其它用户自定义类型的指针动态分配内存空间。第55页/共81页structnode

{ intx;

floaty;

charz[10];

};voidmain()

{ node*pn;

pn=newnode;

pn->x=2;

pn->y=4.3;

strcpy(pn->z,"China!");

cout<<pn->x<<'\t'<<pn->y<<'\t'<<pn->z<<'\n';

deletepn;

}第56页/共81页

在使用new和delete运算符时,要注意如下几点:

(1)如果new运算符动态分配内存失败(内存中没有符合要求的空闲的连续内存单元),则返回NULL(0),此时指针为空指针。此时,要进行空指针判断处理。float*fp;

fp=newfloat[5000];

if(fp==0)

{cout<<“动态分配内存失败,程序终止运行!\n”;

exit(3);

}第57页/共81页(2)动态分配存放数组的内存空间时,不能在分配空间的同时进行初始化。如:int*pi=newint[8]{1,2,3,4,5,6,7,8};r第58页/共81页(3)可以用new运算符动态分配多维数组空间,但要注意的是,它返回的是行指针。当撤消动态分配二维数组空间时,一定要指明数组的行数,否则只能撤消第0行的内存空间。float*pf1;

pf1=newfloat[3][5];

//错误!类型不匹配。

float(*pf)[5];

pf=newfloat[3][5];

delete[3]pf;

//注意pf前的行数不可省略!第59页/共81页(4)动态分配的二维数组的列向量要与指向数组的指针变量中的数组大小一致,而行向量可为任意的正整数。如:float(*pf)[5];pf=newfloat[3][6];

//错误!类型不匹配。第60页/共81页引用

引用是另一个变量别名,或另一个变量的同义词,引用变量依附于另一个变量而定义。定义引用类型变量的一般格式为:

<类型>&<变量名1>=<变量名2>;

其中<变量名1>为引用类型的变量,而<变量名2>必须是已经定义过的且与引变量同类型的变量。

intI=0;int&j=I;第61页/共81页

在定义一个引用变量时,编译系统并不会为其单独分配存储空间,因此必须对它进行初始化,将它与某个已定义的同类型的变量相关联。在定义一个引用变量之后,它与所引用的变量共享同一个内存空间,并随着所引用的变量的撤销而撤销,因此对引用的任何操作都是对它所关联的变量的操作。第62页/共81页voidmain()

{ intk,&ref=k;

k=100;

cout<<"&k:"<<&k<<"\t&ref:"<<&ref<<'\n';

cout<<"k="<<k<<"\tref="<<ref<<'\n';

ref+=200;

cout<<"k="<<k<<"\tref="<<ref<<'\n';

intl=500;

ref=l;

cout<<"k="<<k<<"\tref="<<ref<<"\tl="<<l<<'\n';

cout<<"&k:"<<&k<<"\t&ref:"<<&ref<<"\t&l:"<<&l<<'\n';

}0x20000x20001001003003005005005000x20000x20000x1FF8第63页/共81页voidfun()

{ inti=10;

staticint&j=i;

j++;

cout<<j<<'\n';

}voidmain()

{fun();

fun();

}1111第64页/共81页

对于引用类型的变量时,要注意如下几个问题:

1.在定义引用类型的变量时,必须用同类型的已定义的变量对它初始化,不同类型的变量以及常量不可对它初始化!如:int&ref1;//错误,未初始化intI;float&ref2=I;//错误,类型不一致int&ref3=4;//错误,不可用常量初始化第65页/共81页2.可以将引用与指针变量所指向的数据相关联,也可以将引用与数组中的元素相关联。如:

Int*pi=newint(3);

int&ref1=*pi;

inta[10];

int&ref2=a[3];

3.可以定义指针类型的引用。

int*pi=newint;

int*&ref1=pi;

inta[10];

int*&ref2=a;第66页/共81页4.可以定义对引用类型变量的引用,但不能定义引用的引用,也不能定义引用指针和引用数组。如:

intI,&ref1=i;

int&ref2=ref1;

int&&ref3=i;

//错误,不能定义引用的引用

inta[8];

int&*ref4=a;

//错误,不能定义引用指针

int&ref5[8]=a;

//错误,不能定义引用数组第67页/共81页引用和函数

参数的三种传递方式:值传递、地址传递、引用传递。

当函数的形参为引用类型时,调用该函数的方式称为引用传递。第68页/共81页

引用传递具有某些与地址传递相似的特征,即引用类型的参数既可以作为输入参数,也可以作为输出参数。对引用类型的参数的操作实际上就是对传递给它的实参的操作,而不需要将实参拷贝一个副本给形参,这是与其它两种传递

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论