六章数组、指针与字符串.ppt

上传人:本田雅阁 文档编号:2131284 上传时间:2019-02-20 格式:PPT 页数:76 大小:1.11MB
返回 下载 相关 举报
六章数组、指针与字符串.ppt_第1页
第1页 / 共76页
六章数组、指针与字符串.ppt_第2页
第2页 / 共76页
六章数组、指针与字符串.ppt_第3页
第3页 / 共76页
亲,该文档总共76页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《六章数组、指针与字符串.ppt》由会员分享,可在线阅读,更多相关《六章数组、指针与字符串.ppt(76页珍藏版)》请在三一文库上搜索。

1、1,C+语言程序设计,第二单元 指针,第六章 数组、指针、字符串,2,教学要求: 1. 掌握数组的概念和使用; 2. 掌握指针的概念、运算、指针数组和对象指针; 3. 掌握动态内存分配的应用; 4. 掌握字符串的应用; 教学重点: 1. 数组的声明、存储,数组作为参数和对象数组 2. 指针的声明、运算,处理数组元素,对象指针 3. new运算和 delete运算 教学难点: 1. 指针的概念 2. 指针作为函数参数,处理数组元素,对象指针,3,第六章 数组 指针与字符串,教学目的: 通过本章的学习,学生应掌握使用数组;掌握字符串数据的组织和处理;掌握指针的概念和使用方法;掌握派生类的声明;继承

2、中的访问控制。 教学重点: 派生类的声明;继承中的访问控制。 教学难点:不同继承方式下对基类成员的访问控制 教学手段:电子教案,4,本章主要内容,数组 指针 动态存储分配 指针与数组 指针与函数 字符串,5,6.2 指针(关于内存地址),6.2.1内存空间的访问方式 地址编码 存储单元的地址 基本内存单元 从内存单元存取数据的 方法 通过变量名访问 通过地址访问,6,6.2.1指针变量的概念, 指针和指针变量 的概念 指针: 在C和C+中, 将地址形象化地 称为“指针”。一个 变量的地址称为该 变量的 “ 指针 ”。 指针变量: 专门用来存放地址的变量叫做 “ 指针变量 ”。,内存用户数据区,

3、7,6.2.2 指针变量的应用,指针变量应用的步骤: 1. 声明指针变量 2. 给指针变量赋值 3. 引用指针变量,8,指针变量的声明 定义指针变量的一般形式为:,6.2.3指针变量的定义与应用,数据类型 * 指针变量名,例如: int * pointer_1 ; float * pointer_2 ; 指针变量前面的 “ * ”,表示该变量的类型为指针型变量。 “数据类型”可以是任意类型,用来指定该指针变量所指向的变量的类型,称之为指针的类型。,专门用来存放int型数据的地址,专门用来存放float型数据的地址,9,指针变量的赋值 声明一个指针变量,未赋值时其中的地址值是一个随机的数。因此声

4、明指针变量之后必须先赋值,才可以使用。,例如: 指针变量 pointer_1 用来存放指向 int 型变量的指针 pointer_2存放指向 float 型变量的指针 。, 声明时同时初始化: 数据类型 *指针变量名 = 地址; 使用赋值语句赋值: 数据类型 *指针变量; 指针变量 = 地址;,10,6.2.4指针变量的赋值 “&”是取地址运算符,用来获取一个变量的地址。将获取的变量的地址赋值给指针变量。 不能把普通非 0 整数赋值给指针变量。,指针变量的定义与应用,int i , * pointer_1; pointer_1 = /*将变量 i 的地址存放到指针变量 pointer_1 中,

5、因此pointer_1 就 “指向”了变量 i */,11,指针变量的赋值 使用变量地址赋值时,该变量必须在赋值之前已声明过,且变量类型应与指针类型一致。 可以用一个已赋值的指针变量去赋值给另一 个指针变量。 数组名代表数组的起始地址,可以将数组名表示的地址赋值给指针变量,指针变量的定义与应用,int array 10 , * p1; p1 = array;,float f; int *p; p = ,类型不一致,12,指针变量的赋值 一般情况下,一种类型的指针变量只能存放相同类型的变量的地址。 特殊的 void 类型的指针,可以存放任何类型的变量的地址。经过类型强制转换,void 类型的指针

