第六章 指针、引用和动态空间管理

124
第第第 第第 第第第第第第第第第 6.1 第第第第第 6.1.1 第第第第第 6.1.2 第第第第第第第第第第第 1 第第第第第第第第第第第第 第第第第第第第 .。 * 第第int* // 第第第第 char* // 第第第第 double*//double 第第第

description

第六章 指针、引用和动态空间管理. 6.1 指针的概念  6.1.1 指针的概念 6.1.2 指针变量的定义和初始化 1 .指针表示内存空间的地址。指针类型定义以*标识。  例: int* // 整型指针  char* // 字符指针  double*//double 型指针 . 第六章 指针、引用和动态空间管理. 2 .指针变量定义  例: int* ip; char* cptr; int* iptr1,*iptr2;. 第六章 指针、引用和动态空间管理. 3 .建立指针  (1) 建立指针包含指针变量定义和给指针赋初值 ( 地址 ) 。  - PowerPoint PPT Presentation

Transcript of 第六章 指针、引用和动态空间管理

Page 1: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理 6.1 指针的概念  6.1.1 指针的概念 6.1.2 指针变量的定义和初始化1 .指针表示内存空间的地址。指针类型定义以

* 标识。 例: int* // 整型指针    char* // 字符指针    double*//double 型指针  

Page 2: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

2 .指针变量定义 例: int* ip;     char* cptr;     int* iptr1,*iptr2;

 

Page 3: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

3 .建立指针 (1) 建立指针包含指针变量定义和给指针赋

初值 ( 地址 ) 。 (2)& 操作符可取变量地址,指针变量用于

存放地址。  

Page 4: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: int* iptr;     int icount=18;     iptr=&icount;// 指针赋值 

  该例等价与 

Page 5: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: int icount=18;     int* iptr=&icount;// 指针的初始化  

内存表示:   

Page 6: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

4 .间接引用指针 

 操作符 * 可取指针变量所指单元内容,称为间接引用指针。 

Page 7: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: #include<iostream.h>   void main()   {   int * iptr;   int icount=18;   iptr=&icount;   cout<<*iptr<<endl;   *iptr=58;   cout<<*iptr<<endl;   }  结果: 18      58  

Page 8: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理 

5 .指针变量地址:指针变量也具有内存地址。 例: #include<iostream.h>     void main()     {      int icount=18;      int* iptr=&icount;      *iptr=58;      cout<<icount<<endl;      cout<<iptr<<endl;      cout<<&icount<<endl;      cout<<*iptr<<endl;      cout<<&iptr<<endl;     }  

Page 9: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

结果: 58      0x0067fe00      0x0067fe00      58      0x0067fefc  内存表示:

Page 10: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: int icount=58;     int* iptr=&icount;    则    icount // 整型变量    iptr // 指针变量    &icount // 整型变量 icount 地址   

Page 11: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

   &iptr // 指针变量 iptr 地址    *icount // 错误    *iptr // 指针变量 iptr 所指单元内容 

6 . *( 取内容 ) 和 &( 取地址 ) 为互逆操作。 

 

Page 12: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.1.3 const 指针 

1 .指向常量的指针:在指针定义语句的类型前加 const ,表示指针指向的数据为常量。 

Page 13: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: const int a=78;     const int b=28;    int c=18;    const int * pi=&a; //int const * pi=&a;     *pi=58; // 错误, *pi 为常量     pi=&b;     *pi=68; // 错误, *pi 为常量 

Page 14: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

pi=&c;   *pi=88; // 错误, *pi 为常量  c=98;   结论: const int * pi=&a;( 或 int const * pi

=&a;) 中, *pi 为常量, pi 为变量,故 *pi 不能为左值。 

Page 15: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

2 .指针常量:在指针定义语句的指针名前加 const ,表指针本身为常量。 

