《间接访问指针》课件_第1页
《间接访问指针》课件_第2页
《间接访问指针》课件_第3页
《间接访问指针》课件_第4页
《间接访问指针》课件_第5页
已阅读5页,还剩213页未读 继续免费阅读

下载本文档

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

文档简介

第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针第7章间接访问—指针指针的概念指针介绍

本章将介绍C++语言的一个重要的特性:指针,为了成为一个优秀的C++语言程序员,你必须掌握指针并熟练地使用它们。指针是内存的地址并可作为数据是一个灵活和危险的机制允许共享处理数据允许内存动态分配(只要需要,而非预先定义)指针介绍本章将介绍C++语言的一个重要的特性:指针,为指针的概念指针就是把地址作为数据处理指针变量:存储地址的变量变量的指针:当一个变量存储另一个变量的地址时,那我们说它就是那个变量的指针使用指针的目的:提供间接访问指针的概念指针就是把地址作为数据处理指针的概念续如在某一程序中定义了

intx=2;如系统给x分配的空间是1000号单元,则指向x的指针是另一个变量p,p中存放的数据为10001000号单元的内容有两种访问方式:访问变量x(直接访问)访问变量p指向的单元的内容(间接访问)100021000xp指针的概念续如在某一程序中定义了10002100定义指针变量定义指针变量要告诉编译器该变量中存放的是一个地址。指针变量的主要用途是提供间接访问,因此也需要知道指针指向的单元的数据类型指针变量的定义类型标识符*指针变量;如:int*intp;double*doublep;int*p,x,*q;定义指针变量定义指针变量要告诉编译器该变量中存放的是一个地址指针变量的操作如何让指针指向某一变量?因为我们不知道系统分配给变量的真正地址是什么。用地址运算符“&”

解决。如表达式“&x”

返回的是变量x

的地址。如:intp=&x;&运算符后面不能跟常量或表达式。如&2

是没有意义的,&(m*n+p)。也是没有意义的如何通过指针变量处理和改变它所指向的单元的值?用引用运算符“*”解决。如*intp

表示的是intp

指向的这个单元的内容。如:*intp=5等价于x=5在对intp

使用引用运算之前,必须先对intp

赋值指针变量的操作如何让指针指向某一变量?因为我们不知道系统分配指针实例如有:intX,*intp,Y;X=3;Y=4;intp=&X;1000intp10044Y10003X如执行:*intp=Y+4;1000intp10044Y10008X注意:不能用intp=100;因为我们永远不知道变量存储的 真实地址,而且程序每次运行变量地址可能都不同。指针实例如有:1000intp10044Y10003X如执行指针使用指针变量可以指向不同的变量。如上例中intp指向x,我们可以通过对intp的重新赋值改变指针的指向。如果想让intp指向y,只要执行intp=&y就可以了。这时,intp与x无任何关系。同类的指针变量之间可相互赋值,表示二个指针指向同一内存空间。空指针指针没有指向任何空间空指针用常量NULL表示,NULL的值一般赋为0不能引用空指针指向的值指针使用指针变量可以指向不同的变量。如上例中intp指向x,指针变量的使用设有定义

intx,y;int*p1,*p2;1000x1004y1008p11012p2执行语句:x=23;y=234;100023x1004234y1008p11012p2执行语句:p1=&x;p2=&y;100023x1004234y10081000p110121004p2执行语句:*p1=34;p2=p1;100034x1004234y10081000p110121000p2指针变量的使用设有定义1000x1004y1008p1101指针实例有以下结构Ap1aBp2b比较执行p1=p2和*p1=*p2后的不同结果。

解:

Ap1aBp2bBp1aBp2b指针实例有以下结构Ap1aBp2b比较执行p1=p2和指针的初始化指针在使用前必须初始化。和别的变量一样,定义指针不初始化是一个比较普通的错误。没有初始化的指针可能指向任意地址,对这些指针作操作可能会导致程序错误。NULL是一个特殊指针值,称为空指针。它的值为0。它可被用来初始化一个指针,表示不指向任何地址。思考:int*p;*p=5;有什么问题?指针的初始化指针在使用前必须初始化。第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针第7章间接访问—指针指针的概念指针运算和数组指向数组元素的指针数组元素是一个独立的变量,因此可以有指针指向它。如:p=&a[1],p=&a[i]数组元素的地址是通过数组首地址计算的。如数组的首地址是1000,则第i个元素的地址是1000+i*每个数组元素所占的空间长度指针运算和数组指向数组元素的指针指针与数组在C++中,指针和数组关系密切,几乎可以互换使用数组名可以看成是常量指针,对一维数组来说,数组名是数组的起始地址,也就是第0个元素的地址如执行了p=array,则p与array是等价的,对该指针可以进行任何有关数组下标的操作指针与数组在C++中,指针和数组关系密切,几乎可以互换使用例如:有定义inta[10],*p