6、可以访问任何类型的数据。,指针变量的定义与应用,void *p1; int i, *p2; p1 = ,可以访问任何类型的数据,指针忘了赋值比整型变量忘了赋值危险得多。 例: int count; int *iPtr ; *iPtr = 58; iPtr当前指向什么地方?该代码能通过编译,但没有赋初值的指针iPtr是一个随机地址。“*iPtr = 58;”是把58赋到内存中的随机位置,因此很可能已经破坏了另一变量,甚至修改了栈中的函数返回地址,计算机将死机或进入死循环。,指针没有赋值这样非常危险,13,指针变量的引用 “ * ”是指针运算符,表示指针所指向的变量。,指针变量的定义与应用,int

7、 i , *p; p = ,* p,2,3,&i,i = 2; /* 通过变量名直接访问 */ *p = 3; /* *p是 p 所指向的变量,即变量 i ,这 是通过指针的间接访问*/,p 是指针变量,* p 就是 p 所指向的变量 i , 即 *p 等价于 变量 i 。,14,指针变量的引用,指针变量的定义与应用,注意:“ * ”出现在声明语句中和执行语句中含义不同。 1、“ * ”出现在声明语句中,表示声明的变量是指针变量。 例如: int *p; 2、 “ * ”出现在执行语句中,表示访问指针所指向的变量。 例如: *p = 3; printf ( “%d n”, *p );,例:in

8、t i = 26 ; int *P = ”混淆。前者是定义语句,*是指针定义符,C+为P指针分配一个指针空间,并用i 的地址值初始化,后者是执行语句,左右两边类型不匹配。 *操作符在指针上的两种用途要区分开:定义或声明时,建立一个指针;执行时,间接引用一指针。,也要注意: ” /取地址,15,例6-6 指针的声明、赋值与使用,#include void main( ) int *i_pointer; /声明int型指针i_pointer int i; /声明int型数i i_pointer= /输出int型指针所指地址的内容,16,指针变量的地址 指针也是变量,是变量就具有内存地址。所以指针也

9、有地址。 例:下面的程序输出iCount变量值,以及iPtr和iCount的地址值: # include int iCount = 18 ; int * iPtr = ,17,cout /指针本身的地址 运行结果: 58 0x0067fe00 0x0067fe00 58 0x0067fdfc,iPtr,0067:FDFC,0067:FE00,iCount,0067:FE00,58,18,指针与整型数的区别 指针在使用中必须类型匹配。例: int iCount = 26 ; int * iPtr = ”在BC中会引起类型转换的错误。 (cannot convert int* to int),强制

10、转换是合法。 例:允许语句“* iPtr = (int)” 但要注意其赋值的意义。该语句表示将变量iCount的地址值作为一个整型数赋给变量* iPtr ,即iCount变量。,19,指针与常量(const指针) 指向常量的指针,int a = 1; int * pi ; pi = ”。如果不想通过指针间接改变a的值, 可以声明指向常量的指针。,不能通过指针来改变所指对象的值,但指针本身可以改变,可以指向另外的对象。 在指针定义语句的类型前加const,表示指向的对象是常量。例: int n1=3; int const n2 = 5; const int *pn = /错误,20,指针与常量

11、指针常量,若声明指针常量,则指针本身的值不能被改变。 在指针定义语句的指针名前加const,表示指针本身是常量。例1: int n1 = 3; int const n2 = 5; int *const pn= /正确,21,void类型指针 一般情况下,指针的值只能赋给相同类型的指针。但是有一种特殊的void类型指针,可以存储任何类型的对象地址。 例: void类型指针的使用 void vobject ; /error,不能声明void类型的变量 void * pv ; / ok ,可以声明void类型的指针 int * pint ; int i ; void main( ) / void类型