Page 16: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: char * const pc="asdf";     pc=“dfgh”;// 错误, pc 为常量   *pc='b';     *(pc+1)='c';    *pc++=‘y’; // 错误, pc 为常量   结论: int * const pi=&a; 中, *pi 为变量, pi 为常

量,故 pi 不能为左值。  

Page 17: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

3 .指向常量的指针常量  

 结论: const int * const pi=&a; 中, *pi 、pi 均为常量,故均不能作为左值。 

Page 18: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: const int ci=7;     int ai;    const int * const cpc=&ci;     const int * const cpc=&ai;     cpi=&ai; // 错误, cpi 为常量    *cpi=39; // 错误, *cpi 为常量    ai=39;   

Page 19: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.2 指针运算6.2.1 赋值 (=) 同类型指针之间可相互赋值。 任何类型的指针可赋值给 void 指针,反

之不行。例: char c=‘x’,*s=&c;

void * p1,* p2=Null;

p1=s;// 对 s=p2;// 错

Page 20: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.2.2 取地址 (&) 单目运算符 & 可取变量的地址。例: int k,*p;

p=&k;

k

p

Page 21: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.2.3 取内容 (*) 单目运算符 * 可取指针所指的内存单元内容。例: int *pd,d;

pd=&d;

*pd=99;

cout<<*pd<<‘ ‘<<endl;

99

d

pd

Page 22: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.2.4 判断一指针是否为空指针 (== 或 !=) 。例:如果 p 是空指针,则… if(p==0)… if(p==Null)… if(!p)…例:如果 p 不是空指针,则… if(p!=0)… if(p!=Null)… if(p)…

Page 23: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理6.2.5 计算两地址间数据单元的个数 (-) 。 计算两地址间存储单元的个数。 一般将高地址指针作被减数,且其数据

不计算在内。例: int n,m[12],*p1=&m[5],*p2=&m[10];

n=p2-p1;//n==5

低地址 高地址p1 p2

Page 24: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.2.6 指针移动1. 移动 n 个单位:操作符 + 、 - 、 += 和

-= 。指针向后 ( 高地址 ) 移动 n 个单位:指针

表达式 +n 或指针表达式 +=n 。指针向前 ( 低地址 ) 移动 n 个单位:指针

表达式 -n 或指针表达式 -=n 。例:见书。

Page 25: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

2. 移动 1 个单位:操作符 ++( 前增 1) 、 ++( 后增 1) -- ( 前减 1) 和 -- ( 后减 1) 。

指针向后 ( 高地址 ) 移动 1 个单位:指针变量 ++ 或 ++ 指针变量。

指针向前 ( 低地址 ) 移动 1 个单位:指针变量 -- 或 -- 指针变量。

Page 26: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: int k,*pk=&k; cout<<endl<<++pk; cout<<endl<<pk;结果是两个相同的地址。

例: int k,*pk=&k; cout<<endl<<pk++; cout<<endl<<pk;结果是两个不相同的地址。

Page 27: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理6.2.7 指针表达式的副作用1. 表达式的副作用:表达式计算过程中,若参与

运算的变量的值发生了改变,称此表达式具有副作用。如 i+j++ 。

2. 表达式的副作用产生的原因是使用了具有副作用的操作符,包括:

(1) 赋值 (=)

(2) 复合赋值 (+=,-=,*=,/= 等等 )

(3) 前增 1 和前减 1(++,--)

(4) 后增 1 和后减 1(++,--)

Page 28: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理3. 对指针表达式具有副作用的操作符,包括:(1) 赋值 (=)(2) 复合赋值 (+=,-=,*=,/= 等等 )(3) 前增 1 和前减 1(++,--)(4) 后增 1 和后减 1(++,--)无副作用的操作符,包括:(1) 取地址 (&)(2) 间接引用 (*)(3) 其它如 +,-,== 等

Page 29: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

4. 对指针表达式,设 p 为指针变量。(1) 前增量 ++p, 前减量— p, 间接引用 *p,

赋值及复合赋值的结果仍为左值。