并且执行了p=a,那么可用下列语句访问数组a的元素for(i=0;i<10;++i)cout<<p[i];例如:有定义inta[10],*p指针运算指针+1表示数组中指针指向元素的下一元素地址;指针-1表示数组中指针指向元素的上一元素地址;合法的指针操作:p+k,p-k,p1-p2指针保存的是一个地址,地址是一个整型数,因此可以进行各种算术运算,但仅有加减运算是有意义的。指针运算与数组有密切的关系指针运算指针+1表示数组中指针指向元素的下一元素地址;指针保数组元素的指针表示当把数组名,如intarray,赋给了一个同类指针intp后,intarray的元素可以通过intp访问。第i个元素的地址可表示为intp+i,第i个元素的值可表示为*(intp+i)。通过指针访问数组时,下标有效范围由程序员自己检查。如输出数组a的十个元素数组元素的指针表示当把数组名,如intarray,赋给了一方法3:

for(p=a;p<a+10;++p)cout<<

*p;

方法2:

for(i=0;i<10;++i)cout<<*(a+i);

方法1:for(i=0;i<10;++i)cout<<a[i];

方法4:

for(p=a,i=0;i<10;++i)cout<<

*(p+i);

方法5:for(p=a,i=0;i<10;++i)cout<<

p[i];下列程序段有无问题?

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

*a;++a;}方法3:方法2:方法1:方法4:方法5:下列程序段指针和数组的区别虽然通过指针可以访问数组,但两者本质是不同的。在定义数组时为数组的各个元素分配了全部的存储区,而在定义指针时,仅仅分配四个字节的存储区存放指针地址。只有把一个数组名付给了对应的指针后,指针才能当作数组使用如有:intarray[5],*intp;arrayintp当执行了

intp=array后指针和数组的区别虽然通过指针可以访问数组,但两者本质是不同的第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针第7章间接访问—指针指针的概念动态分配在C++语言中,每个程序需要用到几个变量,在写程序前就应该知道。每个数组有几个元素也必须在写程序时就决定。有时我们并不知道我们需要多大的数组元素直到程序开始运行。因此希望能在程序中根据某一个当前运行值来决定数组的大小。如设计一个打印魔阵的程序,我们希望先输入魔阵的阶数,然后根据阶数定义一个矩阵动态分配在C++语言中,每个程序需要用到几个变量,在写程序前动态分配方法这些问题的解决方案就是内存的动态分配。我们定义一个指针,并让它指向一个合适的内存。如:

int*scores;scores=内存的起始地址;动态分配方法这些问题的解决方案就是内存的动态分配。我们定义一动态内存分配与回收C++中由new和delete两个运算符替代

-运算符new用于进行内存分配:

申请动态变量:p=newtype;

申请动态数组:p=newtype[size];

申请动态变量并初始化:p=newtype(初值);

-运算符delete释放new分配的内存:

释放动态变量:deletep;

释放动态数组:delete[]p;动态内存分配与回收C++中由new和delete两个运算动态内存分配与回收//为简单变量动态分配内存,并作初始化intmain(){int*p;p=newint(99);//动态分配内存,并将99作为初始化值赋给它

cout<<*p;deletep;return0;}动态内存分配与回收//为简单变量动态分配内存,并作初始化动态内存分配与回收//动态字符串的使用intmain(){int*p;char*q;p=newint(5);q=newchar[10];strcpy(q,"abcde");cout<<*p<<endl;cout<<q<<endl;deletep;deleteq;return0;}输出结果:5abcde动态内存分配与回收//动态字符串的使用输出结果:动态分配的检查new操作的结果是申请到的空间的地址当系统空间用完时,new操作可能失败new操作失败时,返回空指针动态分配的检查new操作的结果是申请到的空间的地址动态内存分配与回收//动态分配检查intmain(){int*p;p=newint;if(!p){cout<<"allocationfailure\n";return1;}*p=20;cout<<*p;deletep;return0;}动态内存分配与回收//动态分配检查assert宏assert()宏在标准头文件cassert中assert()有一个参数,表示断言为真的表达式,预处理器产生测试该断言的代码。如果断言不是真,则在发出一个错误消息后程序会终止。assert宏assert()宏在标准头文件cassert#include<iostream>#include<cassert>//包含assert宏的头文件usingnamespacestd;intmain(){int*p;p=newint;assert(p!=0);//p等于0,则退出程序*p=20;cout<<*p;

deletep;return0;}#include<iostream>内存分配的进一步介绍静态分配:对全局变量和静态变量,编译器为它们分配空间,这些空间在整个程序运行期间都存在自动分配:函数内的局部变量空间是分配在系统的栈工作区。当函数被调用时,空间被分配;当函数执行结束后,空间被释放动态分配:在程序执行过程中需要新的存储空间时,可用动态分配的方法向系统申请新的空间,当不再使用时用显式的方法还给系统。这部分空间是从被称为堆的内存区域分配。OSProgramHeap动态分配Stack自动分配Globevariables静态分配内存分配的进一步介绍静态分配:对全局变量和静态变量,编译器为内存泄漏动态变量是通过指针间接访问的。如果该指针被修改,这个区域就被丢失了。堆管理器认为你在继续使用它们,但你不知道它们在哪里,这称为内存泄露。为了避免出现孤立的区域,应该明白地告诉堆管理器这些区域不再使用。可以采用delete操作,它释放由new申请的内存。当释放了内存区域,堆管理器重新收回这些区域,而指针仍然指向堆区域,但不能再使用指针指向的这些区域。要确保在程序中同一个区域释放一次。释放内存对一些程序不重要,但对有些程序很重要。如果你的程序要运行很长时间,而且存在内存泄漏,这样程序会耗尽所有内存,直至崩溃。内存泄漏动态变量是通过指针间接访问的。如果该指针被修改,这个动态空间分配示例输入一批数据,计算它们的和。数据个数在设计程序时尚无法确定。存储一批数据应该用数组,但C++语言的数组大小必须是固定的。该问题有两个解决方案:开设一个足够大的数组,每次运行时只使用一部分。缺点:浪费空间用动态内存分配根据输入的数据量申请一个动态数组动态空间分配示例输入一批数据,计算它们的和。数据个数在设计程#include<iostream>usingnamespacestd;intmain(){int*p,i,n,sum=0;cout<<"Anarraywillbecreateddynamically.\n\n";cout<<"Inputanarraysizenfollowedbynintegers:";cin>>n;if

