第六章 指针、引用和动态空间管理
description
Transcript of 第六章 指针、引用和动态空间管理
第六章 指针、引用和动态空间管理 6.1 指针的概念 6.1.1 指针的概念 6.1.2 指针变量的定义和初始化1 .指针表示内存空间的地址。指针类型定义以
* 标识。 例: int* // 整型指针 char* // 字符指针 double*//double 型指针
第六章 指针、引用和动态空间管理
2 .指针变量定义 例: int* ip; char* cptr; int* iptr1,*iptr2;
第六章 指针、引用和动态空间管理
3 .建立指针 (1) 建立指针包含指针变量定义和给指针赋
初值 ( 地址 ) 。 (2)& 操作符可取变量地址,指针变量用于
存放地址。
第六章 指针、引用和动态空间管理
例: int* iptr; int icount=18; iptr=&icount;// 指针赋值
该例等价与
第六章 指针、引用和动态空间管理
例: int icount=18; int* iptr=&icount;// 指针的初始化
内存表示:
第六章 指针、引用和动态空间管理
4 .间接引用指针
操作符 * 可取指针变量所指单元内容,称为间接引用指针。
第六章 指针、引用和动态空间管理
例: #include<iostream.h> void main() { int * iptr; int icount=18; iptr=&icount; cout<<*iptr<<endl; *iptr=58; cout<<*iptr<<endl; } 结果: 18 58
第六章 指针、引用和动态空间管理
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; }
第六章 指针、引用和动态空间管理
结果: 58 0x0067fe00 0x0067fe00 58 0x0067fefc 内存表示:
第六章 指针、引用和动态空间管理
例: int icount=58; int* iptr=&icount; 则 icount // 整型变量 iptr // 指针变量 &icount // 整型变量 icount 地址
第六章 指针、引用和动态空间管理
&iptr // 指针变量 iptr 地址 *icount // 错误 *iptr // 指针变量 iptr 所指单元内容
6 . *( 取内容 ) 和 &( 取地址 ) 为互逆操作。
第六章 指针、引用和动态空间管理
6.1.3 const 指针
1 .指向常量的指针:在指针定义语句的类型前加 const ,表示指针指向的数据为常量。
第六章 指针、引用和动态空间管理
例: 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 为常量
第六章 指针、引用和动态空间管理
pi=&c; *pi=88; // 错误, *pi 为常量 c=98; 结论: const int * pi=&a;( 或 int const * pi
=&a;) 中, *pi 为常量, pi 为变量,故 *pi 不能为左值。
第六章 指针、引用和动态空间管理
2 .指针常量:在指针定义语句的指针名前加 const ,表指针本身为常量。
第六章 指针、引用和动态空间管理
例: char * const pc="asdf"; pc=“dfgh”;// 错误, pc 为常量 *pc='b'; *(pc+1)='c'; *pc++=‘y’; // 错误, pc 为常量 结论: int * const pi=&a; 中, *pi 为变量, pi 为常
量,故 pi 不能为左值。
第六章 指针、引用和动态空间管理
3 .指向常量的指针常量
结论: const int * const pi=&a; 中, *pi 、pi 均为常量,故均不能作为左值。
第六章 指针、引用和动态空间管理
例: const int ci=7; int ai; const int * const cpc=&ci; const int * const cpc=&ai; cpi=&ai; // 错误, cpi 为常量 *cpi=39; // 错误, *cpi 为常量 ai=39;
第六章 指针、引用和动态空间管理
6.2 指针运算6.2.1 赋值 (=) 同类型指针之间可相互赋值。 任何类型的指针可赋值给 void 指针,反
之不行。例: char c=‘x’,*s=&c;
void * p1,* p2=Null;
p1=s;// 对 s=p2;// 错
第六章 指针、引用和动态空间管理
6.2.2 取地址 (&) 单目运算符 & 可取变量的地址。例: int k,*p;
p=&k;
k
p
第六章 指针、引用和动态空间管理
6.2.3 取内容 (*) 单目运算符 * 可取指针所指的内存单元内容。例: int *pd,d;
pd=&d;
*pd=99;
cout<<*pd<<‘ ‘<<endl;
99
d
pd
第六章 指针、引用和动态空间管理
6.2.4 判断一指针是否为空指针 (== 或 !=) 。例:如果 p 是空指针,则… if(p==0)… if(p==Null)… if(!p)…例:如果 p 不是空指针,则… if(p!=0)… if(p!=Null)… if(p)…
第六章 指针、引用和动态空间管理6.2.5 计算两地址间数据单元的个数 (-) 。 计算两地址间存储单元的个数。 一般将高地址指针作被减数,且其数据
不计算在内。例: int n,m[12],*p1=&m[5],*p2=&m[10];
n=p2-p1;//n==5
低地址 高地址p1 p2
第六章 指针、引用和动态空间管理
6.2.6 指针移动1. 移动 n 个单位:操作符 + 、 - 、 += 和
-= 。指针向后 ( 高地址 ) 移动 n 个单位:指针
表达式 +n 或指针表达式 +=n 。指针向前 ( 低地址 ) 移动 n 个单位:指针
表达式 -n 或指针表达式 -=n 。例:见书。
第六章 指针、引用和动态空间管理
2. 移动 1 个单位:操作符 ++( 前增 1) 、 ++( 后增 1) -- ( 前减 1) 和 -- ( 后减 1) 。
指针向后 ( 高地址 ) 移动 1 个单位:指针变量 ++ 或 ++ 指针变量。
指针向前 ( 低地址 ) 移动 1 个单位:指针变量 -- 或 -- 指针变量。
第六章 指针、引用和动态空间管理
例: int k,*pk=&k; cout<<endl<<++pk; cout<<endl<<pk;结果是两个相同的地址。
例: int k,*pk=&k; cout<<endl<<pk++; cout<<endl<<pk;结果是两个不相同的地址。
第六章 指针、引用和动态空间管理6.2.7 指针表达式的副作用1. 表达式的副作用:表达式计算过程中,若参与
运算的变量的值发生了改变,称此表达式具有副作用。如 i+j++ 。
2. 表达式的副作用产生的原因是使用了具有副作用的操作符,包括:
(1) 赋值 (=)
(2) 复合赋值 (+=,-=,*=,/= 等等 )
(3) 前增 1 和前减 1(++,--)
(4) 后增 1 和后减 1(++,--)
第六章 指针、引用和动态空间管理3. 对指针表达式具有副作用的操作符,包括:(1) 赋值 (=)(2) 复合赋值 (+=,-=,*=,/= 等等 )(3) 前增 1 和前减 1(++,--)(4) 后增 1 和后减 1(++,--)无副作用的操作符,包括:(1) 取地址 (&)(2) 间接引用 (*)(3) 其它如 +,-,== 等
第六章 指针、引用和动态空间管理
4. 对指针表达式,设 p 为指针变量。(1) 前增量 ++p, 前减量— p, 间接引用 *p,
赋值及复合赋值的结果仍为左值。
(2) 后增量 p++, 后减 p--, 取地址 &k 及由 p构成的算术表达式和关系表达式的结果不能作为左值。
第六章 指针、引用和动态空间管理
例:设 p 为指针变量。 ++(++p) // 对 (p++)++ // 错 --p+=&k // 对 p--+=&k // 错 ++p++ // 错 (++p)++ // 对 ++(p++) // 错 p++-=3 // 错 (p+3)++ // 错 ++(p+3) // 错 ++++p // 对 p++++ // 错
第六章 指针、引用和动态空间管理
6.2.8 指针类型的强制转换 ( 类型修饰符 *) 指针表达式
6.2.9 指针操作符的综合运用例:见书。
第六章 指针、引用和动态空间管理
6.3 指针与数组6.3.1 一维指针与数组1 .指针的加减运算即指针的移动操作 ( 以
内存单元为单位 ) 。 2 .一维数组名是首元素地址。
第六章 指针、引用和动态空间管理
例: int a[5];
a[0]
a[4]
a[1]
a[2]
a[3]
a
a+4
a+1
a+2
a+3
第六章 指针、引用和动态空间管理
例: int a[10];
int* pa=a;//int* pa=&a[0];
a[0] a[1] a[2] … … a[9]
… …
a
pa
第六章 指针、引用和动态空间管理
第 i 个元素 ( 四种表示 ) : a[i] *(a+i) p [i] *(p+i)
第 i 个元素地址 ( 四种表示 ) : &a[i] (a+i) &p[i] (p+i)
第六章 指针、引用和动态空间管理
例: #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; }
第六章 指针、引用和动态空间管理
上例内存表示:
第六章 指针、引用和动态空间管理
3 .一维数组名是首元素地址,但数组名是指针常量,不能作为左值。
例:见书。4 .数组指针:指向数组且与数组名等价
的指针。
第六章 指针、引用和动态空间管理
例: int a[100]; int* iptr=a; iptr 称为数组指针。
此时 iptr++ // 正确,因 iptr 为指针变量 a++ // 错误,因 a 为指针常量
第六章 指针、引用和动态空间管理
例:对数组的求和运算,有以下 5 种方法。
#include<iostream.h> int s1,s2,s3,s4,s5; int a[]={1,4,7,10,13,16,19,22,25}; int* iptr;
第六章 指针、引用和动态空间管理
void main() { int size,n; size=sizeof(a)/sizeof(*a); //size=sizeof(a)/sizeof(a[0]);
第六章 指针、引用和动态空间管理
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
第六章 指针、引用和动态空间管理
iptr=a; for(n=0;n<size;n++) s4+=iptr[n];// 方 法 4
for(n=0;n<size;n++)s5+=*(iArray+n);// 方法 5
第六章 指针、引用和动态空间管理
cout<<s1<<endl <<s2<<endl <<s3<<endl <<s4<<endl <<s5<<endl; }
第六章 指针、引用和动态空间管理
6.3.2 多维数组与指针 1. 二维数组的数组名是首行地址。例: int b[5][2] ; int (*pb)[2]=b;
此时, pb 与数组名 b 等价,称 pb 是与数组 b 等价的数组指针。
第六章 指针、引用和动态空间管理
内存表示:
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 的第 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)
第六章 指针、引用和动态空间管理
由于 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] 。 ……
第六章 指针、引用和动态空间管理
内存表示:
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
第六章 指针、引用和动态空间管理
例:设计函数 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;}
第六章 指针、引用和动态空间管理
6.3.3 数组指针1. 数组指针:指向数组且与数组名等价的
指针。例 ( 指向一维数组的指针 )
int a[10];
int* pa=a;
称 pa 为数组指针。
第六章 指针、引用和动态空间管理
例 ( 指向二维数组的指针 )int b[3][4];int (*pb)[4]=b;称 pb 为数组指针。
第六章 指针、引用和动态空间管理
2. 函数的形参为数组参数时,形式上是数组,本质上是指针,是与该数组名等价的数组指针。
例:int sum (int array[] ,int n); 等价于int sum (int*array , int n);
第六章 指针、引用和动态空间管理
6.3.4 字符指针与字符串1 .字符串:分为字符数组与字符串常量
两种。 (1) 字符数组是用来初始化字符数组的字符
串。 (2) 字符串常量是该字符串首字符地址,类
型为 char* 。
第六章 指针、引用和动态空间管理
例: char buffer[]=“hello”;// 字符数组 cout<<“good”<<endl;// 字符串常量
第六章 指针、引用和动态空间管理
2 .字符串常量存放在 data 区中的 const 区中。
由于字符串常量是该字符串首字符地址,如字
符串常量“ hello” 值为 0000:0100( 因存放它的首单元地址是 0000:0100) ,另有字符串常量“ hello” 值为 0238:045d( 因存放它的首单元地址是 0238:045d) ,故两个同样字符组成的字符串常量是不相等的。见图。
第六章 指针、引用和动态空间管理
3 .字符指针 (1) 字符串常量、字符数组名和字符指针的
类型均为 char* 。 (2) 输出字符指针就是输出字符串。 (3) 输出字符指针的间接引用就是输出单个
字符。
第六章 指针、引用和动态空间管理 例: #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;// 输出字符指针 }
第六章 指针、引用和动态空间管理
结果: hello ello e ABC
第六章 指针、引用和动态空间管理
4 .字符串比较
(1) 两个字符串常量的比较是地址的比较。
(2) 两个数组名的比较也是地址的比较。
第六章 指针、引用和动态空间管理
例: #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
第六章 指针、引用和动态空间管理
(3) 真正要从字面上比较两个字符串可用标
准库函数 strcmp() 进行。 标准库函数 strcmp() ,在头文件 string.
h 中,函数原型如下: int strcmp(const char* s1,const char* s
2);
第六章 指针、引用和动态空间管理
函数值如下:
0 s1 值等于 s2 值 正值 s1 值大于 s2 值 负值 s1 值小于 s2 值
第六章 指针、引用和动态空间管理
例: #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
第六章 指针、引用和动态空间管理
5 .字符串赋值 (1) 因字符数组名是指针常量,故不能直
接给字符数组名赋值。 例: char buffer[10]; buffer=“hello”;// 错误,此为赋值
第六章 指针、引用和动态空间管理
例: 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’;
第六章 指针、引用和动态空间管理
(3) 字符指针可初始化或赋值。 例: char *string=“I love china”;// 正确,
此为初始化 例: char *string; string=“ I love china”;// 正确,此为
赋值
第六章 指针、引用和动态空间管理
(4) 可调用标准库函数 strcpy() 给字符数组赋值。
标准库函数 strcpy() ,在头文件 string.h 中,函数原型如下:
char* strcpy( char* dest,const char* src); 功能:将 src 的内容拷贝到 dest 中,并将 dest
的值作为函数值返回。
第六章 指针、引用和动态空间管理
例: char s[]="12345"; cout<<s<<" "; cout<<strcpy(s, "ABCD")<<" "; cout<<s; 结果: 12345 ABCD ABCD
第六章 指针、引用和动态空间管理
例: char buffer1[10]; char buffer2[10]; strcpy(buffer1, "hello"); strcpy(buffer2, buffer1); 注: strcpy() 仅能对以‘ \0’ 作结束符的字
符数组进行操作。若要对其它类型的数组赋值可调用函数 memcpy() 。
第六章 指针、引用和动态空间管理
(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 见书。
第六章 指针、引用和动态空间管理
6.3.5 指针数组和命令行参数 1 .指针数组:数组元素值为指针的数组称之指
针数组。 例: char* proname[]={"fortran","c","c++"};
2 .指针数组与二维数组 例 : char* proname[]={“fortran”,“c”,“c++”};//
指针数组
第六章 指针、引用和动态空间管理
数组 proname 占 2 字节 *3=6 字节,所指向的字符串占 8+2+4=14 个字节,故该指针数组共占 20 个字节的存储空间。
例: char name[3][8]={“fortran”,“c”,“c++”};//
二维数组 数组 name 共占 8 字节 *3=24 个字节的存储空
间。 故二维数组一般比指针数组多浪费存储空间。
第六章 指针、引用和动态空间管理
3 .二级指针:指向指针的指针。 数组名表示首元素地址,是一级指针。
指针数组名是指向指针的指针,即二级
指针。
第六章 指针、引用和动态空间管理
例: int a=3; int* pa=&a;//pa 是一级指针 int** ppa=&pa;//ppa 是二级指针 该例内存示意图
第六章 指针、引用和动态空间管理
例: char* pc[]={"a","b","c"}; char** ppc; ppc=pc;//ok
4 . Null 指针 Null 指针又称零指针或空指针值。
第六章 指针、引用和动态空间管理
指针数组的主要应用是命令行参数。
5 .命令行参数: DOS 命令中,程序命令及键入的参数称为命令行参数。
例: c>copy filea fileb//三个命令行参数 c>type c:autoexec.bat// 二个命令行参数
第六章 指针、引用和动态空间管理
命令行参数通过主函数 main() 的参数描述。主函数 main() 的参数有三个:
int argc//描述命令行参数个数 char* argv[]//描述命令行参数的指针数组
char* env[]//描述环境变量的指针数组
第六章 指针、引用和动态空间管理
例: void main() void main(int argc) void main(int argc, char* argv[])// 该
形式较常用 void main(int argc, char* argv[],char*
env[])
第六章 指针、引用和动态空间管理
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++; } }
第六章 指针、引用和动态空间管理
c>ch6_22 aBcD eFg hIjKl arg0:ch6_22 arg1: aBcD arg2: eFg arg3: hIjKl
第六章 指针、引用和动态空间管理
例: // 该例功能同上例 #include<iostream.h> void main(int argc, char* argv[]) { int i=0; while(*argv!=Null) cout<<"arg"<<i++<<":"<<*argv++<<end
l; }
第六章 指针、引用和动态空间管理
7 .命令行参数使用形式 (1)void main() void main(int argc) void main(int argc, char* argv[])// 该形式较常
用 void main(int argc, char* argv[],char* env[])
第六章 指针、引用和动态空间管理
(2) 操作系统以空格区分不同参数,若参数中含有空格,可用引号括起来。
例: c>ch6_22 Hello how are you arg0:ch6_22 arg1: Hello arg2: how arg3: are arg4:you
第六章 指针、引用和动态空间管理
例: c>ch6_22 "Hello how are you" arg0:ch6_22 arg1: Hello how are you 6.3.6 数组参数实际上是指针
第六章 指针、引用和动态空间管理
6.4 指针与函数 6.4.1 指针参数1 .数组作为函数形参时,形式上是数组,
实际上是指针。 例: void sum(int array[],int n); // 等价与 void sum(int * array,int n);
第六章 指针、引用和动态空间管理
例: #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); }
第六章 指针、引用和动态空间管理
2 .形参和实参结合规则
(1) 形参为简单变量时,结合规则:形参=实参的值
第六章 指针、引用和动态空间管理
例: ( 形参为简单变量 ) #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; }
第六章 指针、引用和动态空间管理例: ( 形参为普通变量 ) #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
第六章 指针、引用和动态空间管理
(2) 形参为指针变量时,结合规则:形参指针=实参指针的值 ( 地址值 )
第六章 指针、引用和动态空间管理
例: ( 形参为指针变量 ) #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
第六章 指针、引用和动态空间管理
3 .指针函数:返回指针值的函数。 定义格式:类型修饰符 * 函数名(形参表) 函数体 (1) 指针函数不能把在它内部说明的具有局部作
用域的数据地址作为返回值。 (2) 可以返回堆地址,可以返回全局或静态变量
的地址。
第六章 指针、引用和动态空间管理
例:有若干个学生的成绩,要求在用户输入学生序号以后,能输出该学生的全部成绩。
#include<iostream.h> void main() { static float score[][4]={60,70,80,90,65,76,
87,69,88,66,79,80};
第六章 指针、引用和动态空间管理
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)<< " "; }
行数
第六章 指针、引用和动态空间管理
float* search(float (* pointer )[4] , int n) { float* pt; pt= *( pointer + n); return (pt); }
第六章 指针、引用和动态空间管理
例: char* trim(char* s ) { char * p=s+strlen(s)-1; while(p-s>=0&&*p==‘ ‘) p--; *(p+1)=‘\0’;
return s; }
第六章 指针、引用和动态空间管理
4 . void 指针 ( 即 void*) void 指针,又称空类型指针。不能进行
指针运算,也不能进行间接引用。可将其它类型指针赋给 void 指针,反之不行,除非进行显示转换。
第六章 指针、引用和动态空间管理
例: 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
第六章 指针、引用和动态空间管理
6.4.3 函数指针:指向函数且与函数名等价的指针。
1 .函数名是指向函数的指针常量。2 .函数指针定义 (1) 若函数原型为:类型 函数名 ( 形参表 ) ; 则相应函数指针定义为: 类型 (* 变量名 )( 形参表 )〖=函数名〗;
第六章 指针、引用和动态空间管理
(2) 若函数原型为:类型 * 函数名 ( 形参表 ) ; 则相应函数指针定义为: 类型 * (* 变量名 )( 形参表 )〖=函数名〗; 例: int f1(int n); int (*pf1)(int n); pf1=f1;//pf1 是与 f1 等价的函数指针
第六章 指针、引用和动态空间管理
例: 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 等价的函数指针
第六章 指针、引用和动态空间管理
例: char* f2(int n,char* s);// 指针函数 char* (*pf2)(int n,char* s)=f2;//pf2 是
与 f2 等价的函数指针
3 .通过函数指针来调用函数
第六章 指针、引用和动态空间管理
例: #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
第六章 指针、引用和动态空间管理
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; }
第六章 指针、引用和动态空间管理
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; }
6.5 引用 (reference) 的概念
1 .引用:为一个变量、函数等对象规定一个别名,该别名称为引用。此后,对别名的操作即是对别名所代表的对象的操作。
第六章 指针、引用和动态空间管理
第六章 指针、引用和动态空间管理
2 .声明引用:声明引用与定义指针类似,只不过将 * 换成 & 。引用只有声明,没有定义。因为引用不占存储空间,而定义要分配存储空间。
第六章 指针、引用和动态空间管理
3 .引用若不是作为函数参数的,则必须初始化。
声明引用格式如下: 格式:类型 & 别名〖=别名所代表的
对象〗;
第六章 指针、引用和动态空间管理
例: int i=0; int& ir=i;// 定义引用 ir 作为对象 i 的别名 ir=2;// 形式上向 ir 赋值,实际上是向 i 赋
值,等同于 i=2; int* p=&ir;// 形式上取 ir 的地址,实际
上是取 i 的地址,等同于 int* p=&i;
第六章 指针、引用和动态空间管理
例: 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]
第六章 指针、引用和动态空间管理
例:#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
第六章 指针、引用和动态空间管理
4. 引用作为函数的形参
函数形参为引用时,形参和实参结合规则。 形参为引用时,形参 ( 引用 ) 接收实参 ( 对象 )
的地址,每当使用引用时, c++ 就去求该引用所含地址中的变量值。
第六章 指针、引用和动态空间管理
或表述为:
形参为引用时,函数调用期间,凡遇到形参 ( 引用 ) 的地方,全部用实参 ( 对象 ) 来代替。
第六章 指针、引用和动态空间管理
例: #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; }
第六章 指针、引用和动态空间管理
结果: before swap,x:5,y:6 after swap,x:6,y:5
例:见书。
第六章 指针、引用和动态空间管理
6.6 动态空间管理 (堆内存管理 ) 1 .堆内存 (heap) :堆是一块内存区域,堆允许程序在运行时 (而不是编译时 ) ,申请某个大小的内存空间。堆内存又称为动态内存。
第六章 指针、引用和动态空间管理
2 .获得堆内存 c 中用函数 malloc()( 在头文件 alloc.h 中 ) 来获得堆内存; c++ 中用操作符 new 来获得堆内存。
3 .释放堆内存 c 中用函数 free()( 在头文件 alloc.h 中 ) 来释放堆内存; c++ 中用操作符 delete 来释放堆内存。
第六章 指针、引用和动态空间管理
4 . new 和 delete 操作符
(1) 对非数组空间 new 类型 [( 表达式 )] delete 指针表达式 [ ,指针表达式 ]
第六章 指针、引用和动态空间管理
例: int* p1,**p2; p1=new int(5); p2=new (int *); *p2=new int(7); cout<<endl<<*p1<<' '<<**p2; delete p1 , *p2 , p2;
第六章 指针、引用和动态空间管理
上例的内存表示:
注: new 操作符若申请成功,返回首单元地址;否则返回 Null 值。
第六章 指针、引用和动态空间管理
(2) 对数组空间 new 类型 [ 元素个数 ] //申请一维数组空间
delete[] 指针表达式 [ ,指针表达式 ]
第六章 指针、引用和动态空间管理
例: int* ap=new int[10]; delete[] ap;
第六章 指针、引用和动态空间管理
例 : double (*matrix)[4]=new double[4][4]; delete[] matrix;
matrix