(2) 后增量 p++, 后减 p--, 取地址 &k 及由 p构成的算术表达式和关系表达式的结果不能作为左值。

Page 30: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例:设 p 为指针变量。 ++(++p) // 对 (p++)++ // 错 --p+=&k // 对 p--+=&k // 错 ++p++ // 错 (++p)++ // 对 ++(p++) // 错 p++-=3 // 错 (p+3)++ // 错 ++(p+3) // 错 ++++p // 对 p++++ // 错

Page 31: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.2.8 指针类型的强制转换 ( 类型修饰符 *) 指针表达式

6.2.9 指针操作符的综合运用例:见书。

Page 32: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.3 指针与数组6.3.1 一维指针与数组1 .指针的加减运算即指针的移动操作 ( 以

内存单元为单位 ) 。 2 .一维数组名是首元素地址。 

Page 33: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: int a[5];

a[0]

a[4]

a[1]

a[2]

a[3]

a

a+4

a+1

a+2

a+3

Page 34: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: int a[10];

int* pa=a;//int* pa=&a[0];

a[0] a[1] a[2] … … a[9]

… …

a

pa

Page 35: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

第 i 个元素 ( 四种表示 ) : a[i] *(a+i) p [i] *(p+i)

第 i 个元素地址 ( 四种表示 ) : &a[i] (a+i) &p[i] (p+i)

Page 36: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: #include<iostream.h>     void main()     {      int iArray[10];      int sum=0;      int* iptr=iArray;// 数组名是首元素地址     for(int i=0;i<10;i++) iArray[i]=i*2;       for(int index=0;index<10;index++)      {      sum+=*iptr;      iptr++;      }     cout<<”sum is”<<sum<<endl;     }  

Page 37: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

上例内存表示:

Page 38: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

3 .一维数组名是首元素地址,但数组名是指针常量,不能作为左值。 

例:见书。4 .数组指针:指向数组且与数组名等价

的指针。 

Page 39: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: int a[100];     int* iptr=a;     iptr 称为数组指针。  

  此时 iptr++ // 正确,因 iptr 为指针变量    a++ // 错误,因 a 为指针常量  

Page 40: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例:对数组的求和运算,有以下 5 种方法。 

   #include<iostream.h>     int s1,s2,s3,s4,s5;     int a[]={1,4,7,10,13,16,19,22,25};     int* iptr;  

Page 41: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

void main()  {    int size,n;    size=sizeof(a)/sizeof(*a);    //size=sizeof(a)/sizeof(a[0]);   

Page 42: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

for(n=0;n<size;n++) s1+=a[n];// 方法 1  

iptr=a;   for(n=0;n<size;n++) s2+=*iptr++;// 方法 2

  iptr=a;   for(n=0;n<size;n++) s3+=*(iptr+n);// 方法

3  

Page 43: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

iptr=a;   for(n=0;n<size;n++) s4+=iptr[n];// 方 法 4

 

for(n=0;n<size;n++)s5+=*(iArray+n);// 方法 5  

Page 44: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

cout<<s1<<endl   <<s2<<endl   <<s3<<endl   <<s4<<endl   <<s5<<endl;  }  

Page 45: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.3.2 多维数组与指针 1. 二维数组的数组名是首行地址。例: int b[5][2] ; int (*pb)[2]=b;

此时, pb 与数组名 b 等价,称 pb 是与数组 b 等价的数组指针。 

Page 46: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

内存表示:  

b

b+1

b+2

b+3

b+4

b[0][0]

b[1][0]

b[2][0]

b[3][0]

b[4][0]

b[0][1]

b[1][1]

b[2][1]

b[3][1]

b[4][1]

Page 47: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

数组 b 的第 i 行第 j 列元素可表示为: pb[i][j] b[i][j] *(b[i]+j)

*(*(b+i)+j) *(pb[i]+j) *(*(pb+i)+j)

相应地,有数组 b 的第 i 行第 j 列元素地址的表示方法。

