六章数组、指针与字符串课件_第1页
六章数组、指针与字符串课件_第2页
六章数组、指针与字符串课件_第3页
六章数组、指针与字符串课件_第4页
六章数组、指针与字符串课件_第5页
已阅读5页,还剩71页未读 继续免费阅读

下载本文档

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

文档简介

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

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

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

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

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

6、类型的变量的地址。特殊的 void 类型的指针,可以存放任何类型的变量的地址。经过类型强制转换,void 类型的指针可以访问任何类型的数据。指针变量的定义与应用void *p1;int i, *p2;p1 = & i;p2 = ( int * ) p1;可以访问任何类型的数据指针忘了赋值比整型变量忘了赋值危险得多。例: int count; int *iPtr ; *iPtr = 58; iPtr当前指向什么地方?该代码能通过编译,但没有赋初值的指针iPtr是一个随机地址。“*iPtr = 58;”是把58赋到内存中的随机位置,因此很可能已经破坏了另一变量,甚至修改了栈中的函数返回地址,计算机

7、将死机或进入死循环。指针没有赋值这样非常危险12指针变量的引用“ * ”是指针运算符,表示指针所指向的变量。 指针变量的定义与应用int i , *p;p = &i; pi* p23&i i = 2; /* 通过变量名直接访问 */*p = 3; /* *p是 p 所指向的变量,即变量 i ,这是通过指针的间接访问*/ p 是指针变量,* p 就是 p 所指向的变量 i , 即 *p 等价于 变量 i 。13指针变量的引用指针变量的定义与应用注意:“ * ”出现在声明语句中和执行语句中含义不同。1、“ * ”出现在声明语句中,表示声明的变量是指针变量。 例如: int *p;2、 “ * ”出

8、现在执行语句中,表示访问指针所指向的变量。 例如: *p = 3; printf ( “%d n”, *p );例:int i= 26 ; int *P = &i ; /初始化为整型地址 *P = &i ; /error 不能将“int *P = &i ; ”与“*P = &i ; ”混淆。前者是定义语句,*是指针定义符,C+为P指针分配一个指针空间,并用i 的地址值初始化,后者是执行语句,左右两边类型不匹配。*操作符在指针上的两种用途要区分开:定义或声明时,建立一个指针;执行时,间接引用一指针。也要注意: ”&”出现在声明语句中和执行语句中其含义是不同的;例:int i , *p; int

9、&rf = i; /表示声明的是引用 p = &i; /取地址14例6-6 指针的声明、赋值与使用#includevoid main( )int *i_pointer;/声明int型指针i_pointerint i; /声明int型数ii_pointer=&i; /取i的地址赋给i_pointeri=10; /int型数赋初值cout“Output int i=”iendl; /输出int型 /数的值coutOutput int pointer i=*i_pointerendl; /输出int型指针所指地址的内容15指针变量的地址指针也是变量,是变量就具有内存地址。所以指针也有地址。例:下面的

10、程序输出iCount变量值,以及iPtr和iCount的地址值: # include int iCount = 18 ; int * iPtr = &iCount ; * iPtr = 58 ; cout iCount endl ; cout iPrt endl ;16 cout &iCount endl ; /与iPtr值相同 cout *iPtr endl ; /与 iCount值相同 cout &iPtr endl ; /指针本身的地址 运行结果:58 0 x0067fe00 0 x0067fe00 58 0 x0067fdfciPtr0067:FDFC0067:FE00iCount00

11、67:FE005817指针与整型数的区别指针在使用中必须类型匹配。例:int iCount = 26 ; int * iPtr = &iCount ; /定义语句:*在此 /处作定义指针变量用,而非间接引用。 * iPtr = &iCount ; /error:不能将整型地 /址转换成整型数 * iPtr = 50 ; /执行语句:*在此处作间接引用 指针值不是整型数赋值语句“* iPtr = &iCount ; ”在BC中会引起类型转换的错误。 (cannot convert int* to int)强制转换是合法。 例:允许语句“* iPtr = (int)&iCount ;” 但要注意其

12、赋值的意义。该语句表示将变量iCount的地址值作为一个整型数赋给变量* iPtr ,即iCount变量。18指针与常量(const指针) 指向常量的指针 int a = 1; int * pi ; pi = &a ; * pi = 58 ; 可以看到,一个指针涉及到两个变量,指针本身pi 和指向的变量a 。修改这两个变量的对应操作为“pi = &a ;”和“* pi = 58 ;”。如果不想通过指针间接改变a的值, 可以声明指向常量的指针。不能通过指针来改变所指对象的值,但指针本身可以改变,可以指向另外的对象。在指针定义语句的类型前加const,表示指向的对象是常量。例: int n1=3;

13、int const n2 = 5;const int *pn = &n1; pn=&n2; /正确*pn=6; /错误19指针与常量 指针常量若声明指针常量,则指针本身的值不能被改变。 在指针定义语句的指针名前加const,表示指针本身是常量。例1:int n1 = 3;int const n2 = 5;int *const pn= &n1; pn = &n2; /错误*pn = 6; /正确常量pn0067:FDA60067:F000Data区0067:F00020void类型指针 一般情况下,指针的值只能赋给相同类型的指针。但是有一种特殊的void类型指针,可以存储任何类型的对象地址。例:

14、 void类型指针的使用 void vobject ; /error,不能声明void类型的变量 void * pv ; / ok ,可以声明void类型的指针 int * pint ; int i ; void main( ) / void类型的函数没有返回值 pv = &i ; /void类型指针指向整型变量 pint = (int *)pv ; / 类型强制转换 /void类型指针赋值给整型指针21指针与常量 指向常量的指针常量可以定义一个指向常量的指针常量,它必须在定义时进行初始化。const int ci = 7 ;int ai ;const int * const cpc = &c

15、i ; /指向常量的指针常量const int * const cpi = &ai ; /ok cpi = &ci ; / error:指针值不能修改 *cpi = 39 ; / error:不能修改所指向的对象 ai = 39 ; /ok常量cpc0067:FD660067:F600常量ci0067:F6007226.2.5指针变量的运算指针与整数的加减运算 指针 p 加上或减去 n ,其意义是指针当前指向位置的前方或后方第 n 个数据的地址。 这种运算的结果值取决于指针指向的数据类型。指针加一,减一运算 指向下一个或前一个数据的地址。 例如: y = *px+ y = *(px+) ( *

16、 和 + 优先级相同,自右向左运算)23papa-2pa-1pa+1pa+2pa+3*(pa-2)*pa*(pa+1)*(pa+2)*(pa+3)*(pa-1)int *pa24long *pbpb-1pbpb+1pb+2*(pb-1)*pb*(pb+1)*(pb+2)25关系运算指向相同类型数据的指针之间可以进行各种关系运算。指向不同数据类型的指针,以及指针与一般整数变量之间的关系运算是无意义的。指针可以和零之间进行等于或不等于的关系运算。例如:p = 0 或 p! = 0赋值运算向指针变量赋的值必须是地址常量或地址变量,不能是普通整数。但可以赋值为 整数0,表示 空指针。指针变量的关系运算

17、例:int *p ; /声明一个int型指针p p = 0 ; /将p设置为空指针,不指向任何地址266.2.6指向数组元素的指针声明与赋值例: int a10, *p; p = &a0; 或 p = a;通过指针引用数组元素经过上述声明及赋值后: *p 就是a0,*(p+1) 就是a1,. , *(p+i) 就是 ai 。 a i , *(p+i), *(a+i), p i 都是等效的。不能写 a+因为 a 是数组首地址是常量。 27例设有一个int型数组a,有10个元素。用三种方法输出各元素:使用数组名和下标使用数组名和指针运算使用指针变量 指 针28main( ) int a10; in

