C++大学基础教程.ppt_第1页
C++大学基础教程.ppt_第2页
C++大学基础教程.ppt_第3页
C++大学基础教程.ppt_第4页
C++大学基础教程.ppt_第5页
已阅读5页,还剩104页未读, 继续免费阅读

下载本文档

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

文档简介

1、C+大学基础教程,第6章 指针和引用,2020/12/18,2/98,编程风格提示,编程序的目的包括: 让程序正确运行 让别人能够看懂 代码要有注释,c+代码行数注释比为 7:3,2020/12/18,3/98,编程风格提示,尽量不用全局变量、全局数组 全局变量破坏了信息的封装性,与软件开发中的“信息隐藏”规则不符 除非,出于性能的考虑,有必要使用全局变量,2020/12/18,4/98,编程风格提示,C+规定,main函数必须要返回一个int值。 因此正确的main函数定义方式是 int main() return 0; 或者 int main(int argc, char* argv) r

2、eturn 0; 教材上的写法有问题,2020/12/18,5/98,指针概述,指针(Pointer)和引用(Reference)是C+的扩展数据类型。 指针和引用使得C+具备汇编语言的某些功能,可以访问存储器 指针和引用在概念上和使用上都有相似之处,但是也有重要的差别。,2020/12/18,6/98,第六章 指针和引用,6.1 指针的概念 6.2 指针的运算 6.3 指针和函数 6.4 指针和字符串 6.5 通过指针访问数组 6.6 指针访问动态内存 6.7 引用概念,2020/12/18,7/98,6.1.0 变量的地址属性,变量名携带着存储的位置信息即变量的地址属性。,低地址,高地址,

3、z=x的含义 根据变量x的地址属性,找到相应内存地址中存放的信息。 把这个信息赋给变量z,2020/12/18,8/98,6.1.0 变量的地址属性,取地址运算符 /定义long *型的指针pl , double *型指针pd,2020/12/18,9/98,6.1.1 指针和指针变量,指针 指针是变量或常量的地址。或者说是在内存中的一块区域的地址,这块区域存放某种类型的数据 。 例:定义了整型变量a,a的地址 就是一个指针。 也可以不定义任何变量,只是指定内存某个地址开始(如0 x00430100)的4个字节存放整型变量,这样的地址也是指针。 指针变量 存放指针的变量就是指针变量。,2020

4、/12/18,10/98,指针变量和它所指的“位置”,int* p;int a=5;p=,0 x2500,5,0 x2500,p,a,内存地址,内存地址,2020/12/18,11/98,6.1.1 指针和指针变量,当声明了一个指针变量后,确定了三件事: 变量本身在内存中所分配的地址和字节数,指针变量总是占有4个字节; 系统允许的地址范围,以及地址单元内可以存放的内容; 指针变量可以进行的运算。 对于内存单元的间接访问 访问指针变量时,只能看到指针变量的值即一个地址。然后再通过这个地址找到相应内存存放的信息。,2020/12/18,12/98,6.1.2 指针变量的声明和初始化,指针变量声明的

5、格式是: * 变量名1, * 变量名2; 例如: int *va1, *va2; char *ch1, *ch2; 或者: char* ch1; char* ch2; 指针变量在声明后,变量的值(地址)是随机的。这样的指针变量是不能安全的使用的。,2020/12/18,13/98,6.1.2 指针变量的声明和初始化,在声明指针变量时的“*”,有两个含义: 声明变量va1、va2、ch1、ch2都是指针变量; 说明变量va1和va2的类型是(int *)型,即指向整型变量的指针。va1和va2所指定的地址单元中,只能存放整型数据。类似地,ch1和ch2的类型是(char *)型,它们所指定的地址

6、单元中,只能存放字符。 指针变量都是有类型的.指针变量的类型就是它所指定的地址单元中存放的数据的类型。 定义指针时: int *p1, *p2; int* p1; int* p2; /推荐这种方式,2020/12/18,14/98,6.1.2 指针变量的声明和初始化,指针变量的初始化有两种方法:在声明时的初始化和声明后的初始化。 声明指针变量后,用赋值的方式对它们进行初始化。例如: int i1=Y, i2=A; int *pi1, *pi2; pi1=,int* pi1; 与 int *pi1; 之间只有形式上的差别 int* pi1, pi2; 定义了什么?,* 不是一种独立类型 必须附着