(!(p=newint[n]))exit(1);for(i=0;i<n;++i)cin>>p[i];for(i=0;i<n;++i)sum+=p[i];delete[]p;

cout<<"Numberofelements:"<<n<<endl;cout<<"Sumoftheelements:"<<sum<<endl;return0;}可改为:p=newint[n];assert(p!=NULL);#include<iostream>可改为:第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针第7章间接访问—指针指针的概念字符串再讨论字符串的另一种表示是定义一个指向字符的指针。然后直接将一个字符串常量或字符串变量赋给它如

char*String,ss[]=“abcdef”;String=“abcde”;String=ss;字符串再讨论字符串的另一种表示是定义一个指向字符的指针。然后String“abcde”ProgramOS数据段或代码区栈堆String=“abcde”;的执行结果字符串常量存储在一个称为数据段的内存区域里将存储字符串”abcde”的内存的首地址赋给指针变量String。String“abcde”PrograString“abcdef\0”ProgramOS数据段栈堆String=ss的执行过程将字符数组ss的起始地址存入StringStringProgramOS数据段栈堆StString=newchar[5];

strcpy(String,“aaa”)StringProgramOS数据段栈堆“aaa\0”动态变量存储在堆工作区将存储字符串”aaa”的内存的首地址赋给指针变量String。String=newchar[5];

