程序设计6(指针)_第1页
程序设计6(指针)_第2页
程序设计6(指针)_第3页
程序设计6(指针)_第4页
程序设计6(指针)_第5页
已阅读5页,还剩37页未读 继续免费阅读

下载本文档

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

文档简介

六、指针与引用6.1指针的基本概念6.2指针与一维数组6.3堆内存分配6.4字符指针6.5指针数组6.6引用的概念和操作(了解)6.7指针与二维数组(自主学习)木纹背景的资料属自主学习的内容6.1指针的基本概念6.1.1变量的地址6.1.2指针变量6.1.3指针运算6.1.1变量的地址1、内存的每个字节都有一个编号。这个编号就是这个字节对应的内存地址。2、程序中的每个数据都对应着内存中的一个地址,从该地址开始的一个或多个字节用来存放该数据。如:inti,j,k;i=3;j=6;3、内存单元的地址和内存单元的内容的区别4、程序编译后,变量名转换为变量的地址,计算机通过内存地址对变量进行存取。5、变量的直接访问和间接访问直接访问:通过变量的地址(变量名)存取变量。间接访问:通过存放变量的地址的变量存取变量。6、”指向”的含义存放变量a的地址(&a)的变量指向变量a。1、变量的指针:即变量的地址。2、指针变量:专门用来存放另一个变量的地址的变量。指针变量的值(即指针变量中存放的值)是指针(地址)。3、声明指针变量: 数据类型*变量;4、指针变量的初始化

inta=100; int*p=&a;5、指针变量的引用(取地址运算符&与指针运算符*)&只能作用于变量:&x,&a[5];//正确不能作用于常量、表达式:&25,&(i+1);//错误int*p;p=3000无意义intx,*p;x=p无意义4、有关说明 指针变量的地址,。。。6.1.2指针变量地址内存数据区…20003整型变量a//inta=320046整型变量b//intb=620089整型变量c//intc=9…

…30002004指针变量p//int*p=&b;…当前pb20046p++后pc20089p=p-2后pa200036.1.3指针运算算术运算:加法运算和减法运算关系运算:比较两个指针变量赋值运算:6.2指针与数组(一维数组)

每个变量都有地址。 一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们也都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组和数组元素(把数组起始地址或某一元素的地址放到一个指针变量中)。 所谓数组的指针是指数组的起始地址,数组元素的指针是数组元素的地址。数组,指针,循环语句三者是天生的好搭档例如:inta[10];

//定义a为包含10个整型数据的数组int*p; //定义p为指向整型变量的指针变量p=&a[0];p++; //指向a[1]6.2.1指向数组元素的指针如果p的初值为&a[0],则:(1)p+i和a+i就是a[i]的地址,或者说,它们指向a数组的第i个元素,见图。这里需要说明的是a代表数组首地址,a+i也是地址,它的计算方法同p+i,即它的实际地址为a+i×sizeof(int)。例如,p+9和a+9的值是&a[9],它指向a[9]。6.2.2通过指针访问数组元素(2)*(p+i)或*(a+i)是p+i或a+i所指向的数组元素(的内容),即a[i]。例如,*(p+5)或*(a+5)就是a[5]。即*(p+5)=*(a+5)=a[5]。实际上,在编译时,对数组元素a[i]就是处理成*(a+i),即按数组首地址加上相对位移量得到要找的元素的地址,然后找出该单元中的内容。 例如,若数组a的首地址为1000,设数组为int型,且sizeof(int)=4,则a[3]的地址是这样计算出来的:

1000+3×4=1012,然后从1012地址所标志的整型单元取出元素的值,即a[3]的值。可以看出,[]实际上是变址运算符,即将a[i]按a+i计算地址,然后找出此地址单元中的值。(3)指向数组的指针变量也可以带下标,如p[i]与(p+i)等价。根据以上叙述,引用一个数组元素,可以用:下标法,如a[i]形式;指针法,如*(a+i)或*(p+i)。其中a是数组名,p是指向数组的指针变量,其初值p=a。例:输出数组元素。下标法。通过数组名计算数组元素地址,找出元素的值。用指针变量指向数组元素。6.2.3举例说明//例1intmain(){chara[13],*p=a;strcpy(a,“helloworld!”);cout<<a<<endl;inti,len=strlen(a);for(i=0;i<len;i++)cout<<a[i];for(i=0;i<len;i++)cout<<*(a+i);for(i=0;i<len;i++)cout<<*(p+i);for(p=a;p<a+len;p++)cout<<*p;return0;}//例2intmain(){inta[10],i,*p=a;for(i=0;i<10;i++)a[i]=i;//初始化for(i=0;i<10;i++)cout<<a[i]; for(i=0;i<10;i++)cout<<*(a+i);for(i=0;i<10;i++)cout<<*(p+i);for(p=a;p<a+10;p++)cout<<*p;return0;}//例3intmain(){char*p,*q;p=“helloworld!”;cout<<p<<endl;

inti,len=strlen(p);for(i=0;i<len;i++)cout<<*(p+i);for(q=p+len-1;q>=p;q--)cout<<*q;//逆向输出return0;}6.3堆内存分配6.3.1堆内存6.3.2堆内存操作函数6.3.3指针变量的空间申请和释放6.3.4指针与函数6.3.1堆内存

堆是程序运行时动态使用的一个内存空间,要在堆中分配空间,必须使用特定的函数,使用完成后必须及时释放空间。6.3.2堆内存操作函数(C语言的选择)void*malloc(unsignedlongsize)voidfree(void*)头文件为:alloc.h上面的堆内存操作函数在C++中不太常用!使用new分配内存空间使用delete释放内存空间例如:intmain(){

int*p=newint[10]; //申请空间

inti,sum=0; for(i=0;i<10;i++) p[i]=i; for(i=0;i<10;i++) sum+=p[i]; cout<<sum<<endl;

delete[]p; //释放空间,注意不要忘了中括号

return0;}6.3.3指针变量的空间申请和释放6.3.4指针与函数指针或变量的地址作为函数参数指针函数(课后了解)函数指针(课后了解)例:使用指针作为参数,设计函数,参数为a,b,c3个整型变量的地址,执行函数后,实现a≤b≤c。intmain(){ inta=3,b=125,c=38; int*pa=&a,*pb=&b,*pc=&c;

fun(pa,pb,pc); //使用指针作为参数

cout<<“a=“<<a<<“,b=“<<b<<“,c=“<<c<<endl; a=3;b=125;c=38;

fun(&a,&b,&c); //使用地址作为参数

cout<<“a=“<<a<<“,b=“<<b<<“,c=“<<c<<endl; return0;}输出结果为:a=3,b=38,c=125a=3,b=38,c=125voidfun(int*pa,int*pb,int*pc){ intx;

if(*pa>*pb){x=*pa;*pa=*pb;*pb=x;} if(*pb>*pc){x=*pc;*pc=*pb;*pb=x;} if(*pa>*pb){x=*pa;*pa=*pb;*pb=x;}}6.4字符指针6.4.1字符指针的使用6.4.2字符指针与字符数组的区别举例:charstr[6]=“China”,c;char*p,*q;p=str;q=&c;strcpy(str,“Hello”);//正确//下列语句有潜在风险strcpy(str,“Helloworld!”);//风险举例inta=100;charstr[6]=“China”;strcpy(str,“Helloworld!”);cout<<a<<endl;

运行结果:5602294906.4.1字符指针的使用另外,常用的可行方法:charstr[6]=“China”;strings1=str;//此时s1和str占据2块不同的内存区域s1=“Helloworld”;//正确strings2=“Helloworld”;//方法c_str()将string强制转换成c格式的字符串char*p=(char*)s2.c_str();cout<<p<<endl;6.4.2字符指针与字符数组的区别概念