7、在其他类型上,2020/12/18,15/98,6.1.2 指针变量的声明和初始化,声明指针变量时就进行初始化的格式是: *指针变量名=,char ch1=Y; char *pch1; *pch1=,char *pch1= /编译器报错否?,A. *pch1=ch1; B. pch1=*ch1; C. pch1=ch1; D. pch1=,2020/12/18,16/98,未初始化指针,没有初始化指针变量是不可以使用的。 编译带有这样的指针变量的程序,编译系统会给出警告,而运行时会出现错误。 int* p;*p=12; 定义整型指针变量p之后,变量p的值是不确定的,2020/12/18,17/

8、98,第六章 指针和引用,6.1 指针的概念 6.2 指针的运算 6.3 指针和函数 6.4 指针和字符串 6.5 通过指针访问数组 6.6 指针访问动态内存 6.7 引用概念,2020/12/18,18/98,6.2 指针的运算,表6.1 指针的运算,2020/12/18,19/98,6.2.1 指针的赋值运算,指针的赋值运算一定是地址的赋值。用来对指针变量赋值的可以是: 同类型变量的地址; 同类型的已经初始化的指针变量; 其他同类型的指针。 0或者NULL(或编译时可获得0值的整型常量)。表示指针不指向任何物理地址。 编译器可检测出0值指针 不同类型的指针是不可以互相赋值的。指针赋值不存在

9、自动类型转换。,2020/12/18,20/98,例6.1 观察以下指针赋值运算的结果。如果将注释去掉,结果将如何? #include using namespace std; void main() int va1=100,*pva1; float vf1=A, *pvf1, *pvf2; int *pva2=NULL; coutvalue of pva2 is pva2endl; pva1= ,value of pva2 is 0 x00000000 0 x0012FF7C 0 x0012FF7C 0 x0012FF74 0 x0012FF74 注释去掉会出现编译错误,参见VC工程 Set

10、PointerValue,2020/12/18,21/98,6.2.2 解引用运算,解引用(de-reference)运算符“*” 一元算符,和指针变量连用 对指针所指向的内存地址单元进行间接访问。 *指针变量 例: int va=12; int* iptr= /输出结果:12,不准确: 教材 p.124 间接引用运算符,* 的用法 1. 乘法运算: a*b 2. 指针定义:int* x; 3. 解引用: cout *iptr;,2020/12/18,22/98,例6.2 对变量的直接访问和间接访问,#include using namespace std; int main() char c

11、h1=a,*ch; int k1=100;/ ascii码中编号为100的字符是d ch= ,运行结果: *ch=a ch1=B *ch=d,*ch= ?,ch1= ?,*ch= ?,2020/12/18,23/98,二重指针,int a=5; int* pa=,0 x10A8,0 x10B0,5,0 x10B0,ppa,a,内存地址,内存地址,pa,4bytes,下面的代码有没有问题? int a=5 int* ppa; *ppa= ,int* *ppa=,2020/12/18,24/98,二重指针,5,0 x10B0,ppa,a,内存地址,内存地址,4bytes,下面的代码有没有问题? i

12、nt a=5 int* ppa; *ppa= ,2020/12/18,25/98,例6.3 定义指向指针的指针变量。观察对这种指针变量间接访问的结果。 #include using namespace std; void main() int va=100,*pva,*ppva; /ppva是指向指针的指针 int k1=100; pva= /就是指针pva的内容 ,运行结果: *pva=100 *ppva=0 x0012FF7C pva=0 x0012FF7C,2020/12/18,26/98,6.2.2 间接引用运算,ppva,地址,*ppva,*ppva,整数,*pva=100 *ppv

13、a=0 x0012FF7C pva=0 x0012FF7C,2020/12/18,27/98,6.2.3 指针的算术运算,指针可以进行的算术运算只有加法和减法。 指针可以和一个整数n做加法或者减法运算。,指针p和整数n相加(相减)的含义是p所指向的位置的前方或后方第n个数据的地址。,2020/12/18,28/98,例6.4 通过指针的间接访问,输出下标为偶数的数组元素的值。 #include using namespace std; void main() int k110=11,24,37,44,58,66,79,86,93,108,*k; k= ,运行结果: K10=11 k12=37.