以上转换要点: a[i] 等价与 *(a+i)

Page 48: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

由于 b[0] 可看成具有 2 个元素的一维整形数组 , 故其数组名 b[0] 即首元素地址 &b[0][0],b[0]+1 即 &b[0][1] 。

同理 b[1] 即 &b[1][0] , b[1]+1 即 &b[1][1] 。 b[2] 即 &b[2][0] , b[2]+1 即 &b[2][1] 。  b[3] 即 &b[3][0] , b[3]+1 即 &b[3][1] 。 ……

Page 49: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

内存表示:  

b

b+1

b+2

b+3

b+4

b[0][0]

b[1][0]

b[2][0]

b[3][0]

b[4][0]

b[0][1]

b[1][1]

b[2][1]

b[3][1]

b[4][1]

b[0] b[0]+1

b[1] b[1]+1

Page 50: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例:设计函数 show_matrix ,它显示参数传来的任意规格的整形二维数组。#include<iomanip.h>void show_matrix(int* array,int row,int col,int width){ for(int i=0;i<row;i++) { cout<<endl; for(int j=0;j<col;j++) cout<<setw(width)<<*(array+i*col+j); }}void main(){ int s[][3]={{1,2,3},{4,5,6},{7,8,9},{10,11,12}}; show_matrix(s[0],4,3,5); //&s[0][0] 或 (int*)s cout<<endl;}

Page 51: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.3.3 数组指针1. 数组指针:指向数组且与数组名等价的

指针。例 ( 指向一维数组的指针 )

int a[10];

int* pa=a;

称 pa 为数组指针。  

Page 52: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例 ( 指向二维数组的指针 )int b[3][4];int (*pb)[4]=b;称 pb 为数组指针。  

Page 53: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

2. 函数的形参为数组参数时,形式上是数组,本质上是指针,是与该数组名等价的数组指针。

例:int sum (int array[] ,int n); 等价于int sum (int*array , int n);

Page 54: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.3.4 字符指针与字符串1 .字符串:分为字符数组与字符串常量

两种。 (1) 字符数组是用来初始化字符数组的字符

串。 (2) 字符串常量是该字符串首字符地址,类

型为 char* 。 

Page 55: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: char buffer[]=“hello”;// 字符数组    cout<<“good”<<endl;// 字符串常量 

Page 56: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 2 .字符串常量存放在 data 区中的 const 区中。

  由于字符串常量是该字符串首字符地址,如字

符串常量“ hello” 值为 0000:0100( 因存放它的首单元地址是 0000:0100) ,另有字符串常量“ hello” 值为 0238:045d( 因存放它的首单元地址是 0238:045d) ,故两个同样字符组成的字符串常量是不相等的。见图。  

 

Page 57: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

3 .字符指针 (1) 字符串常量、字符数组名和字符指针的

类型均为 char* 。 (2) 输出字符指针就是输出字符串。 (3) 输出字符指针的间接引用就是输出单个

字符。 

Page 58: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理 例: #include<iostream.h>     void main()     {      char buffer[10]="ABC";      char* pc;      pc="hello";      cout<<pc<<endl;// 输出字符指针     pc++;      cout<<pc<<endl;// 输出字符指针    cout<<*pc<<endl;// 输出字符指针的间接引用    pc=buffer;     cout<<pc;// 输出字符指针   }  

Page 59: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

结果: hello      ello      e      ABC   

Page 60: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

4 .字符串比较  

(1) 两个字符串常量的比较是地址的比较。 

(2) 两个数组名的比较也是地址的比较。  

Page 61: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: #include<iostream.h>     void main()     {      char buffer1[10]="hello";      char buffer2[10]="hello";   if(buffer1==buffer2)     // 实质上是地址的比较   cout<<"equal\n";   else   cout<<"not equal\n";   }   结果: not equal   

Page 62: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 (3) 真正要从字面上比较两个字符串可用标