strcpy(S用指针表示的字符串的操作可以直接作为字符串操作函数的参数。但必须注意,如果该指针指向的是一个字符串常量时,则使用是受限的。如不能作为strcpy的第一个参数由于在C++中,数组名被解释成指向数组首地址的指针。因此,字符串是用一个指针变量表示,我们可以把此指针变量解释成数组的首地址,通过下标访问字符串中的字符。如string[3]的值是d。用指针表示的字符串的操作可以直接作为字符串操作函数的参数。但用指针处理串目的:编写一个记录串中单词的个数的函数。关键技术:要传递一个字符串给函数用指针处理串目的:编写一个记录串中单词的个数的函数。字符串作为函数的参数字符串作为函数的参数和数组名作为参数传递一样,可以有两种方法作为字符数组传递作为指向字符的指针传递两种传递方式的本质是一样的,都是传递了字符串的首地址字符串作为字符数组传递时不需要指定长度。因为字符串操作的结束是依据‘\0’字符串作为函数的参数字符串作为函数的参数和数组名作为参数传递#include<ctype>Usingnamespacestd;intword_cnt(constchar*s){intcnt=0;while(*s!='\0'){ while(isspace(*s))++s;//跳过空白字符

if(*s!='\0'){++cnt; //找到一个单词

while(!isspace(*s)&&*s!='\0') ++s;//跳过单词 }}returncnt;}统计字符串中单词数的函数#include<ctype>统计字符串中单词数的函数第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针第7章间接访问—指针指针的概念指针作为函数参数和返回值指针作为函数参数数组名作为函数参数返回指针的函数引用和引用传递返回引用的函数指针作为函数参数和返回值指针作为函数参数指针作为函数参数例:编一函数,交换二个参数值。

voidswap(inta,intb){intc;c=a;a=b;b=c;}希望通过调用swap(x,y)交换变量x和y的值新手可能会编出如下的函数:因为C++采用的是值传递机制,函数中a、b值的交换不会影响实际参数x和y的值指针作为函数参数例:编一函数,交换二个参数值。voidsvoidswap(int*a,int*b){intc;c=*a;*a=*b;*b=c;}

34xyab交换x和y的值,可以调用swap(&x,&y)用指针作为参数可以在函数中修改主调程序的变量值,即实现变量传递。必须小心使用!!!正确的方法voidswap(int*a,int*b)3能解一元二次方程的函数目前为止我们了解到的函数只能有一个返回值,由return语句返回。一个一元二次方程有二个解,如何让此函数返回二个解。答案是采用指针作为函数的参数。由调用程序准备好存放两个根的变量,将变量地址传给函数。在函数中将两个根的值分别放入这两个地址能解一元二次方程的函数目前为止我们了解到的函数只能有一个返回函数原型函数原型可设计为:

voidSolveQuadratic(doublea,doubleb,doublec,

double*px1,double*px2)函数的调用

SolveQuadratic(1.3,4.5,2.1,&x1,&x2)SolveQuadratic(a,b,c,&x1,&x2)函数的参数有两类:输入参数和输出参数。一般,输入参数用值传递,输出参数用指针传递。在参数表中,输入参数放在前面,输出参数放在后面。函数原型函数原型可设计为:原型的改进并不是每个一元二次方程都有两个不同根,有的可能有两个等根,有的可能没有根。函数的调用者如何知道x1和x2中包含的是否是有效的解?解决方案:让函数返回一个整型数。该整型数表示解的情况原型的改进并不是每个一元二次方程都有两个不同根,有的可能有两完整的函数intSolveQuadratic(doublea,doubleb,doublec,double*px1,double*px2) {doubledisc,sqrtDisc;if(a==0)return3;//不是一元二次方程

disc=b*b-4*a*c;if(disc<0)return2;//无根

if(disc==0){*px1=-b/(2*a);return1;}//等根//两个不等根

sqrtDisc=sqrt(disc);*px1=(-b+sqrtDisc)/(2*a);*px2=(-b-sqrtDisc)/(2*a);return0;}完整的函数intSolveQuadratic(double函数的调用intmain(){doublea,b,c,x1,x2;intresult;cout<<"请输入a,b,c:";cin>>a>>b>>c;result=SolveQuadratic(a,b,c,&x1,&x2);switch(result){case0:cout<<"方程有两个不同的根:x1="<<x1<<"x2="<<x2;break;case1:cout<<"方程有两个等根:"<<x1;break;

case2:cout<<"方程无根";break;case3:cout<<"不是一元二次方程";}return0;}函数的调用intmain()指针作为函数参数和返回值指针作为函数参数数组名作为函数参数返回指针的函数引用和引用传递返回引用的函数指针作为函数参数和返回值指针作为函数参数数组传递的进一步讨论数组传递的本质是地址传递,因此形参和实参可以使用数组名,也可以使用指针。数组传递是函数原型可写为:

typefun(typea[],intsize);

也可写为typefun(type*p,intsize);

但在函数内部,a和p都能当作数组使用调用时,对这两种形式都可用数组名或指针作为实参建议:如果传递的是数组,用第一种形式;如果传递的是普通的指针,用第二种形式数组传递的进一步讨论数组传递的本质是地址传递,因此形参和实参#include<iostream>usingnamespacestd;voidf(intarr[],intk){cout<<sizeof(arr)<<""<<sizeof(k)<<endl;}voidmain(){inta[10]={1,2,3,4,5,6,7,8,9,0};cout<<sizeof(a)<<endl;f(a,10);}输出:404C++将数组名作为参数传递处理成指针的传递即在main中,a是数组,占用了40个字节。而在函数f中,arr是一个指针#include<iostream>输出:C++将数组名作数组传递的灵活性voidsort(intp[],intn){...}main(){inta[100];...sort(a,100);//排序整个数组

sort(a,50);//排序数组的前50个元素

sort(a+50,50);//排序数组的后50个元素

...}数组传递的灵活性voidsort(intp[],实例设计一函数用分治法在一个整数数组中找出最大和最小值具体方法是:如果数组只有一个元素,则最大最小都是他。如果数组中只有两个元素,则大的一个就是最大数,小的就是最小数。这种情况不需要递归。否则,将数组分成两半,递归找出前一半的最大最小值和后一半的最大最小值。取两个最大值中的较大者作为最大值,两个最小值中的较小值作为最小值。

实例设计一函数用分治法在一个整数数组中找出最大和最小值设计考虑函数的参数是要查找的数组,传递一个数组要两个参数:数组名和数组规模函数返回的是数组中的最大值和最小值,将它们作为指针传递的参数查找数组的前一半就是递归调用本函数,传给他的参数是当前的数组名,数组的规模是原来的一半查找数组的后一半也是递归调用本函数,传给它的参数是数组后一半的起始地址,规模也是原来的一半设计考虑函数的参数是要查找的数组,传递一个数组要两个参数:数伪代码voidminmax(inta[],intn,int*min_ptr,int*max_ptr){switch(n){case1:最大最小都是a[0];case2:大的得放入*max_ptr,小的放入*min_ptr;

Default:对数组a的前一半和后一般分别调用minmax;取两个最大值中的较大者作为最大值;取两个最小值中的较小值作为最小值

}}伪代码voidminmax(inta[],invoidminmax(inta[],intn,int*min_ptr,int*max_ptr){intmin1,max1,min2,max2;switch(n){case1:*min_ptr=*max_ptr=a[0];return;case2:if(a[0]<a[1]){*min_ptr=a[0];*max_ptr=a[1];}else{*min_ptr=a[1];*max_ptr=a[0];}return;default:minmax(a,n/2,&min1,&max1);

minmax(a+n/2,n-n/2,&min2,&max2);

if(min1<min2)*min_ptr=min1;

else*min_ptr=min2;if(max1<max2)*max_ptr=max2;else*max_ptr=max1;return; }}voidminmax(inta[],intn指针作为函数参数和返回值指针作为函数参数数组名作为函数参数返回指针的函数引用和引用传递返回引用的函数指针作为函数参数和返回值指针作为函数参数返回指针的函数函数的返回值可以是一个指针返回指针的函数原型:类型*函数名(形式参数表);当函数的返回值是指针时,返回地址对应的变量不能是局部变量。返回指针的函数函数的返回值可以是一个指针实例设计一个函数从一个字符串中取出一个子串。原型设计:从哪一个字符串中取子串、起点和终点返回值:字符串可以用一个指向字符的指针表示,所以函数的执行结果是一个字符串,表示一个字符串可以用一个指向字符的指针返回值指针指向的空间必须在返回后还存在。这可以用动态字符数组实例设计一个函数从一个字符串中取出一个子串。char*subString(char*s,intstart,intend){ intlen=strlen(s); if(start<0||start>=len||end<0||end>=len||start>end){ cout<<"起始或终止位置错"<<endl; returnNULL; } char*sub=newchar[end-start+2]; strncpy(sub,s+start,end-start+1); sub[end-start+1]='\0'; returnsub;}char*subString(char*s,ints指针作为函数参数和返回值指针作为函数参数数组名作为函数参数返回指针的函数引用和引用传递返回引用的函数指针作为函数参数和返回值指针作为函数参数引用传递引用传递是地址传递的另一种更简单明了的实现方法引用的概念函数中的引用引用传递引用传递是地址传递的另一种更简单明了的实现方法引用的C++中的引用引用的定义:给一个变量取一个别名,使一个内存单元可以通过不同的变量名来访问。例:inti;int&j=i;j是i的别名,i与j是同一个内存单元。C++引入引用的主要目的是将引用作为函数的参数。C++中的引用引用的定义:给一个变量取一个别名,使一个内存单引用传递引用传递是地址传递的另一种更简单明了的实现方法引用的概念函数中的引用引用传递引用传递是地址传递的另一种更简单明了的实现方法引用的引用参数C++引入引用的主要目的是将引用作为函数的参数。指针参数voidswap(int*m,int*n){inttemp;temp=*m;*m=*n;*n=temp;}调用:swap(&x,&y)引用参数voidswap(int&m,int&n){inttemp;temp=m;m=n;n=temp;}调用:swap(x,y)注意:实参必须是变量,而不能是一个表达式引用参数C++引入引用的主要目的是将引用作为函数的参数。指针调用swap(x,y)时,相当于发生了变量定义

int&m=xint&n=y即,形式参数m和实际参数x共享一块空间,形式参数n和实际参数y共享一块空间。在swap函数中交换了m和n的值,就相当于交换了x和y的值。调用swap(x,y)时,相当于发生了变量定义指针作为函数参数和返回值指针作为函数参数数组名作为函数参数返回指针的函数引用和引用传递返回引用的函数指针作为函数参数和返回值指针作为函数参数返回引用的函数的主要用途将函数用于赋值运算符的左边,即作为左值。

inta[]={1,3,5,7,9};int&index(int);//声明返回引用的函数

voidmain(){index(2)=25;//将a[2]重新赋值为25cout<<index(2);}int&index(intj){returna[j];}//函数是a[j]的一个引用返回引用的函数的主要用途将函数用于赋值运算符的左边,即作为左第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针第7章间接访问—指针指针的概念指针数组与多级指针指针数组Main函数的参数多级指针指针数组与多级指针指针数组指针数组地址本身也是数据,他们也可以像其他数据一样组织成一个数组一个数组,如果他的元素均为指针,则称为指针数组一维指针数组的定义形式:类型名*数组名[数组长度];例如,char*String[10];定义了一个名为String的指针数组,该数组有10个元素,数组的每个成员是一个指向字符的指针指针数组地址本身也是数据,他们也可以像其他数据一样组织成一个指针数组的应用字符串可以用一个指向字符的指针表示,一组字符串可以用一个指向字符的指针数组来表示例:写一个函数用二分法查找某一个城市在城市表中是否出现。用递归实现关键问题:城市表的存储:用指向字符的指针数组查找时的比较:用字符串比较函数指针数组的应用字符串可以用一个指向字符的指针表示,一组字符串//该函数用二分查找在cityTable中查找cityName是否出现//lh和rh表示查找范围,返回出现的位置IntbinarySearch(char*cityTable[],intlh,intrh,char*cityName){intmid,result;if(lh<=rh){ mid=(lh+rh)/2; result=strcmp(cityTable[mid],cityName);if(result==0)returnmid;//找到

elseif(result>0)returnbinarySearch(cityTable,lh,mid-1,cityName); elsereturnbinarySearch(cityTable,mid+1,rh,cityName);}return-1;//没有找到}//该函数用二分查找在cityTable中查找cityNam函数的应用#include<iostream>usingnamespacestd;intbinarySearch(char*cityTable[],intlh,intrh,char*cityName);intmain(){char*string[10]={"aaa","bbb","ccc","ddd","eee","fff","ggg","hhh","iii","jjj"};chartmp[10];;while(cin>>tmp) cout<<binarySearch(string,0,9,tmp)<<endl;

return0;}函数的应用#include<iostream>“aaa”“bbb”“ccc”“ddd”“eee”“fff”“ggg”“hhh”“iii”“jjj”“aaa”“bbb”“ccc”“ddd”“eee”“fff”指针数组与多级指针指针数组Main函数的参数多级指针指针数组与多级指针指针数组main函数的形参如需要实现:copyab之类的功能,可以用带有参数的main函数来实现main函数有二个形式参数:intargc,char*argv[]

argc–参数的数目(包括命令名本身)argv[]—指向每个参数的指针,是一个指向字符串的指针数组main函数的形参如需要实现:copyab之类的功能,可把参数传递给main()#include<stdio.h>intmain(intargc,char*argv[]){ inti; cout<<"argc=“<<argc<<endl; for(i=0;i<argc;++i) cout<<"argv[“<<i<<“]=“<<argv[i]<<endl; return0;}假设生成的执行文件myprogram.exe把参数传递给main()#include<stdio.h>把参数传递给main()续假设生成的执行文件myprogram.exe在命令行输入:myprogram

输出结果:argc=1argv[0]=myprogram在命令行输入:myprogramtrythis

输出结果:argc=3argv[0]=myprogram argv[1]=tryargv[2]=this把参数传递给main()续假设生成的执行文件myprogmain函数参数实例编写一个求任意n个正整数的平均数的程序如果该程序对应的可执行文件名为aveg,则可以在命令行中输入

aveg1030502040↙

表示求10、30、50、20和40的平均值,对应的输出为30。main函数参数实例编写一个求任意n个正整数的平均数的程序设计考虑将这些数据作为命令行的参数从argc得到数据的个数从argv得到每一个数值,但注意数值是以字符串表示,要进行计算,必须把它转换成真正的数值由于每个数据都要转换,而且这个工作很独立,所以将它设计成一个函数设计考虑将这些数据作为命令行的参数字符串形式的数字转换到真正的数值intConvertStringToInt(char*s){intnum=0;while(*s){num=num*10+*s-'0';++s;}returnnum;}字符串形式的数字转换到真正的数值intConvertStr计算程序intmain(intargc,char*argv[]){intsum=0;for(inti=1;i<argc;++i)sum+=ConvertStringToInt(argv[i]);cout<<sum/(argc-1)<<endl;return0;}计算程序intmain(intargc,char*a指针数组与多级指针指针数组Main函数的参数多级指针指针数组与多级指针指针数组多级指针指针指向的内容还是一个指针,称为多级指针如有定义:char*string[10];string是一个数组,数组元素可以通过指针来访问。如果p是指向数组string的某一个元素,那么p指向的内容是一个指向字符的指针,因此p就是一个多级指针。string也是一个多级指针,不过是一个常指针多级指针指针指向的内容还是一个指针,称为多级指针多级指针的定义两级指针:类型名**变量名;三级指针:类型名***变量名;如:int**q;

表示q指向的内容是一个指向整型的指针。可以这样使用:intx=15,*p=&x;q=&p;同样:char**s;

表示s指向的内容是一个指向字符的指针qp15s“abcde”多级指针的定义两级指针:类型名**变量名;qp15s“ab多级指针的应用可以用指向指针的指针访问指针数组的元素。如#include<iostream>usingnamespacestd;intmain(){char*city[]={"aaa","bbb","ccc","ddd","eee"};char**p;for(p=city;p<city+5;++p)cout<<*p<<endl;return0;}输出结果:aaabbbcccdddeee多级指针的应用可以用指向指针的指针访问指针数组的元素。如输出第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针第7章间接访问—指针指针的概念二维数组与指针inta[3][4];等价于定义了3个变量a

a[1]

a[2]

a[0]123456789101112二维数组与指针inta[3][4];等价于定义了3个变量指向一维数组的指针a[]是一个指针数组,它的每个元素是一个整型指针,指向每一行的第一个元素。a是一个指向一维数组的指针,指向a[]的第一个元素。对a加1,事实上是跳到下一行指向一维数组的指针可以这样定义:类型名(*指针变量名)[一维数组的元素个数];注意:圆括号不能省略,如果省略了圆括号就变成了指针数组指向一维数组的指针a[]是一个指针数组,它的每个元素是一个等价于a[i][j]的表达式a[i][j]*(a[i]+j)(*(a+i))[j]*(*(a+i)+j)*(&a[0][0]+5*i+j)inta[3][5];等价于a[i][j]的表达式a[i][j]*(a[i]+用指向数组的指针输出二维数组aint(*p)[4],*q;for(p=a;p<a+3;++p){//每一行

for(q=*p;q<*p+4;++q)//每一列

cout<<*q<<'\t';cout<<endl; }注意:如果输出a和a[0],这两个值是相同的。但是,这两个值的含义是不同的,前者是第0行的首地址,它的类型是指向由四个元素组成的一位数组的首地址,后者是第0行第一个元素的地址,它的类型是整型指针用指向数组的指针输出二维数组aint(*p)[4],*q动态的二维数组方法一:用一维动态数组将它按行序转换成一维数组,用动态的一维数组存储。如一个3行4列的矩阵a可以存储为12个元素的一维数组访问i行j列的元素转换成访问一维数组的第4*i+j个元素方法二:用指向指针的指针,可以用a[i][j]访问用指向指针的指针指向一个一维的指针数组指针数组中的每个元素指向矩阵的每一行的第一个元素动态的二维数组方法一:用一维动态数组intmain(){int**a,i,j,k=0;a=newint*[3];for(i=0;i<3;++i)a[i]=newint[4];for(i=0;i<3;++i)

for(j=0;j<4;++j)a[i][j]=k++;for(i=0;i<3;++i){

cout<<endl; for(j=0;j<4;++j)cout<<a[i][j]<<'\t';}for(i=0;i<3;++i)

delete[]a[i];

delete[]a;return0;}intmain()第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针第7章间接访问—指针指针的概念函数的指针和指向函数的指针变量定义:返回类型(*指针变量名)();

使用:赋值

isdigit(intn,intk);{...}int(*p)(int,int);p=isdigit;

引用:a=isdigit(n,k);

a=(*p)(n,k);或a=p(n,k)函数的指针:指向函数代码的起始地址函数的指针和指向函数的指针变量定义:返回类型(*指针变量函数的指针的用途菜单选择的实现作为函数的参数函数的指针的用途菜单选择的实现函数指针的应用用函数指针的数组实现菜单选择例如,在一个工资管理系统中有如下功能:1。添加员工;2。删除员工;3。修改员工信息;4。打印工资单;5。打印汇总表;6。退出。在设计中,一般把每个功能设计成一个函数。如添加员工的函数为add,删除员工的函数为delete,修改员工信息的函数为modify,打印工资单的函数为printSalary,打印汇总表函数为printReport。主程序是一个循环,显示所有功能和它的编号,请用户输入编号,根据编号调用相应的函数。函数指针的应用用函数指针的数组实现菜单选择intmain(){intselect;while(1){cout<<"1--add\n";cout<<"2--delete\n";cout<<"3--modify\n";cout<<"4--printsalary\n";cout<<"5--printreport\n";cout<<"0--quit\n";cin>>select;

switch(select){case0:return0;case1:add();break;case2:erase();break;case3:modify();break;case4:printSalary();break;case5:printReport();break;default:cout<<"inputerror\n";}}}intmain()利用指向函数的指针intmain(){intselect;void(*func[6])()={NULL,add,erase,modify,printSalary,printReport};while(1){cout<<"1--add\n";cout<<"2--delete\n";

cout<<"3--modify\n";cout<<"4--printsalary\n";cout<<"5--printreport\n";cout<<"0--quit\n";

cin>>select;

if(select==0)return0;if(select>5)cout<<"inputerror\n";elsefunc[select]();}}利用指向函数的指针intmain()函数指针的应用把函数指针作为函数的参数例:设计一个通用的快速排序函数,可以排序任何类型的数据关键问题如何表示要排序的数据:将快速排序设计成一个函数模板,将待排序的数据类型设计成模板参数

不同类型的数据有不同的比较方式:向排序函数传递一个比较函数来解决。函数指针的应用把函数指针作为函数的参数template<classT>voidquicksort(Tdata[],intlow,inthigh,int(*comp)(T,T)){intmid;if(low>=high)return; mid=divide(data,low,high,comp); quicksort(data,low,mid-1,comp);quicksort(data,mid+1,high,comp); }template<classT>template<classT>intdivide(Tdata[],intlow,inthigh,int(*comp)(T,T)){Tk=data[low];do{while(low<high&&comp(data[high],k)>0)--high;if(low<high){data[low]=data[high];++low;}while(low<high&&comp(data[low],k)<0)++low;if(low<high){data[high]=data[low];--high;}}while(low!=high);data[low]=k;returnlow;}template<classT>通用快速排序的应用如果需要排序一组字符串,待排序的一组字符串保存在数组a中。a的定义如下:char*a[]={"aaa","nnn","rrr","fff","sss","ggg","ddd"};调用

quicksort(a,0,6,strcmp);通用快速排序的应用如果需要排序一组字符串,待排序的一组字符串通用快速排序的应用如果要排序一组整型数,则需要定义一个比较函数,如下所示:intintcmp(inta,intb){if(a==b)return0;if(a<b)return-1;elsereturn1;}如果整型数组a定义如下:inta[]={7,9,4,3,8,1,2,5,6,0};调用quicksort(b,0,9,intcmp);通用快速排序的应用如果要排序一组整型数,则需要定义一个比较函总结本章介绍了指针的概念,指针变量的定义、运算采用指针,可以使数组有多种访问方式将指针作为形式参数可以使一个函数与其调用函数共享数据动态分配内存总结本章介绍了指针的概念,指针变量的定义、运算第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针第7章间接访问—指针指针的概念指针介绍

本章将介绍C++语言的一个重要的特性:指针,为了成为一个优秀的C++语言程序员,你必须掌握指针并熟练地使用它们。指针是内存的地址并可作为数据是一个灵活和危险的机制允许共享处理数据允许内存动态分配(只要需要,而非预先定义)指针介绍本章将介绍C++语言的一个重要的特性:指针,为指针的概念指针就是把地址作为数据处理指针变量:存储地址的变量变量的指针:当一个变量存储另一个变量的地址时,那我们说它就是那个变量的指针使用指针的目的:提供间接访问指针的概念指针就是把地址作为数据处理指针的概念续如在某一程序中定义了

intx=2;如系统给x分配的空间是1000号单元,则指向x的指针是另一个变量p,p中存放的数据为10001000号单元的内容有两种访问方式:访问变量x(直接访问)访问变量p指向的单元的内容(间接访问)100021000xp指针的概念续如在某一程序中定义了10002100定义指针变量定义指针变量要告诉编译器该变量中存放的是一个地址。指针变量的主要用途是提供间接访问,因此也需要知道指针指向的单元的数据类型指针变量的定义类型标识符*指针变量;如:int*intp;double*doublep;int*p,x,*q;定义指针变量定义指针变量要告诉编译器该变量中存放的是一个地址指针变量的操作如何让指针指向某一变量?因为我们不知道系统分配给变量的真正地址是什么。用地址运算符“&”

解决。如表达式“&x”

返回的是变量x

的地址。如:intp=&x;&运算符后面不能跟常量或表达式。如&2

是没有意义的,&(m*n+p)。也是没有意义的如何通过指针变量处理和改变它所指向的单元的值?用引用运算符“*”解决。如*intp

表示的是intp

指向的这个单元的内容。如:*intp=5等价于x=5在对intp

使用引用运算之前,必须先对intp

赋值指针变量的操作如何让指针指向某一变量?因为我们不知道系统分配指针实例如有:intX,*intp,Y;X=3;Y=4;intp=&X;1000intp10044Y10003X如执行:*intp=Y+4;1000intp10044Y10008X注意:不能用intp=100;因为我们永远不知道变量存储的 真实地址,而且程序每次运行变量地址可能都不同。指针实例如有:1000intp10044Y10003X如执行指针使用指针变量可以指向不同的变量。如上例中intp指向x,我们可以通过对intp的重新赋值改变指针的指向。如果想让intp指向y,只要执行intp=&y就可以了。这时,intp与x无任何关系。同类的指针变量之间可相互赋值,表示二个指针指向同一内存空间。空指针指针没有指向任何空间空指针用常量NULL表示,NULL的值一般赋为0不能引用空指针指向的值指针使用指针变量可以指向不同的变量。如上例中intp指向x,指针变量的使用设有定义

intx,y;int*p1,*p2;1000x1004y1008p11012p2执行语句:x=23;y=234;100023x1004234y1008p11012p2执行语句:p1=&x;p2=&y;100023x1004234y10081000p110121004p2执行语句:*p1=34;p2=p1;100034x1004234y10081000p110121000p2指针变量的使用设有定义1000x1004y1008p1101指针实例有以下结构Ap1aBp2b比较执行p1=p2和*p1=*p2后的不同结果。

解:

Ap1aBp2bBp1aBp2b指针实例有以下结构Ap1aBp2b比较执行p1=p2和指针的初始化指针在使用前必须初始化。和别的变量一样,定义指针不初始化是一个比较普通的错误。没有初始化的指针可能指向任意地址,对这些指针作操作可能会导致程序错误。NULL是一个特殊指针值,称为空指针。它的值为0。它可被用来初始化一个指针,表示不指向任何地址。思考:int*p;*p=5;有什么问题?指针的初始化指针在使用前必须初始化。第7章间接访问—指针指针的概念指针运算与数组动态内存分配字符串再讨论指针作为函数参数和返回值指针数组与多级指针指向多维数组的指针指向函数的指针第7章间接访问—指针指针的概念指针运算和数组指向数组元素的指针数组元素是一个独立的变量,因此可以有指针指向它。如:p=&a[1],p=&a[i]数组元素的地址是通过数组首地址计算的。如数组的首地址是1000,则第i个元素的地址是1000+i*每个数组元素所占的空间长度指针运算和数组指向数组元素的指针指针与数组在C++中,指针和数组关系密切,几乎可以互换使用数组名可以看成是常量指针,对一维数组来说,数组名是数组的起始地址,也就是第0个元素的地址如执行了p=array,则p与array是等价的,对该指针可以进行任何有关数组下标的操作指针与数组在C++中,指针和数组关系密切,几乎可以互换使用例如:有定义inta[10],*p

并且执行了p=a,那么可用下列语句访问数组a的元素for(i=0;i<10;++i)cout<<p[i];例如:有定义inta[10],*p指针运算指针+1表示数组中指针指向元素的下一元素地址;指针-1表示数组中指针指向元素的上一元素地址;合法的指针操作:p+k,p-k,p1-p2指针保存的是一个地址,地址是一个整型数,因此可以进行各种算术运算,但仅有加减运算是有意义的。指针运算与数组有密切的关系指针运算指针+1表示数组中指针指向元素的下一元素地址;指针保数组元素的指针表示当把数组名,如intarray,赋给了一个同类指针intp后,intarray的元素可以通过intp访问。第i个元素的地址可表示为intp+i,第i个元素的值可表示为*(intp+i)。通过指针访问数组时,下标有效范围由程序员自己检查。如输出数组a的十个元素数组元素的指针表示当把数组名,如intarray,赋给了一方法3:

for(p=a;p<a+10;++p)cout<<

*p;

方法2:

for(i=0;i<10;++i)cout<<*(a+i);

方法1:for(i=0;i<10;++i)cout<<a[i];

方法4:

for(p=a,i=0;i<10;++i)cout<<

*(p+i);

方法5:for(p=a,i=0;i<10;++i)

温馨提示

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

最新文档

评论

0/150

提交评论