《指针的定义和应用ppt课件.ppt》由会员分享,可在线阅读,更多相关《指针的定义和应用ppt课件.ppt(65页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第第1515章章 指指 针针西南交通大学软件学院西南交通大学软件学院计算机基础教研室计算机基础教研室C+C+编程导论编程导论 前一页 休息2本章主要内容本章主要内容vC+C+中指针的基本概念中指针的基本概念v指针类型变量的定义方法指针类型变量的定义方法v指针与地址运算符指针与地址运算符v指针变量赋值、指针的运算指针变量赋值、指针的运算v通过指针类型的变量去访问某个变量或数组元通过指针类型的变量去访问某个变量或数组元素的值素的值v引用引用v动态分配内存动态分配内存v按引用调用按引用调用 前一页 休息3什么是地址什么是地址?l计算机的内存储器就象一个巨大的一计算机的内存储器就象一个巨大的一维数组维
2、数组, 每个数组元素就是一个存储每个数组元素就是一个存储单元(在微型计算机中其大小通常为单元(在微型计算机中其大小通常为一个字节)。一个字节)。l就象数组中的每个元素都有一个下标就象数组中的每个元素都有一个下标一样一样, 每个内存单元都有一个编号每个内存单元都有一个编号, 又又称地址。称地址。 前一页 休息4什么是地址什么是地址?l在运行一个程序时在运行一个程序时, 程序本身及其所程序本身及其所用到的数据都要放在内存储器中:程用到的数据都要放在内存储器中:程序、函数、变量、常数、数组和对象序、函数、变量、常数、数组和对象等等, 在内存储器中占有一席之地。在内存储器中占有一席之地。 l存放在内存
3、储器中的程序和数据都有存放在内存储器中的程序和数据都有一个地址一个地址, 用它们占用的那片存储单用它们占用的那片存储单元中的第一个存储单元的地址表示。元中的第一个存储单元的地址表示。 前一页 休息5什么是地址什么是地址?l在在C+中,为某个变量或者函数分配中,为某个变量或者函数分配内存储器的工作由编译程序完成。内存储器的工作由编译程序完成。l内存地址的访问方式内存地址的访问方式 直接访问方式:通过变量名访问直接访问方式:通过变量名访问 间接访问方式:通过地址访问间接访问方式:通过地址访问 前一页 休息6如何知道某个变量、数组、函数的地址如何知道某个变量、数组、函数的地址+规定规定:v变量的地址
4、可以使用地址运算符变量的地址可以使用地址运算符&求求得。例如得。例如, &x表示变量表示变量x的地址的地址;v数组的地址数组的地址, 即数组第一个元素的地即数组第一个元素的地址址, 可以直接用数组名表示可以直接用数组名表示;v函数的地址用函数名表示。函数的地址用函数名表示。 前一页 休息7什么是指针什么是指针l指针是指针是C+语言中的一种数据类型,语言中的一种数据类型,是专门用来处理地址的。是专门用来处理地址的。l指针是某个内存单元的首地址。指针是某个内存单元的首地址。 前一页 休息8什么是指针变量?什么是指针变量?v指针变量是包含另一个变量地址的变指针变量是包含另一个变量地址的变量。量。v指
5、针变量也是一个变量,遵循先定义,指针变量也是一个变量,遵循先定义,后使用。后使用。v定义指针变量的类型是由该指针指向定义指针变量的类型是由该指针指向的变量类型决定。的变量类型决定。 前一页 休息9指针变量的概念定义例:int i; int * i_pointer; 指向整型变量的指针内存用户数据区内存用户数据区变量变量 i变量变量 j变量变量 i_pointer362000200020043010 前一页 休息10指针变量的声明指针变量的声明变量的指针变量的指针:变量在内存中的存放起始地址:变量在内存中的存放起始地址指针变量的声明:指针变量的声明: 类型标识符* 指针变量 例如:例如:int*
6、 p; 定义语句中的定义语句中的“*”表示该变量为指针变量表示该变量为指针变量 一个指针变量只能存储同一种类型变量的地址一个指针变量只能存储同一种类型变量的地址 前一页 休息11指针变量的初始化v语法形式语法形式 类型标识符类型标识符 * 指针名初始地址;指针名初始地址;例:例: int * pa=&a; 前一页 休息12指针变量的初始化v注意事项注意事项用变量地址作为初值时,该变量必须在指用变量地址作为初值时,该变量必须在指针初始化之前定义。针初始化之前定义。 如:如:int a; int * pa=&a;已赋初值的指针可以初始化另一已赋初值的指针可以初始化另一 个指针变个指针变量。量。in
7、t * pa=&a; int * pb; pb=pa; 前一页 休息13指针与地址运算符指针与地址运算符l“ &”在执行语句中作为取地址运算符,它是一元运算符,返回操作数的地址,操作数必须是变量名。l“*”除了可以在声明语句中声明指针时使用外,还可以在执行语句中作为为指针运算符使用,也称为“间接访问”运算符,指针运算符是一元运算符,指针运算符 * 表示指针所指向的变量的值。&a&a:取变量:取变量a a的地址。的地址。* *a a:指针变量所指向的变量的值。:指针变量所指向的变量的值。int y=5; intint y=5; int* * p; p=&y;cout p; p=&y;cout*
8、*p;p; 前一页 休息14指针与地址运算符指针与地址运算符l * *出现在声明语句和执行语句中出现在声明语句和执行语句中的含义是不同的。的含义是不同的。l intint* * p; p; / / * *在声明语句中表在声明语句中表示声明的是指针,声明示声明的是指针,声明p p是整型指是整型指针针l coutcout* *p; p; / / * *在执行语句中表在执行语句中表示指针所指对象的内容示指针所指对象的内容 前一页 休息15指针变量的赋值运算指针变量的赋值运算指针变量指针变量= =地址地址v p = &a; p = &a; v p=array;/ p=array;/将数组的首地址赋值给
9、将数组的首地址赋值给p pv p= &arrayi; / p= &arrayi; /将数组的第将数组的第i i个元个元素的地址赋值给素的地址赋值给p pv p = max;/ p = max;/将函数将函数maxmax的入口地址赋的入口地址赋给给p pv p1=p2;/ p1=p2;/将指针将指针p2p2的值赋个指针的值赋个指针p1p1 前一页 休息16指针变量的赋值运算指针变量的赋值运算指针变量指针变量= =地址地址v不能把常量或表达式的地址赋给指针变量。不能把常量或表达式的地址赋给指针变量。 如:如:P=&67P=&67;P=&(i+5)P=&(i+5)是非法的是非法的 v不能将一个整数赋
10、给指针变量,但可以赋整不能将一个整数赋给指针变量,但可以赋整数值数值0 0,表示该指针空指针,不指向任何内容。,表示该指针空指针,不指向任何内容。v指针的类型是它所指向变量的类型。指针的类型是它所指向变量的类型。v允许声明指向允许声明指向 void void 类型的指针。该指针可类型的指针。该指针可以被赋予任何类型对象的地址。以被赋予任何类型对象的地址。例:例: void void * *general; general; 前一页 休息17例例1 指针的定义、赋值与使用指针的定义、赋值与使用#includeusing namespace std;void main( )int *i_point
11、er; int i; i_pointer=&i; i=10; cout“Output int i=”iendl; coutOutput int pointer i=*i_pointerendl; 前一页 休息18程序运行的结果是:程序运行的结果是:Output int i=10Output int pointer i=10 前一页 休息19指针变量的算术运算指针变量的算术运算v指针与整数的加减运算指针与整数的加减运算指针指针 p p 加上或减去加上或减去 n n ,其意义是,其意义是指针当前指向位置的前方或后方第指针当前指向位置的前方或后方第 n n 个数据的地址。个数据的地址。这种运算的结果
12、值取决于指针指向这种运算的结果值取决于指针指向的数据类型。的数据类型。v指针加一,减一运算指针加一,减一运算指向下一个或前一个数据。指向下一个或前一个数据。 前一页 休息20papa-2pa-1pa+1pa+2pa+3*(pa-2)*pa*(pa+1)*(pa+2)*(pa+3)*(pa-1)short *pa 前一页 休息21pb-1pbpb+1pb+2*(pb-1)*pb*(pb+1)*(pb+2)int *pb 前一页 休息22v关系运算关系运算 两个指针变量指向同一个数组中的元两个指针变量指向同一个数组中的元素时,其关系运算的结果表明了这两个素时,其关系运算的结果表明了这两个指针变量所
13、指向的数组元素的先后关系指针变量所指向的数组元素的先后关系 指针可以和零之间进行等于或不等于指针可以和零之间进行等于或不等于的关系运算。例如的关系运算。例如:p=0p=0或或p!=0p!=0 前一页 休息23指针的关系运算指针的关系运算例如:例如: char a10; char *p1,*p2; p1=a+2; p2=a+4; p1+;p2-; 前一页 休息24指向数组元素的指针指向数组元素的指针v定义与赋值定义与赋值例: int a10, *pa; pa=&a0; 或 pa=a; 前一页 休息25指向数组元素的指针指向数组元素的指针v通过指针引用数组元素通过指针引用数组元素v经过上述声明及赋
14、值后,在执行语句经过上述声明及赋值后,在执行语句中中*pa就是就是a0,*(pa+1)就是就是a1,. ,*(pa+i)就是就是ai.ai, *(pa+i), *(a+i), pai都是等效的。都是等效的。不能写不能写 a+,因为,因为a是数组首地址是常是数组首地址是常量。量。 前一页 休息26应用举例应用举例2设有一个int型数组a,有10个元素。用四种方法访问数组的各个元素:E使用数组名和下标E使用数组名和指针运算E使用指针变量E使用下标表示法引用指针指向的数组元素 前一页 休息27#include using namespace std;void main( ) int a10; int
15、 i,*p; for(i=0; iai; for(i=0; i10; i+) cout*(a+i); for(p=a; p-a10; p+) cout*p;p=a;for(i=0; i10; i+)coutpi; 前一页 休息28应用举例应用举例3#include #include using namespace std;void main( ) const int M=20,N=10; int aM,bN,cM; int d,e,f=0,*pa,*pb,*pc; 从键盘输入整数集合从键盘输入整数集合a a、b b的元素个的元素个数和各个元素的值,计算并输出其交集数和各个元素的值,计算并输出其
16、交集 前一页 休息29cout输入数组输入数组a中元素的个数:中元素的个数:d; cout输入数组输入数组a的的d个元素:个元素:endl;for(pa=a;pa*pa;cout输入数组输入数组b中元素的个数:中元素的个数:e;cout输入数组输入数组b的的e个元素:个元素:endl;for(pb=b;pb*pb; 前一页 休息30for(pa=a,pc=c;paa+d;pa+) for(pb=b;pbb+e;pb+) if(*pa=*pb) *pc+=*pa; f+;break; cout交集交集c的各个元素依次为的各个元素依次为:endl; for (pc=c;pcc+f;pc+) cou
17、tsetw(3)*pc; 前一页 休息31应用举例应用举例4#include #include using namespace std;void main( ) const int M=20,N=10; int aM,bN,cM+N; int d,e,f=0,*pa,*pb,*pc; 从键盘输入整数集合从键盘输入整数集合a a、b b的元素个的元素个数和各个元素的值,计算并输出其并集数和各个元素的值,计算并输出其并集 前一页 休息32cout输入数组输入数组a中元素的个数:中元素的个数:d; cout输入数组输入数组a的的d个元素:个元素:endl;for(pa=a;pa*pa;cout输入数
18、组输入数组b中元素的个数:中元素的个数:e;cout输入数组输入数组b的的e个元素:个元素:endl;for(pb=b;pb*pb; 前一页 休息33 for(pa=a,pc=c;paa+d;pa+,pc+) *pc=*pa; f+; for(pb=b;pbb+e;pb+) for(pa=a;pa=a+d) *pc+=*pb; f+; cout“并集并集c的各个元素依次为的各个元素依次为:endl; for (pc=c;pcc+f;pc+) coutsetw(3)p2; p2; 正确的正确的 / / 等价于等价于cincina; a; 前一页 休息36字符指针的定义、赋值和引用字符指针的定义、
19、赋值和引用-例例5#include #include using namespace std;void main ( ) char *p,sa20,sb20; int i; p=sa; strcpy (sa,“Today is Sunday.”); for (i=0;*(sa+i)!=0;i+) sbi=*p+ +; sbi=0; p=sb; coutp; 前一页 休息37动态存储分配动态存储分配v静态存储分配:静态存储分配: 程序中使用的变量和数组的类型、数目、大小程序中使用的变量和数组的类型、数目、大小是由编写程序时确定的,程序运行时这些数据占是由编写程序时确定的,程序运行时这些数据占用的
20、存储空间数也是一定的。用的存储空间数也是一定的。缺点:程序无法在运行时根据具体情况(如用户缺点:程序无法在运行时根据具体情况(如用户输入)灵活调整存储分配情况。输入)灵活调整存储分配情况。v动态存储分配:动态存储分配: 使用指针、运算符使用指针、运算符newnew和和deletedelete,在程序运行,在程序运行期间按照实际需要申请适量内存,克服了静态存期间按照实际需要申请适量内存,克服了静态存储分配的缺点。储分配的缺点。 前一页 休息38动态申请内存操作符动态申请内存操作符 new = new = new = new = new ( )功能:在程序执行期间,申请用于存放功能:在程序执行期间
21、,申请用于存放类型对象的内存空间,并依初值列表类型对象的内存空间,并依初值列表赋以初值。赋以初值。结果值:结果值:成功:类型的指针,指向新分配的内存成功:类型的指针,指向新分配的内存首地址首地址。失败:失败:0 0(NULLNULL) 前一页 休息39动态申请内存操作符动态申请内存操作符 newl例如:例如:l int x,*p=new int(6);l x=*p;l coutx*pendl; l delete p; 前一页 休息40动态申请内存操作符动态申请内存操作符 newnewnew运算符为数组申请内存运算符为数组申请内存使用形式:使用形式: = new = new 前一页 休息41释放
22、内存操作符释放内存操作符deletedelete 指针指针功能:释放指针功能:释放指针P所指向的内存。所指向的内存。P必须必须是是new操作的返回值。操作的返回值。 前一页 休息42使用使用动态存储分配时,应注意:时,应注意:确认分配成功后才能使用。确认分配成功后才能使用。分配成功后不宜变动指针的值。分配成功后不宜变动指针的值。用运算符用运算符new获取的内存空间,必须用获取的内存空间,必须用delete进行释放。进行释放。对一个指针只能调用一次对一个指针只能调用一次delete。在使用在使用delete运算符进行释放时,不用考虑运算符进行释放时,不用考虑数组的维数。数组的维数。 前一页 休息
23、43动态存储分配动态存储分配-例例6 从内存中获取一个整型数组,赋值后并打印出来。从内存中获取一个整型数组,赋值后并打印出来。#include iostream#include #include stdlib#include using namespace std;using namespace std;void main( )void main( ) int int n,i; / n,i; /定义数组元素的个数定义数组元素的个数 intint * *p;p;cout“please input the length of the array:”n;if(p=new intn)= =0) cou
24、t“cant allocate memory.”endl; exit(1);for(i=0;in;i+) pi=i*2;cout“now output the array:”endl;for(i=0;in;i+)coutpi“ “;coutendl;delete p;运行运行 结果为:结果为:please input the length of the array:6now output the array:0 2 4 6 8 10 前一页 休息46引用引用1声明引用的格式声明引用的格式1 类型类型& & 引用名引用名 = = 变量名;变量名; 例:例:intint a=1; a=1; int
25、 int& b=a; /& b=a; /将引用将引用b b声明为变量声明为变量a a的别名的别名 intint& c=a; /& c=a; /将引用将引用c c声明为变量声明为变量a a的别名的别名1引用是实体的别名,对引用的存取就是对变量的引用是实体的别名,对引用的存取就是对变量的存取,引用与被引用的实体具有相同的地址。存取,引用与被引用的实体具有相同的地址。1无初始化的引用是无效的。无初始化的引用是无效的。 coutcoutabc; /abc; /有声明语句有声明语句 前一页 休息47按引用调用按引用调用lC+C+用两种方式向函数传递数值:用两种方式向函数传递数值: 值调用值调用 引用调用
26、引用调用l按引用调用时,调用者让被调用函数能够按引用调用时,调用者让被调用函数能够直接访问调用者的数据,并允许被调用函直接访问调用者的数据,并允许被调用函数能够修改其中的数据。数能够修改其中的数据。l按引用调用分为用按引用调用分为用引用参数引用参数按引用调用和按引用调用和用用指针参数指针参数按引用调用。按引用调用。 前一页 休息48按引用调用按引用调用l用用引用参数引用参数是其相应参数的别名。要是其相应参数的别名。要表示函数的参数是按引用传递的,在表示函数的参数是按引用传递的,在函数原型和函数头中该参数类型后面函数原型和函数头中该参数类型后面加上加上& &。l在函数调用中,只要指定变量名,该在
27、函数调用中,只要指定变量名,该变量就会通过引用传递。在被调用函变量就会通过引用传递。在被调用函数体中,通过数体中,通过引用引用参数名指定的变量参数名指定的变量实际上就是引用了调用函数中的原始实际上就是引用了调用函数中的原始变量,被调用函数可以直接修改原始变量,被调用函数可以直接修改原始变量。变量。 前一页 休息49按引用调用按引用调用l用指针参数用指针参数按引用调用是用指针按引用调用是用指针和间接运算符模拟按引用调用。和间接运算符模拟按引用调用。调用函数并要修改参数时,传递调用函数并要修改参数时,传递该参数地址,在要修改数值的变该参数地址,在要修改数值的变量名前面量名前面加上加上& &符号。符
28、号。 前一页 休息50用引用参数用引用参数按引用调用按引用调用-例例7#include using namespace std;void cubeByReference(int &);void main()int z=4;coutz=z;cubeByReference(z);coutz=z; 前一页 休息51用引用参数用引用参数按引用调用按引用调用-例例7void cubeByReference(int& cRef)cRef=cRef*cRef*cRef; 前一页 休息52用指针参数用指针参数按引用调用按引用调用-例例8#includeusing namespace std;void cube
29、ByReference(int *);void main()int z=4;coutz=z;cubeByReference(&z);coutz=z; 前一页 休息53用指针参数用指针参数按引用调用按引用调用-例例8void cubeByReference(int *p)*p=*p*p*p; 前一页 休息54数组名做函数参数数组名做函数参数 l当数组名作为函数参数时,参数的传当数组名作为函数参数时,参数的传递方式为地址传递,即实参与形参表递方式为地址传递,即实参与形参表示同一个数组,因此被调函数中对形示同一个数组,因此被调函数中对形参数组内容的修改将修改主调函数中参数组内容的修改将修改主调函数中
30、实参数组的内容。实参数组的内容。 前一页 休息55数组名做函数参数数组名做函数参数l实参与形参都是数组名。实参与形参都是数组名。l实参数组与形参数组类型应一致,如不一实参数组与形参数组类型应一致,如不一致,结果将出错。致,结果将出错。l实参数组与形参数组维数大小可以不一致实参数组与形参数组维数大小可以不一致也可以一致。因为也可以一致。因为C+C+编译系统对形参大小编译系统对形参大小不作检查,只是将实参数组的起始地址传不作检查,只是将实参数组的起始地址传给形参。如果要求形参数组得到实参数组给形参。如果要求形参数组得到实参数组全部的元素值,最好指定形参数组与实参全部的元素值,最好指定形参数组与实参
31、数组大小一致。数组大小一致。 前一页 休息56数组名做函数参数数组名做函数参数l数组名作函数参数时,是数组名作函数参数时,是“地址传地址传递递”,把实参数组的起始地址传递给,把实参数组的起始地址传递给形参数组,两个数组共同占用同一段形参数组,两个数组共同占用同一段内存单元。内存单元。l形参数组是多维数时,定义时可以指形参数组是多维数时,定义时可以指定每一维的大小,也可省略第一维大定每一维的大小,也可省略第一维大小的说明,但不能省略第二维以及其小的说明,但不能省略第二维以及其它高维大小的说明。它高维大小的说明。 前一页 休息57 例例99l将键盘输入的将键盘输入的1010个整数按从小到大的个整数
32、按从小到大的顺序排序(选择法)。顺序排序(选择法)。 #includeiostream#include using namespace std;using namespace std;void invert(int a ,intvoid invert(int a ,int n) n) intint t=0; t=0;for(intfor(int i=0;in-1;i+) i=0;in-1;i+)for(int j=i+1;jn;jfor(int j=i+1;jajif(aiaj) t=ait=ai;ai=ajai=aj;ajaj=t;=t; intint main( ) main( ) int
33、int i; i;intint a10; a10;coutInput 10 numbers:endlcoutInput 10 numbers:endl; ;for(ifor(i=0;i10;i+)=0;iaicinai;invert(a,10);invert(a,10);coutThe sorted numbers is:endlcoutThe sorted numbers is:endl; ;for(ifor(i=0;i10;i+)=0;i10;i+)coutaiendlcoutaiendl; ;return 0; return 0; 前一页 休息60指向数组的指针变量作为函数参数指向数组的
34、指针变量作为函数参数 l将一组同类型的数据(数组)从一个将一组同类型的数据(数组)从一个函数传递到另一个函数,可以采用数函数传递到另一个函数,可以采用数组名作为函数参数,也可以采用指向组名作为函数参数,也可以采用指向数组的指针变量作为函数参数。数组的指针变量作为函数参数。l当函数的形参为指向数组的指针时,当函数的形参为指向数组的指针时,函数的实参即可以是数组名,也可以函数的实参即可以是数组名,也可以是指向数组起始地址的指针变量。是指向数组起始地址的指针变量。 前一页 休息61 例例1010l将一个数组中的数据按相反顺序存放。将一个数组中的数据按相反顺序存放。 #include iostream
35、#include using namespace std;using namespace std;void invert(int void invert(int * *p,intp,int n) n) int i,j,temp int i,j,temp; ; for(i=0,j=n-1;ij;i+,j for(i=0,j=n-1;ij;i+,j-)-) temp= temp=* *(p+i(p+i);); * *(p+i)=(p+i)=* *(p+j(p+j);); * *(p+j(p+j)=temp;)=temp; intint main( ) main( ) int int a10,i;
36、a10,i; /int*q=a; coutInput ten interger:endl coutInput ten interger:endl; ; for(i for(i=0;i10;i+)=0;iai cinai; invert(a,10); invert(a,10); /invert(q,10); for(i for(i=0;i10;i+)=0;i10;i+) coutaiendl coutaiendl; ; return 0; return 0; 前一页 休息64练习练习-阅读程序写结果阅读程序写结果l#include l#include l using namespace std;lvoid main( )l lconst int N=10;lint aN+1,p,x,*t;lcout输入输入a数组数组:endl;lfor(t=a;t*t; /(输入输入2,4,6,8,10,12,14,16,18,20 )lcout输入待插入的数输入待插入的数x:x; / (输入输入9 ) 前一页 休息65练习练习-阅读程序写结果阅读程序写结果lt=a;lp=0; lwhile (x*(t+p)&p=a+p;t-) l *(t+1)=*t;lt=a+p;l*t=x;lfor (t=a;t=a+N;t+)l coutsetw(4)*t;l