准库函数 strcmp() 进行。   标准库函数 strcmp() ,在头文件 string.

h 中,函数原型如下:   int strcmp(const char* s1,const char* s

2);  

Page 63: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

  函数值如下: 

   0 s1 值等于 s2 值   正值 s1 值大于 s2 值   负值 s1 值小于 s2 值  

Page 64: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: #include<iostream.h>     #include<string.h>     void main()     {      char buffer1[10]= "hello";      char buffer2[10]="hello";      if(strcmp(buffer1,buffer2)==0)       cout<<"equal\n";      else      cout<<"not equal\n";     }    结果: equal   

Page 65: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

5 .字符串赋值  (1) 因字符数组名是指针常量,故不能直

接给字符数组名赋值。  例: char buffer[10];      buffer=“hello”;// 错误,此为赋值

 

Page 66: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: char buffer[11]= “I am a boy”;// 正确,此为初始化 

 (2) 可通过 for 循环给字符数组赋值。  例: char buffer[11];      for (int i =0; i <10; i ++) cin>>a[i];

     a[10]=’\0’;  

Page 67: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

(3) 字符指针可初始化或赋值。 例: char *string=“I love china”;// 正确,

此为初始化  例: char *string;     string=“ I love china”;// 正确,此为

赋值 

Page 68: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

(4) 可调用标准库函数 strcpy() 给字符数组赋值。 

 标准库函数 strcpy() ,在头文件 string.h 中,函数原型如下: 

   char* strcpy( char* dest,const char* src);   功能:将 src 的内容拷贝到 dest 中,并将 dest

的值作为函数值返回。 

Page 69: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

例: char s[]="12345";     cout<<s<<" ";     cout<<strcpy(s, "ABCD")<<" ";     cout<<s;  结果: 12345 ABCD ABCD  

Page 70: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 例: char buffer1[10];     char buffer2[10];     strcpy(buffer1, "hello");     strcpy(buffer2, buffer1);  注: strcpy() 仅能对以‘ \0’ 作结束符的字

符数组进行操作。若要对其它类型的数组赋值可调用函数 memcpy() 。 

Page 71: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 (5) 标准库函数 memcpy() ,在头文件 mem.h 中,函数原型如下: 

  void* memcpy( void* d,void* s,size_t n);   功能:从源 s 中拷贝 n 个字节到目标 d 。  例: int intarray1[5]={1,3,5,7,9};     int intarray2[5];     memcpy(intarray2,intarray1,5*sizeof(int))例 6.2 例 6.3 见书。 

Page 72: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.3.5 指针数组和命令行参数 1 .指针数组:数组元素值为指针的数组称之指

针数组。 例: char* proname[]={"fortran","c","c++"};   

2 .指针数组与二维数组 例 : char* proname[]={“fortran”,“c”,“c++”};//

指针数组 

Page 73: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 数组 proname 占 2 字节 *3=6 字节,所指向的字符串占 8+2+4=14 个字节,故该指针数组共占 20 个字节的存储空间。 

  例: char name[3][8]={“fortran”,“c”,“c++”};//

二维数组  数组 name 共占 8 字节 *3=24 个字节的存储空

间。  故二维数组一般比指针数组多浪费存储空间。

 

Page 74: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 3 .二级指针:指向指针的指针。  数组名表示首元素地址,是一级指针。

  指针数组名是指向指针的指针,即二级

指针。  

Page 75: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: int a=3;     int* pa=&a;//pa 是一级指针    int** ppa=&pa;//ppa 是二级指针   该例内存示意图 

Page 76: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: char* pc[]={"a","b","c"};     char** ppc;     ppc=pc;//ok  

4 . Null 指针    Null 指针又称零指针或空指针值。   

Page 77: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

指针数组的主要应用是命令行参数。

5 .命令行参数: DOS 命令中,程序命令及键入的参数称为命令行参数。 

例: c>copy filea fileb//三个命令行参数   c>type c:autoexec.bat// 二个命令行参数

 