数组是一个整体,指针只是地址赋值方式:charstr[20],*p;strcpy(str,“helloworld”):p=“helloworld”;内存分配方式: 数组空间在编译时分配,指针的指向运行时确定能否赋值数组名是常量(即数组首地址),不能对数组名赋值指针可以直接赋值6.5指针数组指针数组的简单介绍6.6引用的概念和操作(不作要求,了解)6.6.1引用的概念6.6.2引用的操作6.6.3引用的说明6.6.1引用的概念在C++中,引用提供了一种把实体的变量作为该实体的别名的机制。通俗地说,引用即给对象起“别名”。引用运算符是“&”。“&”在定义时出现在赋值运算符的左边表示是“引用”,否则是取址符;一个对象一旦有了别名,此别名就不能再作为别的对象的别名,所以声明时必须进行初始化;有了别名的对象,不管对真名、还是对别名进行操作,都是对此对象进行操作;一个被声明成引用的变量,并不另外再占有存储空间。6.6.2引用的操作用引用传递函数的参数利用引用返回多个值

(把需要返回的多个值的引用作为函数的参数)例:设计函数,参数为a,b,c3个整型变量,执行函数后,满足a≤b≤c(用引用传递函数的参数)voidf2(int&a,int&b,int&c){ intx;

if(a>b){x=a;a=b;b=x;} if(b>c){x=c;c=b;b=x;} if(a>b){x=a;a=b;b=x;}}intmain(){ intx1=3,x2=125,x3=38;

int&p1=x1,&p2=x2,&p3=x3; //此处定义了3个引用

f2(p1,p2,p3);//使用引用作为参数

//f2(x1,x2,x3);//使用传统的传地址方式(其本质就是引用) cout<<“x1=“<<x1<<“,x2=“<<x2<<“,x3=“<<x3<<endl; return0;}输出结果为:x1=3,x2=38,x3=125例:利用引用返回多个值由于引用能够改变参数的值,因此利用这个特点就可以实现返回多个值。voidfun(intn,int&a,int&b){ a=n*n; b=n*n*n; }intmain(){ intx,y,z; cin>>x; fun(x,y,z); cout<<x<<","<<y<<","<<z<<endl; return0;}6.6.3引用的说明引用在声明的时候必须同时要初始化,否则会出现错误。引用是从一而终的,在初始化后不会再指向其他的变量。任何对该引用的赋值都是对引用所维系的目标赋值,而不是将引用维系到另一个目标上。由于引用本身不是类型,所以没有引用的指针和引用的引用。但可以有指针的引用。用引用传递函数参数与指针的效果一样,传递的是原来的变量或对象,而不是在函数作用域内建立副本。可以利用引用返回多个值 shortinta[3][4]={ {1,3,5,7},

{9,11,13,15},

{17,19,21,23}}; a是一个数组名。a数组包含3行,即3个元素:a[0],a[1],a[2]。而每一元素又是一个一维数组,它包含4个元素(即4个列元素),例如,a[0]所代表的一维数组又包含4个元素:a[0][0],a[0][1],a[0][2],a[0][3],见下图。6.7指针与二维数组(自主学习)本节内容相对较难理解,建议通过实践来帮助理解

从二维数组的角度来看,a代表整个二维数组的首地址,也就是第0行的首地址。a+1代表第1行的首地址。如果二维数组的首地址为2000,则a+1为2008,因为第0行有4个short型数据,因此a+1的含义是a[1]的地址,即a+4×2=2008。a+2代表第2行的首地址,它的值是2016,见下图。

a[0]、a[1]、a[2]既然是一维数组名,而C/C++语言又规定了数组名代表数组的首地址,因此a[0]代表第0行一维数组中第0列元素的地址,即&a[0][0]。a[1]的值是&a[1][0],a[2]的值是&a[2][0]。

第0行第1列元素的地址怎么表示? 可以用a[0]+1来表示。