12、的函数没有返回值 pv = / 类型强制转换 /void类型指针赋值给整型指针,22,指针与常量 指向常量的指针常量,可以定义一个指向常量的指针常量,它必须在定义时进行初始化。 const int ci = 7 ; int ai ; const int * const cpc = /ok,23,6.2.5指针变量的运算,指针与整数的加减运算 指针 p 加上或减去 n ,其意义是指针当前指向位置的前方或后方第 n 个数据的地址。 这种运算的结果值取决于指针指向的数据类型。 指针加一,减一运算 指向下一个或前一个数据的地址。 例如: y = *px+ y = *(px+) ( * 和 + 优先级相

13、同,自右向左运算),24,25,26,关系运算 指向相同类型数据的指针之间可以进行各种关系运算。 指向不同数据类型的指针,以及指针与一般整数变量之间的关系运算是无意义的。 指针可以和零之间进行等于或不等于的关系运算。例如:p = 0 或 p! = 0 赋值运算 向指针变量赋的值必须是地址常量或地址变量,不能是普通整数。但可以赋值为 整数0,表示 空指针。,指针变量的关系运算,例: int *p ; /声明一个int型指针p p = 0 ; /将p设置为空指针,不指向任何地址,27,6.2.6指向数组元素的指针,声明与赋值 例: int a10, *p; p = 通过指针引用数组元素经过上述声明