14、,数组第一个元素(下标为0)的地址赋值给指针k,每次循环,指针加2,?,?,k1i,2020/12/18,29/98,6.2.3 指针的算术运算,加法规则:指针和指针的直接加法是没有意义的,也是不允许的。 减法规则1:指针和指针的减法是可以进行的,其意义是求出两个指针之间可以存放几个指定类型的数据。 减法规则2:不允许用一个整数减一个指针。,int a4=1,2,3,4; int *p1=a, *p2=/正?误?,2020/12/18,30/98,6.2.4指针的关系运算和逻辑运算,=, != 相同类型的指针可以进行各种关系运算。比较两个指针相等还是不相等。 , =, = 进行指针“大于”、“

15、小于”的比较,只是要判定指针在内存中的相对位置。 惟一可以和指针比较的整数是0。 通过指针和0的比较来判定指针本身是不是空指针。 if(0=p) coutnull pointer; if(0!=p) coutregular pointer;,2020/12/18,31/98,6.2.5 void类型指针,void类型的指针就是“无类型”指针(pointer to object of unknown type)。声明的方式如下: void * ; void类型的指针变量中存放的也是内存的地址,但是不指定这个地址单元内的数据的类型。,2020/12/18,32/98,6.2.5 void类型指针的

16、使用,void类型指针的赋值运算 任何其他类型的指针都可以赋值给void指针。必须注意,这样赋值后的void指针的类型仍然是void。 void类型指针不可以直接赋值给任何其他类型的指针。 void指针都不可以通过间接引用来访问内存中的数据。 要通过void类型指针访问内存的数据,必须进行指针类型的强制转换。 int* a; void* pvoid=a; int b; b=*pvoid;,参见VC工程 PointerConvert,2020/12/18,33/98,例6.5 使用memcpy通用复制函数复制数组。 #include using namespace std; #include v

17、oid main() char src10=012345678; char dest10; char* pc=(char*)memcpy(dest,src,10); cout pc endl; int s13=1,2,3; int d13; int *pi=(int*)memcpy(d1,s1,12); cout*pi *(pi+1) *(pi+2)endl; ,运行结果: 012345678 1 2 3,复制字符数据,10个字节,做了3次类型转换,复制整型数据,12个字节,void *memcpy( void *dest, const void *src, size_t count );,2

18、020/12/18,34/98,6.2.5 void类型指针,void类型指针还有一个具体的应用:显示字符指针的内容。 除字符指针外,其他指针都可以直接用cout语句来输出地址值。 但是,用cout输出字符指针时,则是输出它所指向的字符串。可以将字符指针强制转换为void指针,再用cout语句输出,就可以看到地址值。如: char *pch=Hello C+; coutpchendl; cout(void*)pchendl;,2020/12/18,35/98,第六章 指针和引用,6.1 指针的概念 6.2 指针的运算 6.3 指针和函数 6.4 指针和字符串 6.5 通过指针访问数组 6.6

19、指针访问动态内存 6.7 引用概念,2020/12/18,36/98,6.3.1 指针作为函数的参数,用指针作为函数参数,实现地址调用,必须满足以下条件: 函数的形式参数是指针变量; 函数的实参数是内存的地址,具体来说可以是数组名、变量的地址、用变量地址初始化的指针; 形参指针类型和实参地址类型必须相同。,2020/12/18,37/98,6.3.1 指针作为函数的参数,满足以上条件后,这样的函数调用在使用上有以下的特点: 实参传递给形参的是内存的地址,所以形参指针指向实参变量; 形参指针通过间接引用,直接访问实参变量,包括改变实参变量的值; 函数调用后,可以保留对实参变量的操作结果,如果有多