Page 78: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

命令行参数通过主函数 main() 的参数描述。主函数 main() 的参数有三个: 

int argc//描述命令行参数个数 char* argv[]//描述命令行参数的指针数组

 char* env[]//描述环境变量的指针数组 

Page 79: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 例: void main()     void main(int argc)     void main(int argc, char* argv[])// 该

形式较常用    void main(int argc, char* argv[],char*

env[])   

Page 80: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6 .打印命令行参数  例: //ch6-22.cpp      #include<iostream.h>      void main(int argc, char* argv[])      {      int icount=0;   while(icount<argc)   {        cout<<"arg"<<icount<<":“      <<argv[icount]<<endl;     icount++;   }   }  

Page 81: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

c>ch6_22 aBcD eFg hIjKl  arg0:ch6_22  arg1: aBcD  arg2: eFg  arg3: hIjKl  

Page 82: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: // 该例功能同上例   #include<iostream.h>    void main(int argc, char* argv[])    {     int i=0;     while(*argv!=Null)    cout<<"arg"<<i++<<":"<<*argv++<<end

l;     }  

Page 83: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

7 .命令行参数使用形式 (1)void main()    void main(int argc)    void main(int argc, char* argv[])// 该形式较常

用   void main(int argc, char* argv[],char* env[])   

Page 84: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

(2) 操作系统以空格区分不同参数,若参数中含有空格,可用引号括起来。 

例: c>ch6_22 Hello how are you  arg0:ch6_22  arg1: Hello  arg2: how  arg3: are  arg4:you  

Page 85: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 例: c>ch6_22 "Hello how are you"  arg0:ch6_22  arg1: Hello how are you   6.3.6 数组参数实际上是指针 

 

Page 86: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.4 指针与函数 6.4.1 指针参数1 .数组作为函数形参时,形式上是数组,

实际上是指针。 例: void sum(int array[],int n);     // 等价与 void sum(int * array,int n);

 

Page 87: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: #include<iostream.h>     void sum(int array[],int n)     { int sum=0;     for(int i=0;i<n;i++)     {      sum+=*array;     array++;     }     cout<<sum<<endl;     }     void main()     { int a[10]={1,2,3,4,5,6,7,8,9,10};     sum(a,10);     }  

Page 88: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

2 .形参和实参结合规则  

(1) 形参为简单变量时,结合规则:形参=实参的值 

Page 89: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: ( 形参为简单变量 )     #include<iostream.h>     double time2(double n)     {      n=n*2;      return n;     }     void main()     {      double m=7.0;      cout<<endl<<m;      cout<<endl<<time2(m);      cout<<endl<<m;     }   

Page 90: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理例: ( 形参为普通变量 )     #include<iostream.h>     void swap(int,int);     void main()     {   int a=3,b=8;       cout<<"a="<<a<<",b"<<b<<endl;      swap(a,b);      cout<<"after swapping…\n";      cout<<"a="<<a<<",b"<<b<<endl;   }     void swap(int x,int y)     {   int temp=x;      x=y;      y=temp;     }  

运行结果: a=3,b=8      after swapping…      a=3,b=8  

Page 91: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

(2) 形参为指针变量时,结合规则:形参指针=实参指针的值 ( 地址值 )  

Page 92: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: ( 形参为指针变量 )     #include<iostream.h>     void swap(int*,int*);     void main()     {   int a=3,b=8;       cout<<"a="<<a<<",b"<<b<<endl;      swap(&a,&b);      cout<<"after swapping…\n";      cout<<"a="<<a<<",b"<<b<<endl;     }     void swap(int* x,int* y)     { int temp=*x;     *x=*y;      *y=temp;    }  

运行结果: a=3,b=8      after swapping…   a=8,b=3  

Page 93: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

3 .指针函数:返回指针值的函数。 定义格式:类型修饰符 * 函数名(形参表)     函数体 (1) 指针函数不能把在它内部说明的具有局部作

