第六章 指针、引用和动态空间管理 6.1 指针的概念 6.1.1 指针的概念 6.1.2 指针变量的定义和初始化 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; } 结果:18 58
第六章 指针、引用和动态空间管理 5.指针变量地址:指针变量也具有内存地址。 例:#include<iostream.h> 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 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; cout<<*pd<<‘ ‘<<endl; d pd 99
第六章 指针、引用和动态空间管理 6.2.4 判断一指针是否为空指针(==或!=)。 例:如果p是空指针,则… if(p==0)… if(p==Null)… if(!p)… 例:如果p不是空指针,则… if(p!=0)… if(p!=Null)… if(p)…
一般将高地址指针作被减数,且其数据不计算在内。 例:int n,m[12],*p1=&m[5],*p2=&m[10]; 第六章 指针、引用和动态空间管理 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++; 结果是两个不相同的地址。
第六章 指针、引用和动态空间管理 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
int* pa=a;//int* pa=&a[0]; 第六章 指针、引用和动态空间管理 例: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个元素地址(四种表示) :
第六章 指针、引用和动态空间管理 例:#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 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的第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[0] b[0]+1 b[1] b[1]+1 b b+1 b+2 b+3 b+4
第六章 指针、引用和动态空间管理 例:设计函数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区中。 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* s2);
第六章 指针、引用和动态空间管理 函数值如下: 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()给字符数组赋值。 (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.指针数组:数组元素值为指针的数组称之指针数组。 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 第六章 指针、引用和动态空间管理 例: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> 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> 例://该例功能同上例 #include<iostream.h> void main(int argc, char* argv[]) { int i=0; while(*argv!=Null) cout<<"arg"<<i++<<":"<<*argv++<<endl; }
第六章 指针、引用和动态空间管理 7.命令行参数使用形式 (1)void main() void main(int argc) 7.命令行参数使用形式 (1)void main() void main(int argc) void main(int argc, char* argv[])//该形式较常用 void main(int argc, char* argv[],char* env[])
第六章 指针、引用和动态空间管理 (2)操作系统以空格区分不同参数,若参数中含有空格,可用引号括起来。 (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 例: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> 例:(形参为简单变量) #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);
第六章 指针、引用和动态空间管理 运行结果: a=3,b=8 after swapping… a=3,b=8 例:(形参为普通变量) 例:(形参为普通变量) #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> 例:(形参为指针变量) #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.指针函数:返回指针值的函数。 定义格式:类型修饰符* 函数名(形参表) 函数体 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* 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; { 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.函数指针定义 6.4.3 函数指针:指向函数且与函数名等价的指针。 1.函数名是指向函数的指针常量。 2.函数指针定义 (1)若函数原型为:类型 函数名(形参表); 则相应函数指针定义为: 类型 (*变量名)(形参表)〖=函数名〗;
第六章 指针、引用和动态空间管理 (2)若函数原型为:类型* 函数名(形参表); 则相应函数指针定义为: (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为步长,特定范围内的三角函数之和。 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; } 运行结果:intone:5 rint:5 intone:7 rint:7
第六章 指针、引用和动态空间管理 4. 引用作为函数的形参 函数形参为引用时,形参和实参结合规则。 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.获得堆内存 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 *); 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