此时“a[0]+1”中的1代表1个列元素的字节数,即2个字节。今a[0]的值是2000,a[0]+1的值是2002(而不是2008)。这是因为现在是在一维数组范围内讨论问题的,正如有一个一维数组x,x+1是其第1列元素地址一样。a[0]+0、a[0]+1、a[0]+2、a[0]+3分别是a[0][0]、a[0][1]、a[0][2]、a[0][3]的地址。

前已述及,a[0]和*(a+0)等价,a[1]和*(a+1)等价,a[i]和*(a+i)等价。因此,a[0]+1和*(a+0)+1的值都是&a[0][1](即右图中的2002)。a[1]+2和*(a+1)+2的值都是&a[1][2](即右图中的2012)。请注意不要将*(a+1)+2错写成*(a+1+2),后者变成*(a+3)了,相当于a[3]。

进一步分析,欲得到a[0][1]的值,用地址法怎么表示呢?既然a[0]+1和*(a+0)+1是a[0][1]的地址,那么,*(a[0]+1)就是a[0][1]的值。同理,*(*(a+0)+1)或*(*a+1)也是a[0][1]的值。*(a[i]+j)或*(*(a+i)+j)是a[i][j]的值。务请记住*(a+i)和a[i]是等价的。 有必要对a[i]的性质作进一步说明。a[i]从形式上看是a数组中第i个元素。如果a是一维数组名,则a[i]代表a数组第i个元素所占的内存单元。a[i]是有物理地址的,是占内存单元的。但如果a是二维数组,则a[i]是代表一维数组名。a[i]本身并不占内存单元,它也不存放a数组中各个元素的值。它只是一个地址(如同一个一维数组名x并不占内存单元而只代表地址一样)。a、a+i、a[i]、*(a+i)、*(a+i)+j、a[i]+j都是地址。*(a[i]+j)、*(*(a+i)+j)是二维数组元素a[i][j]的值。

为什么a+1和*(a+1)都是2008呢?a+1的值和a+1的地址怎么都是一样的呢? 的确,二维数组中有些概念比较复杂难懂,要反复思考。首先说明,a+1是地址(指向第1行首地址),而*(a+1)并不是“a+1单元的内容(值)”,因为a+1并不是一个实际变量,也就谈不上它的内容。*(a+1)就是a[1],而a[1]是一维数组名,所以也是地址。以上各种形式都是地址计算的不同表示。 为了说明这个容易搞混的问题,举例子来说明。 有一个排,下设3个班,每班有10名战士。规定排长只管理到班,班长管理战士。在排长眼里只有第0、1、2班(为与C/C++语言中数组下标一致,假定班号也从0开始)。排长从第0班的起始位置走到第1班的起始位置,看来只走了一步,但实际上它跳过了10个战士。这相当于a+1(见后图)。为了找到某一班内某一个战士,必须给两个参数,即第i班第j个战士,先找到第i班,然后由该班班长在本班范围内找第j个战士。这个战士的位置就是a[i]+j(这是一个地址)。开始时班长面对第0个战士。注意,排长和班长的初始位置是相同的(如图中的a和a[0]都是2000)。但它们的“指向”是不同的。

排长“指向”班,他走一步就跳过1个班,而班长“指向”战士,走一步只是指向下一个战士。可以看到排长是“宏观管理”,只管班,在图中是控制纵向,班长则是“微观管理”,管理到战士,在图上是控制横向。如果要找第1班第2个战士,则先由排长找到第1班的班长,然后,由班长在本班范围内找到第2个战士。二维数组a相当于排长,每一行(即一维数组a[0]、a[1]、a[2])相当于班长,每一行中的元素(如a[1][2])相当于战士。a+1与a[0]+1是不同的,a+1是第1行的首地址,a+1指向第1行(相当于排长走到第1班的开头),而*(a+1)或a[1]或a[1]+0都指向第1行第0列元素(相当于第1班第0个战士),二者地址虽相同,但含义不同了

温馨提示

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

评论

0/150

提交评论