20、个实参,就可以有多个实参变量在函数调用中得到修改。,2020/12/18,38/98,例6.6 编写数据交换的函数。在main中调用这个函数,交换main中定义的变量。 #include using namespace std; void Swap(int *a, int *b); void main() int x(5), y(10); cout主函数变量的值: x=x y=yendl; Swap( ,运行结果: 主函数变量的值:x=5 y=10 函数中完成了交换:*a=10 *b=5 返回后变量的值: x=10 y=5,变量的地址作为实参数,指针变量作为形式参数,2020/12/18,39

21、/98,6.3.1 指针作为函数的参数,程序中用变量x和y的地址作实参,传递给指针a和b,如图6.1(a)。通过间接引用*a和*b进行交换,实际上就是x和y进行交换,如图6.1(b)。,Swap( ,void Swap(int *a, int *b),2020/12/18,40/98,void main() int x(5), y(10); Swap( ,5,10,x,y,0 x198,0 x19C,5,10,x,y,0 x198,0 x19C,/push( push( void Move(int* a) a=a+1;/对形参进行操作 cout函数中完成了指针移动:*a=*aendl; voi

22、d main() int x5=10,20,30,40,50, int *px=x; cout调用前的*px=*pxendl; Move( px ); cout调用后的px; if(px=x) cout没有变化,*px还是*pxendl; else cout也向前移动,*px变为*pxendl; ,运行结果: 调用前的*px=10 函数中完成了指针移动:*a=20 调用后的px没有变化*px还是10,指针作为实参数,指针变量作为形式参数,参见VC工程 ChangePointer,例6.7 指针变量指向一个数组。用指针变量作为实参调用一个函数。在函数中,指针指向数组的第二个元素。观察函数返回后,

23、实参指针值有无变化。,2020/12/18,42/98,6.3.2 指针的指针作为函数的参数,重要结论: 指针变量作为被调函数的形参,是被调函数中的局部变量。局部变量的改变不影响主调函数,但作为局部变量的该指针变量的解引用的改变会影响主调函数。 如果一定要改变实参指针变量的值,可以用该指针变量的地址作实参,形式参数就是指针的指针。,2020/12/18,43/98,例6.8 修改例6.7,使得实参指针返回后,指向新的地址。 #include using namespace std; void Move(int* a) *a=*a+1; cout函数中完成了指针移动:*a=*aendl; voi

24、d main() int x5=10,20,30,40,50, *px=x; cout调用前的*px=*pxendl; Move( ,运行结果: 调用前的*px=10 函数中完成了指针移动:*a=20 调用后的px也向前移动,*px变为20,指针的地址作为实参数,指针的指针作为形式参数,参见VC工程 DoublePointer,2020/12/18,44/98,6.3.3 传递参数的保护:指针和常量,int a5=3,5,7,2,-1; int b=max(a);/max函数不应改变 a ,int max(int *x) int m = x0; for(int i=1; xi != -1; i

25、+) m = (mxi?m:xi); return m; ,=,通过数组名的地址调用,可以改变实参数组的内容。 但有时不希望数组a发生变化 使用常指针可以达到这个目的。,2020/12/18,45/98,6.3.3 传递参数的保护:指针和常量,常指针是指向常量的指针(Pointer to Constant data)的习惯说法。就是规定指针所指向的内容不可以通过指针的间接引用来改变。 常指针说明的格式是: const * ; 例如: const int* ptint; 指针ptint的类型是 (const int *),2020/12/18,46/98,例6.10 常指针示例。观察以下程序的运

26、行。 #include using namespace std; int main() int ia=10, ib=20; const int *ptint; ptint= ,运行结果: 10 120,常指针声明,注释去掉会出现编译错误,2020/12/18,47/98,6.3.3 传递参数的保护:指针和常量,指针常量(Pointer constant)。 指针本身的内容是个常量,不可以改变。 指针常量声明的格式是: *const =; 例如: char ch, *const ptch= 数组名就是数组的首地址。现在可以说:数组名就是一个指针常量。,等价于: char ch; char* co

27、nst ptch=,下面的代码是否正确? int a=1,2,3; a=a+1;,2020/12/18,48/98,例6.11 指针常量示例。指出以下程序的错误。 #include using namespace std; void main() int a=10, b=100; int* const pa= ,错误语句注释掉后运行结果: 10 20,语句有错:常量不能当左值,语句有错,地址类型不同,/指针常量的间接引用可做左值,const int * const pc=,49/98,变量、常量与常指针,const int ci=10; const int *pci=,int i=10; co

28、nst *int pi=,只是说明 pi 指向的地址中所存的内容,不能通过 *pi 的方式被改变,ci存放于常量区,不可被改变,pci指向的地址中所存的内容,不能通过 *pi 的方式被改变,const int ci=10; int* pi=,ci存放于常量区,不可被改变,也不能通过指向ci的指针改变ci,因此指向ci的指针必须是常指针,参见 ISO C+标准2003版 8.3.1节,2020/12/18,50/98,例6.12 用常指针作形参 #include using namespace std; void printString( char* const Ptarray ) while(

29、*Ptarray) cout *Ptarray+; void main() char phrase = “Aloha, everyone!; printString( phrase ); cout endl; ,不使用常指针也是可以完成打印。但是没有保护了。,参见VC工程 PrintString,cin *Ptarray+;,const char* Ptarray,2020/12/18,51/98,*常量指针和指针常量,常量指针(Pointer to Constant) 指向常量的指针 或者 指针所指的那块内存是变量,但不能通过指针解引用改变 指针常量(Pointer Constant) 指针

30、本身是常量 指针在初始化之后是不能改变的,int a=5, b=9; const int* pa= (*pa)和(pb)都不能被改变,*pa,2020/12/18,52/98,6.3.4 指针函数,如果一个函数的返回值是指针,则这样的函数称为指针函数。如: int* func01(int k); 函数func01返回一个指向整型数据的指针。 注意:不能返回函数中局部变量的地址。,2020/12/18,53/98,例6.13 返回不同地址的指针函数。观察运行的结果。 #include using namespace std ; int va=100;/全局变量 int* get_int(int*

31、 pt, int j) /指针函数 int value=300; int* pti=pt;/pti是一个局部变量 if(j=0 | j=1) return pti; /返回局部变量的值 else if(j=2) return pti= ,运行结果 i=0 *ptint=100 i=1 *ptint=200 i=2 *ptint=-858993460,返回形参指针的值,返回函数局部变量的地址,参见VC工程 PointerFunction,2020/12/18,54/98,第六章 指针和引用,6.1 指针的概念 6.2 指针的运算 6.3 指针和函数 6.4 指针和字符串 6.5 通过指针访问数组

32、 6.6 指针访问动态内存 6.7 引用概念,2020/12/18,55/98,6.4.1 字符串处理的两种方式,C+字符串常量是用双引号括起的字符序列,并以字符0作为结束标志。如 This is a string。 字符串常量存放在内存的某个区域,有自己固定的首地址。 如果将字符串常量的首地址看成是指针,这种指针既是常指针,也是指针常量。,2020/12/18,56/98,6.4.1 字符串处理的两种方式,C+处理字符串有两种方式:数组方式和指针方式。 数组方式是将字符串存入字符数组后,再进行处理。一般可以在声明数组的时候用字符串来初始化: char string_array=Whats a

33、 nice day!; 指针方式是用字符串常量来初始化一个字符指针: char *string_pt=Whats a nice day!;,存放位置: 常量区:Whats a nice day! 栈区:string_array19 栈区:string_ptr,2020/12/18,57/98,; Listing generated by Microsoft (R) Optimizing Compiler Version 14.00.50727.42 TITLEd:MyDocumentTeachingClassesCPP.GenericExampleCH06TestTest.cpp .686P

34、.XMM include listing.inc .modelflat INCLUDELIB OLDNAMES,2020/12/18,58/98,EXTRN_security_check_cookie4:PROC $SG-66DBThis is str_arr, 00H $SG-67DBThis is pstr, 00H PUBLIC_$ArrayPad$ PUBLIC_main EXTRN_security_cookie:DWORD ; Function compile flags: /Odtp ; File d:mydocumentteachingclassescpp.genericexa

35、mplech06testtest.cpp _TEXTSEGMENT _str_arr$ = -24; size = 16 _$ArrayPad$ = -8; size = 4 _pstr$ = -4; size = 4,2020/12/18,59/98,_mainPROC ; 4 : pushebp movebp, esp subesp, 24; 00000018H moveax, DWORD PTR _security_cookie xoreax, ebp movDWORD PTR _$ArrayPad$ebp, eax ; 5 : char str_arr=This is str_arr;

36、 moveax, DWORD PTR $SG-66 movDWORD PTR _str_arr$ebp, eax movecx, DWORD PTR $SG-66+4 movDWORD PTR _str_arr$ebp+4, ecx movedx, DWORD PTR $SG-66+8 movDWORD PTR _str_arr$ebp+8, edx moveax, DWORD PTR $SG-66+12 movDWORD PTR _str_arr$ebp+12, eax,2020/12/18,60/98,; 6 : char *pstr=This is pstr; movDWORD PTR

37、_pstr$ebp, OFFSET $SG-67 ; 7 : return 0; xoreax, eax ; 8 : movecx, DWORD PTR _$ArrayPad$ebp xorecx, ebp call_security_check_cookie4 movesp, ebp popebp ret0 _mainENDP _TEXTENDS END,2020/12/18,61/98,6.4.1 字符串处理的两种方式,常量不能放在等式左边,运行时会出错,2020/12/18,62/98,6.4.2 字符串操作函数,调用这些函数时,原则上可以使用字符数组名、已经初始化的字符指针作为实参数。

38、字符串常量还可以作为源字符串的实参数。 目的串必须是可写的。,2020/12/18,63/98,例6.14 strcpy和strncpy的比较。 #include #include using namespace std; void main(void) int n; char* array1 = Happy Birthday to You; char array2 25 ; char array3 15 ; strcpy( array2, array1 ); cout The string in array1 is: array1 nThe string in array2 is: arra

39、y2 n; /*strcpy(array3,array1); coutarray3endl; */ n=sizeof(array3); strncpy( array3, array1, n-1 ); / 复制array1的n-1个字符到array3 array3 14 = 0; / 添加0 到array3 cout The string in array3 is: array3 endl; ,不包括提示的运行结果 Happy Birthday to You Happy Birthday to You Happy Birthday,复制array1到array2,没有问题,复制array1到ar

40、ray3,空间不够,有运行错误,按实际数组大小,复制array1到array3,没有问题,2020/12/18,64/98,第六章 指针和引用,6.1 指针的概念 6.2 指针的运算 6.3 指针和函数 6.4 指针和字符串 6.5 通过指针访问数组 6.6 指针访问动态内存 6.7 引用概念,2020/12/18,65/98,6.5 通过指针访问数组,指针和数组有天然的联系。因为数组名本身就是地址,也就是某种类型的指针。将指针和数组名联系起来,访问数组就多了一种方法。 虽然一维数组名和二维数组名都是地址,都可以看作是某种指针,但是指针的类型是不同的。因此,通过指针访问一维数组和二维数组的方法

41、是不同的。,2020/12/18,66/98,6.5.1 通过指针访问一维数组,要通过指针访问一维数组,必须首先声明一个和数组类型相同的指针,并且用数组名来对指针初始化,如: int A10, *pa=A; 然后,就可以用多种方式访问数组元素: 数组名和下标,如A0、A4; 指针和下标,如pa0、pa4; 指针加偏移量的间接引用,如*(pa+4); 数组名加偏移量的间接引用,如*(A+4); 指针自加后的间接引用,如*pa+。,2020/12/18,67/98,char ChArray=This is a string.; ChArray就是数组的首地址,值是0 x4000; ChArray0

42、是数组第一个元素, int* p1 = v ; / pointer to initial element (implicit conversion) int* p2 = / pointer to one beyond last element,2020/12/18,69/98,17,.,例6.15 求数组内所存放的字符串的长度。 #include using namespace std; void main(void) char ChArray=This is a string., *ptch; int i,j,k,offset1,offset2; ptch=ChArray;/指针初始化 fo

43、r(i=0; ChArrayi!=0; i+);/找到0字符 cout The length of the string is: iendl; for(j=0; ptchj!=0; j+); cout The length of the string is:“ jendl; for(offset1=0; *(ChArray+offset1)!=0; offset1+); cout The length of the string is:“ offset1endl; for(offset2=0; *(ptch+offset2)!=0; offset2+); cout The length of

44、the string is:“ offset2endl; for(k=0; *ptch+!=0; k+); cout The length of the string is:“ kendl; ,运行结果 都相同,T,h,i,s,i,s,a,s,t,r,i,n,g,0,方式1:数组名和下标,方式2:指针和下标,方式3: 数组名加偏移量的间接引用,方式4:指针加偏移量的间接引用,方式5:指针自加的间接引用,0,2020/12/18,70/98,例6.16 求整型数组的平均值,显示数组元素和平均值。 #include using namespace std; void main() int intA

45、rray10=8,11,23,34,45,56,65,78,86,97, *ptint; int i, num, sum; float average; ptint=intArray; num=sizeof(intArray)/sizeof(*intArray); for(sum=0, i=0; inum; i+) sum += *ptint+ ; average=(float)sum/num; coutn平均值是:averageendl; ,平均值是:50.3,指针初始化,求数组元素的数目,求平均值,?,2020/12/18,71/98,6.5.2 通过指针访问二维数组,二维数组可以看成是一

46、维数组的一维数组。二维数组名虽然也是地址(指针),但是却和一维数组名有不同的类型。 对一维数组A5,数组名A的地址,就是数组第一个元素A0的地址。指针的类型是指向数组元素的指针。A+1就是元素A1的地址。,2020/12/18,72/98,6.5.2 通过指针访问二维数组,对二维数组B34,数组名B的地址,是其中第一个一维数组B0的地址。指针的类型是指向一维数组的指针。B+1就是下一个一维数组B1的地址。如图6.3所示。,2020/12/18,73/98,6.5.2 通过指针访问二维数组,在定义指向一维数组的指针时,还必须指出一维数组的大小。 声明指向一维数组的指针的格式如下: (*指针变量名

47、)一维数组大小; 例如,下图中两个二维数组所对应的指向一维数组的指针定义如下: char (*ptchb)4, (*ptchc)2; ptchb=B; ptchc=C;,2020/12/18,74/98,6.5.2 通过指针访问二维数组,对于指向一维数组的指针,具有以下的特征: 二维数组名是指向一维数组的指针,而不是指向数组元素的指针。 指向一维数组指针加1 的结果,是指向下一个一维数组的指针。 指向一维数组的指针的间接引用的结果仍然是地址,即*ptchb仍然是地址。只是地址的类型变了。变为一维数组B0第一个元素B00的地址。 因为*ptchb是数组元素的地址,*ptchb就是数组元素的值。用

48、指向一维数组指针访问二维数组第i行第j列元素的一般公式是*(*(指针名+i)+j)。,2020/12/18,75/98,例6.17 比较指向一维数组的指针和指向数组元素的指针。 #include using namespace std; void main() short B34, C32; short (*ptshb)4, (*ptshc)2; ptshb=B; ptshc=C; cout比较不同的指向一维数组指针的差别n; coutptshb的地址是: ptshbn; coutptchb+1的地址是:ptshb+1n; coutptchc的地址是: ptshcn; coutptchc+1的

49、地址是:ptshc+1n;,比较不同的指向一维数组指针的差别 ptshb的地址是: 0 x0012FF68 ptshb+1的地址是:0 x0012FF70 ptchc的地址是: 0 x0012FF5C ptchc+1的地址是:0 x0012FF60,B的第0行地址,B的第1行地址,C的第0行地址,C的第1行地址,参见VC工程 Pointer2Array,2020/12/18,76/98,例6.17 比较指向一维数组的指针和指向数组元素的指针。 cout不同类型的指针n; coutptshb的地址是: ptshbendl; cout*ptshb的地址是: *ptshbendl; cout*pts

50、hb+1的地址是: *ptshb+1endl; coutB01的地址是: ,不同类型的指针 ptshb的地址是: 0 x0012FF68 *ptshb的地址是: 0 x0012FF68 *ptshb+1的地址是: 0 x0012FF6A B01的地址是: 0 x0012FF6A *ptshb+1和 void main(void) int dArray34=32,42,12,25,56,76,46,53,76,89,96,82, (*pt)4; int sum, j; float average; sum=0; pt=dArray; j=sizeof (dArray)/sizeof (*dArr

51、ay); for(int i=0;ij;i+) sum=sum+*(*pt+i); average=(float)sum/j; cout数据的平均值等于:averageendl; ,运行结果: 数据的平均值等于57.0833,指向一维数组指针的初始化,求数组元素的数目,*dArray就是元素dArray00,数组求和,求平均值,输出平均值,2020/12/18,78/98,6.5.3 指针数组,若数组元素是某种类型的指针,这样的数组称为指针数组。 指针数组声明的格式如下: *常量表达式; 例如:char* member_name10; 注意差别:指向一维数组指针: char (*member_

52、pointer)10;,2020/12/18,79/98,6.5.3 指针数组,很晕? 指向字符的指针的数组: char* member_name = Merry, John, Hill; 指向这样的指针数组的指针: char* arr = member_name; 或者: char* arr; arr=member_name; 这样定义后,*arr就是指向字符串的指针 cout*arrendl; 将显示数组中的第一个字符串Merry。,one little fat white worm with two antennae,doube(*)() (*pa)9;,int a5; /a是一个数组,

53、数组的每个元素是整数,2020/12/18,80/98,例6.19 将若干字符串存入指针数组,并以NULL表示结束。将这些字符串按升序排序,输出排序后的字符串。 #include #include using namespace std; void Print(char* ); void String_sort(char* ); void main(void) char* pn=George,Bill,Wendy,Abraham,Bruce,NULL; /字符指针数组,或者根据该数组特点称之为“字符串数组” String_sort(pn); Print(pn); ,函数原型,函数原型,指针数组

54、,排序,输出排序后的结果,2020/12/18,81/98,void String_sort(char* arr) char *p1, *p2, *p3; p1=arr; p2=arr+1; while( *(p1+1) != NULL ) while( *p2 != NULL) if( strcmp(*p1,*p2)0 ) p3=*p1; *p1=*p2; *p2=p3; /end if p2+; /end while(*p2 p1+; p2=p1+1; /end while(*(p1+1) /end void String_sort void Print(char* arr) coutSo

55、rted strings are:endl; while(*arr != NULL) cout *arr+ endl; ,Sorted strings are: Abraham Bill Bruce George Wendy,逐次取出每个指针,和其余的每个指针所指的字符串比较,如果字符串*p1大于*p2,交换地址,重新设置p2,参见VC工程 StringSort,2020/12/18,82/98,指针数组char* pn所指的内容,2020/12/18,83/98,数组char* pn的地址以及元素值,2020/12/18,84/98,char* pn=George,Bill,Wendy,Ab

56、raham,Bruce,NULL;,0 x004176FC,0 x00417704,0 x00417710,0 x00417718,0 x00417720,char* pn,2020/12/18,85/98,排序后的char* pn,0 x004176FC,0 x00417704,0 x00417710,0 x00417718,0 x00417720,char* pn,2020/12/18,86/98,6.5.4 命令行参数,命令行参数的示例: 命令行参数是main函数的参数。带有命令行参数的main函数的原型是: main(int argc, char* argv); argc:整数,存放命

57、令行参数的数目。 argv:指针数组,存放所输入的命令行参数。argvargc中自动的存入NULL,表示输入结束。 argv 这个数组有 argc+1个元素,argv0 argvargc-1都是字符串,2020/12/18,87/98,例6.20 显示命令行参数的程序,#include using namespace std; void main( int argc, char* argv ) cout The command line arguments are:n; for ( int i = 0; i argc; +i ) cout argv i ; ,DispCmdParam.exe

58、para1 para2 para3 The command line arguments are: DispCmdParam.exe para1 para2 para3,参见VC工程 DispCmdParam,2020/12/18,88/98,例6.21 对命令行输入的字符串进行排序并输出排序结果。 #include #include #include using namespace std; void Print(char* ); void String_sort(char* ); void main(int argc, char *argv) String_sort(argv+1); Print(argv+1); getche(); ,如在命令行输入: E:myfileproj01debugproj01.exe bcd abc aab bbd 回车后运行并显示: Sorted st

温馨提示

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

评论

0/150

提交评论