14、及赋值后: *p 就是a0,*(p+1) 就是a1,. , *(p+i) 就是 ai 。 a i , *(p+i), *(a+i), p i 都是等效的。 不能写 a+,因为 a 是数组首地址是常量。,28,例,设有一个int型数组a,有10个元素。用三种方法输出各元素: 使用数组名和下标 使用数组名和指针运算 使用指针变量,指 针,29,main( ) int a10; int i; for(i=0; iai; coutendl; for(i=0; i10; i+) coutai; , 使用数组名和下标,30,main( ) int a10; int i; for(i=0; iai; cou

15、tendl; for(i=0; i10; i+) cout*(a+i); , 使用数组名和指针运算,31, 使用指针变量,main( ) int a10; int *p,i; for(i=0; iai; coutendl; for( p = a; p (a+10); p+) cout*p; ,a,32,6.2.7 指针数组,数组的元素是指针变量 声明一维指针数组的语法形式,指 针,由 p_i0, p_i1 两个指针组成,类型名T *数组名下标表达式;,例: int *p_i 2 ;,33,例6-9 利用指针数组输出单位矩阵,void main( ) int line1 =1,0,0; /声明数

16、组,矩阵的第一行 int line2 =0,1,0; /声明数组,矩阵的第二行 int line3 =0,0,1; /声明数组,矩阵的第三行 int *p_line3; /声明整型指针数组 p_line0=line1; /初始化指针数组元素 p_line1=line2; p_line2=line3;,line10 line20 line30,&line10,&line20,&line30,P_line0,P_line1,P_line2,int line1 =1,0,0; int line2 =0,1,0 ; int line3 =0,0,1;,34,/输出单位矩阵 cout“Matrix te

17、st:“endl; for(int i=0;i3;i+) /对指针数组元素循环 for(int j=0;j3;j+) /对矩阵每一行循环 cout p_line i j “ “; coutendl; ,输出结果为: Matrix test: 1,0,0 0,1,0 0,0,1,35,36,for(int i=0;i3;i+) for(int j=0;j3;j+) cout *( p_line i + j ) “ “; coutendl; ,输出结果为: Matrix test: 1,0,0 0,1,0 0,0,1,(p_linei+j)表示指向第i行第j 个元素,*(p_linei+j)表示(

18、p_linei+j)指针所指的变量p_lineij,1.一维数组 int i ; int *p; int a10; p = 效果都一样,a0,a,37,for(int i=0;i3;i+) cout“p_line”i“: ” p_line i endl; for(int j=0;j3;j+) cout “ ”p_line i + j “ “; coutendl; ,38,二维数组的指针,int a 33= 1, 2, 3, 4, 5, 6, 7, 8, 9 ,a 0 ,a 1 ,a 2 ,1,2,3,4,5,6,7,8,9,a33,可以理解为一维指针数组 int * a3,每一行相当于一个具有

19、3个元素的一维int型数组,一维数组的情况 int *p; int a5;,a0 a1 a2 a3 a4,因为:a = ,a,a00 a01,a10 a11,a0,a1,a0=,错误,因为类型不一致,int *p1; int a22; p1 =a;,这样就正确了,因为p1和a现在都是二级指针,39,例6-10 二维数组举例,#include void main( ) int array223=11,12,13,21,22,23; for(int i=0;i2;i+) cout *( array2 + i ) endl; for(int j=0;j3;j+) cout *(*( array2 +

20、 i ) + j) “ ”; coutendl; ,指向i行,相当于array2i,即第i行的数组名。,指向第i行的第j个元素,是array2数组的第i 行j列元素array2ij。,40,在某次运行之后,程序的输出结果为: 0X0065FDE0 11,12,13 0X0065FDEC 21,22,23,for(int j=0;j3;j+) cout *(*( array2 + i ) + j) “ “; ,for(int j=0;j3;j+) cout *( a i + j) “ “; ,41,6.2.8 以指针作为函数参数, 指针变量作为形参 在函数调用时将实参的地址传递给形参,使实参和形

21、参指针变量指向同一内存单元。 通过在被调用函数中直接处理主调函数中的数据,而将函数的处理结果返回给调用者。 实参是数组名时形参可以是指针变量,在c语言中,以指针作为函数的形参有三个作用: 1.使实参与形参指针指向共同的内存空间,以达到参数双向传递的目的,即通过在被调用函数中直接处理主调函数中的数据,而将函数的处理结果返回给调用者。 2.减少函数调用时数据传递的开销。这一作用在C+中有时可以通过引用实现,有时还是需要使用指针。 3.通过指向函数的指针传递函数代码的首地址 在程序设计时,如果某个函数中以指针或引用作为形参都可以达到同样目的,则使用引用会使程序的可读性更好些。,42,例:,题目:读入

22、三个浮点数,将整数部分和小数部分分别输出 #include void splitfloat ( float x, int *intpart, float *fracpart ) /形参 intpart、 fracpart是指针变量 *intpart = int(x); / 取x的整数部分 *fracpart = x - *intpart; /取x的小数部分 ,43,void main(void) int i, n; float x, f; for (i = 0; i x; splitfloat ( x, /变量地址做实参 ,splitfloat ( x, ,n,f,0x0012FF78,0x0

23、012FF70,intpart,fracpart,0x0012FF78,0x0012FF70,void splitfloat ( float x, int *intpart, float *fracpart ),44,例:,实参为数组名, 形参为数组名或指针变量,void main ( ) float score_1 5 = 98.5,97,91.5,60,55; float score_210 = 67.5,89.5,99,69.5,77,76.5,54,60,95.5,78; cout average ( score_1, 5) ; cout average ( score_2, 10)

24、; ,45,/ 形参是数组 float average ( float array , int n ) int i; float aver, sum = array 0; for ( i = 1; i n; i +) sum = sum + array i ; aver = sum / n; return aver; ,46,/形参是指针变量 float average ( float *p, int n ) int i; float aver, sum = *p; for ( i = 1; i n; i +) sum = sum + *( p + i) ; aver = sum / n; r

25、eturn aver; ,47,6.2.9指针型函数 返回指针的函数称为指针函数 指针函数不能把在它内部说明的具有局部作用域的数据地址作为返回值。 指针函数的一般定义形式,数据类型 *函数名(参数表) 函数体 ,指针函数不能把在它内部说明的具有局部作用域的数据地址作为返回值。 可以返回堆地址,可以返回全局或静态变量的地址。,48,例: # include int * getInt(char * str ) /指针函数 int value = 20; cout str endl; return ,49,void main( ) int *pr = getInt(“input a value:”)

26、; /赋值取自返回的指针值 cout *pr endl ; /第一次输出*pr somefn(“It is uncertain.”); cout *pr endl ; /第二次输出*pr 运行结果: input a value: 20 It is uncertain. 4435500,50,含义: 每个函数都占用一段内存单元,被分配一个入口地址(起始地址),指向函数地址的指针称为函数的指针。 函数调用: 函数名( 参数表 ) 实质就是: 函数起始地址( 参数表 ),6.2.10 指向函数的指针,和数组名代表数组起始地址一样,函数名代表函数入口地址。,51,max ( int x, int y

27、) . . . main ( ) c = max ( a, b); ,c = max ( a, b);,c = 00x00501028 ( a, b);,相当于,52,函数指针声明形式 数据类型 (*函数指针名) (形参表 );,指向函数的指针,指向函数的指针 用一个指针变量存放函数的起始地址,即指向该函数。通过指针变量就可以访问所指向的函数。, 函数指针在使用之前也要进行赋值,使指针指向一个已经存在的函数代码的起始地址。 函数指针名函数名;,例:函数指针的定义为: int (*func) (char a , char b ); 注意,与指针型函数的区别: int * func(char a

28、, char b ); 定义中, func先与( )结合构成函数的声明,然后再得到其返回类型为整型指针 int *。,53,例6-11 函数指针,void print_stuff (float data_to_ignore); void print_message (float list_this_data); void print_float (float data_to_print); void (*function_pointer) (float); void main( ) float pi = 3.14159; float two_pi = 2.0 * pi;,54,print_st

29、uff(pi); function_pointer = print_stuff; function_pointer (pi); function_pointer = print_message; function_pointer (two_pi); function_pointer (13.0); function_pointer = print_float; function_pointer (pi); print_float(pi); return 0 ; ,也可以通过 (*function_pointer) (pi); 的方式调用是为了兼容C的形式。,55,void print_stuf

30、f(float data_to_ignore) cout“This is the print stuff function.n“; void print_message(float list_this_data) cout“The data to be listed is” list_this_data endl; void print_float(float data_to_print) cout“The data to be printed is” data_to_print endl ;,56,函数指针的内在差别 省略方括号 的数组名是地址,省略括号( )的函数也是地址,所以可以将省略了

31、( )的函数名作为函数地址赋给函数指针。 函数的差别 函数类型是指函数的返回类型,这里函数的差别不但是返回类型的差异,还有参数的差异,所以,函数类型的差异不能完全说明函数的差别。 例:下面的代码表示函数和函数指针操作的相互关系: int fn1(char x , char y ) ; /两个字符参数和返回整型值的函数,57,int * fn2(char x , char y ); /两个字符参数和返回整型指针的函数 int fn3(int a ) ; /一个整型参数和返回整型值的函数 int (*fp1) (char a , char b ) ; /两个字符参数和返回整型值的函数指针 int

32、(*fp2) (int s ) ; /一个整型参数和返回整型值的函数指针 fp1 = fn1 ; /ok: fn1函数与指针fp1指向的函数一致 fp1 = fn2 ; /error: fn2函数与fp1指向的函数不一致,58,fp2 = fn3 ; /ok: 函数参数与返回类型 /一致,函数名赋给函数指针 fp2 = fp1 ; /error: 两个指针指向的函数不一致 fp2 = fn3 (5); /error: 函数赋给函数指针 /时,不能加括号 函数指针与其他数据类型的指针尽管都是地址,但在类型上有很大的差别。 例:int * ip ; void (*fp) ( ) ; /函数指针 f

33、p = ip ; /error:不能相互赋值 ip = fp ; /error:不能相互赋值,59,6.2.11 指向对象的指针,1.对象指针的一般概念 声明形式,例 Point p1(5,10); Piont *ptr; ptr = 通过指针访问对象成员,类名 *对象指针名;,对象指针名 成员名,60,例: 对象指针应用举例( 例6-12),#include class Point public: Point (int xx, int yy) X = xx; Y = yy; int GetX( ) return X; int GetY( ) return Y; private: int X,

34、 Y; ;,61,void main( ) Point p1(5,10); Point *ptr; ptr= ,62,2.this指针 this 指针是一个隐含于每一个类的成员 函数中的特殊指针(包括构造函数和析构函数),它用于指向正在被成员函数操作的对象。 this 指针就明确地指出了成员函数当前 所操作的数据所属的对象。 实际过程 当通过一个对象调用成员函数时,系统先 将该对象的地址赋给this指针,然后调用成员 函数,成员函数对对象的数据成员进行操作时, 就隐含使用了this指针。 this 是一个指针变量,因此在成员函数中,可以使用*this来标识正在调用该函数的对象。,63,Poin

35、t p1 ( 3, 5 ),Point (int xx, int yy) X = xx; Y = yy; ,this X = xx; this Y = yy;,64,3.指向类的非静态成员的指针 类的成员自身也是一些变量、函数或者对象等,也可以直接将它们的地址存放到一个指针变量中,这样,就可以使指针直接指向对象的成员,进而可以通过这些指针访问对象成员。 声明指针的语句形式,类型说明符 类名:*指针名 ; 类型说明符 (类名:*指针名)(参数表);,注意:通过指向成员的指针也只能访问到公有成员。,65, 对数据成员指针赋值的一般语法形式,指针名 = &类名:数据成员名,说明: 上式只是说明了被赋

36、值的成员指针是专门 用于指向哪个数据成员的,同时在指针中存放该数据成员在类中的相对位置。 当然通过这样的指针现在并不能访问什么。 由于类是通过对象而实例化的,在声明类的对象时才会为具体的对象分配内存空间,这时只要将对象在内存中的起始地址与成员指针存放的相对偏移结合起来就可以访问到对象的数据成员了。,66, 访问数据成员的两种语法形式,对象名. *类成员指针名 或 对象指针名- *类成员指针名, 成员函数指针在声明之后要用以下形式的语句对其赋值:,指针名 = 类名:函数成员名, 利用指针调用成员函数的语句形式,(对象名. *类成员指针名)(参数表) 或 (对象指针名- *类成员指针名)(参数表)

37、,67,例6-13 访问对象的公有成员函数的不同方式,#include class Point public: Point (int xx, int yy) X = xx; Y = yy; int GetX( ) return X; int GetY( ) return Y; private: int X, Y; ;,68,void main( ) /主函数 point A(4,5) ; /声明对象A point *p1 = /使用对象名访问成员函数,69,4.指向类的静态成员的指针 类的静态成员可以用普通的指针来指向和访问。 例6-14通过指针访问类的静态数据成员 #include clas

38、s point public: point (int xx = 0, int yy = 0) /构造函数 X = xx; Y = yy; countp+; point (point ,70,stacit int countp ; /静态数据成员引用性说明 private: int X, Y; ; point:point(point /静态数据成员定义性说明,71,void main( ) /主函数实现 int *count = /直接通过指针访问静态数据成员,72,例6-15 通过指针访问类的静态函数成员 #include class point public: point (int xx =

39、 0, int yy = 0) /构造函数 X = xx; Y = yy; countp+; point (point ,73,private: int X, Y; static int countp ; /静态数据成员引用性说明 ; point:point(point /静态数据成员定义性说明 /初始化,使用类名限定,74,void main( ) /主函数实现 void(*gc)( ) = Point:GetC ; /声明一个指向函数的指针,指向类的静态成员函数 point A(4,5) ; /声明对象A cout“point A,”A.GetX( )“,” A.GetY( ) ; gc( ) ; /输出对象序号,直接通过指针访问静态成员函数 point B(A); /声明对象B cout“point B,”B.GetX( )“,” B.GetY( ) ; gc( ) ; /输出对象序号,直接通过指针访问静态成员函数 ,75,总 结 内存空间的访问方式 指针变量的声明 与地址相关的运算“*”和“&” 指针的赋值 指针运算 用指针处理数组元素 指针数组 用指针作为函数参数 指针型函数 指向函数的指针 对象指针 作业:p188p190(6-6,6-7,6-11,6-13,6-15,8-24),76,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1