18、t i; for(i=0; iai; coutendl; for(i=0; i10; i+) coutai; 使用数组名和下标29main( ) int a10; int i; for(i=0; iai; coutendl; for(i=0; i10; i+) cout*(a+i); 使用数组名和指针运算30 使用指针变量main( ) int a10; int *p,i; for(i=0; iai; coutendl; for( p = a; p (a+10); p+) cout*p;app316.2.7 指针数组数组的元素是指针变量声明一维指针数组的语法形式 指 针由 p_i0, p_i1

19、 两个指针组成类型名T*数组名下标表达式;例: int *p_i 2 ;32例6-9 利用指针数组输出单位矩阵void main( )int line1 =1,0,0; /声明数组,矩阵的第一行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 100&line10&line20&line30 P_line0P_line1P_lin

20、e2int line1 =1,0,0; int line2 =0,1,0;int line3 =0,0,1;33/输出单位矩阵 coutMatrix test:endl;for(int i=0;i3;i+) /对指针数组元素循环 for(int j=0;j3;j+) /对矩阵每一行循环 cout p_line i j ; coutendl;输出结果为:Matrix test:1,0,00,1,00,0,1P_linei表示什么? line1P_linei line2 line334100010001line20 x0012FF740 x0012FF680 x0012FF5Cp_line0p_l

21、ine1p_line2line10 x0012FF680 x0012FF74line30 x0012FF5C35for(int i=0;i3;i+) for(int j=0;j3;j+) cout *( p_line i + j ) ; coutendl;输出结果为:Matrix test:1,0,00,1,00,0,1(p_linei+j)表示指向第i行第j 个元素*(p_linei+j)表示(p_linei+j)指针所指的变量p_lineij1.一维数组 int i ; int *p; int a10; p = &i; 因为: a = &a0 所以: p = a; p = &a0;效果都一

22、样a0a36for(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;37二维数组的指针int a 33= 1, 2, 3, 4, 5, 6, 7, 8, 9 a 0 a 1 a 2 123456789a33a 0 a 0 0 a 0 1 a 0 2 a 1 a 1 0 a 1 1 a 1 2 a 2 a 2 0 a 2 1 a 2 2 可以理解为一维指针数组int * a3每一行相当于一个具有3个元素的一维int型数组一维数组的情况 int *p;

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

24、for(int j=0;j3;j+) cout *(*( array2 + i ) + j) “ ”; coutendl;指向i行,相当于array2i,即第i行的数组名。指向第i行的第j个元素是array2数组的第i 行j列元素array2ij。39在某次运行之后,程序的输出结果为:0X0065FDE011,12,130X0065FDEC21,22,23for(int j=0;j3;j+) cout *(*( array2 + i ) + j) ; for(int j=0;j3;j+) cout *( a i + j) ; 406.2.8 以指针作为函数参数 指针变量作为形参在函数调用时将实

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

26、:题目:读入三个浮点数,将整数部分和小数部分分别输出#include void splitfloat ( float x, int *intpart, float *fracpart ) /形参 intpart、 fracpart是指针变量 *intpart = int(x); / 取x的整数部分 *fracpart = x - *intpart; /取x的小数部分 42void main(void)int i, n;float x, f; for (i = 0; i x; splitfloat ( x, &n, &f); /变量地址做实参splitfloat ( x, &n, &f);nf0

27、 x0012FF780 x0012FF70intpartfracpart0 x0012FF780 x0012FF70void splitfloat ( float x, int *intpart, float *fracpart )43例: 实参为数组名, 形参为数组名或指针变量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

28、_2, 10) ;44/ 形参是数组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;45/形参是指针变量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

29、eturn aver;466.2.9指针型函数 返回指针的函数称为指针函数 指针函数不能把在它内部说明的具有局部作用域的数据地址作为返回值。 指针函数的一般定义形式数据类型*函数名(参数表)函数体指针函数不能把在它内部说明的具有局部作用域的数据地址作为返回值。可以返回堆地址,可以返回全局或静态变量的地址。47例:# include int * getInt(char * str ) /指针函数 int value = 20; cout str endl; return &value ; /warning:将局部变量的地址返回是不妥的Void somefn(char * str) int a =

30、 40; cout str endl ;48void main( ) int *pr = getInt(“input a value:”); /赋值取自返回的指针值cout *pr endl ; /第一次输出*pr somefn(“It is uncertain.”); cout *pr endl ; /第二次输出*pr 运行结果: input a value: 20 It is uncertain. 443550049含义:每个函数都占用一段内存单元,被分配一个入口地址(起始地址),指向函数地址的指针称为函数的指针。 函数调用: 函数名( 参数表 ) 实质就是: 函数起始地址( 参数表 )6

31、.2.10 指向函数的指针 和数组名代表数组起始地址一样,函数名代表函数入口地址。50max ( int x, int y ) . . . main ( ) c = max ( a, b);c = max ( a, b);c = 00 x00501028 ( a, b);相当于指令2max00 x00501028指令1指令2指令1max函数main函数00 x00501015main51函数指针声明形式 数据类型 (*函数指针名) (形参表 );指向函数的指针指向函数的指针用一个指针变量存放函数的起始地址,即指向该函数。通过指针变量就可以访问所指向的函数。函数指针在使用之前也要进行赋值,使指针

32、指向一个已经存在的函数代码的起始地址。 函数指针名函数名;例:函数指针的定义为: int (*func) (char a , char b );注意,与指针型函数的区别: int * func(char a , char b ); 定义中, func先与( )结合构成函数的声明,然后再得到其返回类型为整型指针 int *。52例6-11 函数指针void print_stuff (float data_to_ignore);void print_message (float list_this_data);void print_float (float data_to_print);void

33、(*function_pointer) (float);void main( ) float pi = 3.14159; float two_pi = 2.0 * pi;53 print_stuff(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);

34、 print_float(pi); return 0 ;也可以通过(*function_pointer) (pi); 的方式调用是为了兼容C的形式。54void print_stuff(float data_to_ignore) coutThis 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) coutThe data to

35、 be printed is” data_to_print 成员名59例: 对象指针应用举例( 例6-12)#includeclass Point public: Point (int xx, int yy) X = xx; Y = yy; int GetX( ) return X; int GetY( ) return Y; private: int X, Y; ; 60void main( ) Point p1(5,10); Point *ptr; ptr=&p1;cout GetX ( ) endl;cout p1.GetX ( ) GetX ( )ptrX = 15;612.this指

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

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

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

39、lass Point public: Point (int xx, int yy) X = xx; Y = yy; int GetX( ) return X; int GetY( ) return Y; private: int X, Y; 67void main( ) /主函数 point A(4,5) ; /声明对象A point *p1 = &A ; /声明对象指针并初始化 int(point:*p_GetX)( ) = point:GetX; /声明成员函数指针并初始化 cout(A.*p_GetX)( ) endl; /使用成员函数指针访问成员函数 coutGetX)( ) endl; /使用对象指针访问成员函数 cout A. GetX( ) endl; /使用对象名访问成员函数684.指向类的静态成员的指针类的静态成员可以用普通的指针来指向和访问。例6-14通过指针访问类的静态数据成员#includeclass point public: point (int xx =

温馨提示

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

评论

0/150

提交评论