用域的数据地址作为返回值。 (2) 可以返回堆地址,可以返回全局或静态变量

的地址。  

Page 94: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例:有若干个学生的成绩,要求在用户输入学生序号以后,能输出该学生的全部成绩。 

  #include<iostream.h>    void main()    {     static float score[][4]={60,70,80,90,65,76,

      87,69,88,66,79,80};  

Page 95: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

   float* search(float (* pointer )[4] , int n);     float* p;     int i, m;     cin>>m;     p=search(score,m);     for(i=0; i<4; i++)      cout<<*(p+ i)<< " ";    }  

行数

Page 96: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

   float* search(float (* pointer )[4] , int n)     {      float* pt;      pt= *( pointer + n);      return (pt);     }   

Page 97: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: char* trim(char* s )     {      char * p=s+strlen(s)-1;      while(p-s>=0&&*p==‘ ‘) p--;      *(p+1)=‘\0’;

return s;     }   

Page 98: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

4 . void 指针 ( 即 void*)     void 指针,又称空类型指针。不能进行

指针运算,也不能进行间接引用。可将其它类型指针赋给 void 指针,反之不行,除非进行显示转换。 

 

Page 99: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: void* p ;   p++ ; //error     *p=20.5 ; //error     int a=20 ;    int* pr=&a ;    void* p=pr ; //ok     pr=p ; //error     pr=(int*)p ; //ok   

Page 100: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

6.4.3 函数指针:指向函数且与函数名等价的指针。

1 .函数名是指向函数的指针常量。2 .函数指针定义  (1) 若函数原型为:类型 函数名 ( 形参表 ) ;  则相应函数指针定义为:  类型 (* 变量名 )( 形参表 )〖=函数名〗; 

Page 101: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 (2) 若函数原型为:类型 * 函数名 ( 形参表 ) ;  则相应函数指针定义为:  类型 * (* 变量名 )( 形参表 )〖=函数名〗;  例: int f1(int n);      int (*pf1)(int n);      pf1=f1;//pf1 是与 f1 等价的函数指针  

Page 102: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: int f1(int n);     int (*pf1)(int n)=f1;//pf1 是与 f1 等价的函数

指针  

例: char* f2(int n,char* s);// 指针函数    char* (*pf2)(int n,char* s);     pf2=f2;//pf2 是与 f2 等价的函数指针 

Page 103: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

例: char* f2(int n,char* s);// 指针函数    char* (*pf2)(int n,char* s)=f2;//pf2 是

与 f2 等价的函数指针  

3 .通过函数指针来调用函数 

Page 104: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: #include<iostream.h>     int add(int a,int b){return a+b};     void main()     {     int (*p)(int,int);     p=add; //p 是与 add 等价的函数指针    cout<<add(3,5);     cout<<(*p)(3,5);   四种调用形式效果等价  cout<<p(3,5);    cout<<(*add)(3,5);    }   结果: 8888  

Page 105: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 4 .函数指针作函数形参  

例:计算以 0.10 为步长,特定范围内的三角函数之和。   #include<iostream.h>    #include<math.h>   double sigma(double(*func)(double),double dl,double du)   {

double dt=0.0;

for(double d=dl;d<du;d+=0.1) dt+=func(d);   return dt;   }  

Page 106: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

void main()  { double dsum;   dsum=sigma(sin,0.1,1.0);   cout<<"the sum of sin from       0.1 to 1.0 is"<<dsum<<endl; dsum=sigma(cos,0.5,3.0);    cout<<"the sum of cos from       0.5 to 3.0 is"<<dsum<<endl; }  

Page 107: 第六章 指针、引用和动态空间管理

6.5  引用 (reference) 的概念  

1 .引用:为一个变量、函数等对象规定一个别名,该别名称为引用。此后,对别名的操作即是对别名所代表的对象的操作。 

第六章 指针、引用和动态空间管理 

Page 108: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

2 .声明引用:声明引用与定义指针类似,只不过将 * 换成 & 。引用只有声明,没有定义。因为引用不占存储空间,而定义要分配存储空间。 

Page 109: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

3 .引用若不是作为函数参数的,则必须初始化。 

 声明引用格式如下:  格式:类型 & 别名〖=别名所代表的

对象〗; 

Page 110: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例:  int i=0;    int& ir=i;// 定义引用 ir 作为对象 i 的别名  ir=2;// 形式上向 ir 赋值,实际上是向 i 赋

值,等同于 i=2;    int* p=&ir;// 形式上取 ir 的地址,实际

上是取 i 的地址,等同于 int* p=&i;  

Page 111: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: int a[10], *p=a;  int& ra1=a[6];//ra1代表数组元素 a[6]  int (&ra2)[10]=a;//ra2代表数组 a  int* & rp1=p;//rp1代表指针变量 p  int& rp2=*p;//rp2 代表 p 所指向的那个对象,即数组元素 a[0]  

Page 112: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例:#include<iostream.h>  void main()  {   int intone;   int& rint=intone;   intone=5;   cout<<"intone:"<<intone<<endl;   cout<<"rint : "<<rint<<endl;   rint=7;   cout<<"intone:"<<intone<<endl;   cout<<"rint : "<<rint<<endl;  }  

运行结果: intone:5        rint:5        intone:7        rint:7  

Page 113: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

4. 引用作为函数的形参  

函数形参为引用时,形参和实参结合规则。  形参为引用时,形参 ( 引用 ) 接收实参 ( 对象 )

的地址,每当使用引用时, c++ 就去求该引用所含地址中的变量值。 

Page 114: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

或表述为:

 形参为引用时,函数调用期间,凡遇到形参 ( 引用 ) 的地方,全部用实参 ( 对象 ) 来代替。 

Page 115: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: #include<iostream.h>     void swap(int& x,int& y);     void main()     { int x=5;      int y=6;   cout<<"before swap,x:"<<x<<",y:"<<y<<endl;   swap(x,y);   cout<<"after   swap,x:"<<x<<",y:"<<y<<endl;   }   void swap(int& rx,int& ry)   { int temp=rx;   rx=ry;   ry=temp;   }  

Page 116: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

结果: before swap,x:5,y:6      after swap,x:6,y:5   

例:见书。

Page 117: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

6.6 动态空间管理 (堆内存管理 )  1 .堆内存 (heap) :堆是一块内存区域,堆允许程序在运行时 (而不是编译时 ) ,申请某个大小的内存空间。堆内存又称为动态内存。 

  

Page 118: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

2 .获得堆内存   c 中用函数 malloc()( 在头文件 alloc.h 中 ) 来获得堆内存; c++ 中用操作符 new 来获得堆内存。 

3 .释放堆内存   c 中用函数 free()( 在头文件 alloc.h 中 ) 来释放堆内存; c++ 中用操作符 delete 来释放堆内存。 

 

Page 119: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

4 . new 和 delete 操作符 

(1) 对非数组空间   new 类型 [( 表达式 )]    delete 指针表达式 [ ,指针表达式 ]  

Page 120: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: int* p1,**p2;     p1=new int(5);     p2=new (int *);     *p2=new int(7);     cout<<endl<<*p1<<' '<<**p2;     delete p1 , *p2 , p2;   

Page 121: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

 

上例的内存表示: 

注: new 操作符若申请成功,返回首单元地址;否则返回 Null 值。 

Page 122: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

(2) 对数组空间 new 类型 [ 元素个数 ] //申请一维数组空间

 delete[] 指针表达式 [ ,指针表达式 ]  

Page 123: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例: int* ap=new int[10];     delete[] ap;   

Page 124: 第六章 指针、引用和动态空间管理

第六章 指针、引用和动态空间管理

例 : double (*matrix)[4]=new double[4][4];   delete[] matrix;  

 

matrix