• 1. 1第六章 指针、引用及 动态分配C++语言程序设计
  • 2. 2关于内存地址内存空间的访问方式 通过变量名访问 通过地址访问 地址运算符:& 例: int var; 则&var 表示变量var在内存中的起始地址
  • 3. 3声明 例:static int i; static int *i_pointer=&i; 指向整型变量的指针指针变量的概念概念 指针:内存地址,用于 间接访问内存单元 指针变量: 用于存放地址的变量20003i_pointer *i_pointeri2000内存用户数据区变量 i变量 j变量 i_pointer362000200020043010使用 例1: i=3; 例2: *i_pointer=3; 指 针
  • 4. 指针变量的概念空指针 地址值为 0,专用于表示未指向任何数据;地址值 0 可用 NULL 表示; 无类型指针(void类型指针) 无类型限制的指针,可以用来指向任何类型的数据。 指 针
  • 5. 5指针变量的定义、初始化语法形式 存储类型 数据类型 *指针名=初始地址; 例: int *pa=&a; 注意事项 用变量地址作为初值时,该变量必须在指针初始化之前已说明过,且变量类型应与指针类型一致。 可以用一个已赋初值的指针去初始化另一 个指针变量。 不要用一个内部 变量去初始化 static 指针。 指 针
  • 6. 指针变量的定义、初始化例如: int *pn,*ph; double d,*pd1=&d,*pd2=pd1; char *s=“This is a string”; // s被初始化为字符串常量的首地址 void *pd3=NULL,*pd4=0; long *pd5=NULL; 指 针
  • 7. 指针变量的定义、初始化dpd1pd2sThis is a string\0图6-2指针图示方法示例pd3pd4pd5
  • 8. 指针变量的定义、初始化char * cp = “string”; cout<
  • 9. 指针变量的定义、初始化char a[ ] = “hello world”; char *p = a; cin>>p; cout<
  • 10. 10指向常量的指针不能通过指针来改变所指对象的值,但指针本身可以改变,可以指向另外的对象。 例1 char *name1 = "John"; //name1是一般指针 *name1='A'; //编译正确,运行出错 例2 const char *name1 = "John"; //指向常量的指针 char s[]="abc"; name1=s; //正确,name1本身的值可以改变 *name1='1'; //编译时指出错误 指 针
  • 11. 11指针类型的常量若声明指针常量,则指针本身的值不能被改变。例: char *const name2 = "John"; name2=“abc”; //指针常量值不能改变 int a [10] = {0};//数组名可看为是指针常量 指 针
  • 12. 12指针变量的赋值运算指针名=地址 “地址”中存放的数据类型与指针类型必须相符。 向指针变量赋的值必须是地址常量或变量,不能是普通整数。但可以赋值为整数0,表示空指针。 指针的类型是它所指向变量的类型,而不是指针本身数据值的类型,任何一个指针本身的数据值都是unsigned long int型。 允许声明指向 void 类型的指针。该指针可以被赋予任何类型对象的地址。 例: void *general; 指 针
  • 13. 13例:void类型指针的使用void vobject; //错,不能声明void类型的变量 void *pv; //对,可以声明void类型的指针 int *pint; int i; void main() //void类型的函数没有返回值 { pv = &i; //void类型指针指向整型变量 // void指针赋值给int指针需要类型强制转换: pint = (int *)pv; } 指 针
  • 14. 指针变量的算术运算* 和 & 是两个互逆的操作,当这两个操作符碰到一起时,其作用相互抵消,例如 *&k=3 与 k=3 效果完全相同 “如果p是空指针,则...” if(p==0)... if(p==NULL)... if(!p)... // C++风格 指 针
  • 15. 15指针变量的算术运算指针与整数的加减运算 指针 p 加上或减去 n ,其意义是指针当前指向位置的前方或后方第 n 个数据的地址。 这种运算的结果值取决于指针指向的数据类型。 移动的字节数 = n*sizeof(指针的类型) 指 针
  • 16. 指针变量的算术运算int n,m[12],*p1=&m[5], *p2=&m[10]; n=p2-p1; //n==5m11109876543210p1p2 指 针
  • 17. papa-2pa-1pa+1pa+2pa+3*(pa-2)*pa*(pa+1)*(pa+2)*(pa+3)*(pa-1)short *pa17
  • 18. pb-1pbpb+1pb+2*(pb-1)*pb*(pb+1)*(pb+2)long *pb18
  • 19. 指针变量的算术运算指针加一,减一运算 指向下一个或前一个数据。 *++p、++*p、 (*p)++、 *p++ 。 例如:y=*px++ 相当于 y=*(px++) (*和++优先级相同,自右向左运算) 指 针
  • 20. 指针的基本操作..*p++ :取 p 所指向单元的数据作为表达式的值,然后使 p 指向下一个单元; 执行 *p++ 后: (*p++的值:3)d369p369初始状态: dp
  • 21. 指针的基本操作..(*p)++ :取p所指向单元的数据作为表达式的值,然后使该单元的数据值增1; 执行( *p)++ 后: ((*p)++的值:3)d469p369初始状态: dp
  • 22. 指针的基本操作..*++p :使p指向下一个单元,然后取该单元的数据作为表达式的值;执行 * ++ p后: (* ++ p的值:6)d369p369初始状态: dp
  • 23. 指针的基本操作..++*p :将p所指向单元的数据值增1并作为表达式的值。执行++ *p后: ( ++ *p的值:4)d469p369初始状态: dp
  • 24. 24指向数组元素的指针声明与赋值 例: int a[10], *pa; pa=&a[0]; 或 pa=a; 通过指针引用数组元素 *pa就是a[0],*(pa+1)就是a[1],... ,*(pa+i)就是a[i]. a[i], *(pa+i), *(a+i), pa[i] 都是等效的。 不能写 a++,因为a是数组首地址是常量即指针常量。 指针与数组
  • 25. 指向数组元素的指针int a[10], i, s=0; for (i=0; i<10; i++) { cin>>a[i]; s+= *(a+i); } int *p = a; for (i=0 ;i<10; i++) { cin>>p[i]; s+= p[i]; } 指针与数组
  • 26. 指针数组与数组指针数组的元素是指针型 例:int *dp[2] = {0}; 每个元素为一个int*类型的指针变量。 指向数组的指针 例:int (*dp)[2] ; 指针与数组
  • 27. 指针与二维数组int a [M] [N]; > a[i]就是一维数组的数组名 a[i] = &a[i][0] ; //类型为 int* > 对一维元素a[i],其指针访问 *(a+i); > a[i][j] = (*(a+i))[j] = *(*(a+i)+j) = *(a[i]+j) > a、a[0]、&a[0]、&a[0][0]值相等,但类 型不同。 > a = &a[0]; //指针常量,类型为 int(*)[N] a[0] = &a[0][0]; //类型为 int * 指针与数组
  • 28. 28例:二维数组举例#include using namespace std; void main() { int array [2][3]={{11,12,13},{21,22,23}}; for(int i=0;i<2;i++) { cout<<*(array+i)<
  • 29. 在某次运行之后,程序的输出结果为: 0x0065FDE0 11,12,13 0X0065FDEC 21,22,2329
  • 30. 指针与二维数组int a[2][3] = {{0,1,2},{3,4,5}}; int (*p)[3] = a; // a = &a[0],类型为int(*)[3] //使P指向了二维数组,通过p可以访问数组元素 int i , j; for (i = 0;i < 2;i++){ for (j = 0; j < 3;j++) cout<
  • 31. 31以指针作为函数参数以地址方式传递数据,可以用来返回函数处理结果。 实参是数组名时形参可以是指针。 指针与函数
  • 32. 32例题目:读入三个浮点数,将整数部分和小数部分分别输出 #include using namespace std; void splitfloat(float x, int *intpart, float *fracpart) { //形参intpart、 fracpart是指针 *intpart = int(x); // 取x的整数部分 *fracpart = x - *intpart; //取x的小数部分 } 指针与函数
  • 33. void main(void) { int i, n; float x, f; cout << "Enter three (3) floating point numbers" << endl; for (i = 0; i < 3; i++) { cin >> x; splitfloat(x,&n,&f); //变量地址做实参 cout << "Integer Part is " << n << " Fraction Part is " << f << endl; } }33
  • 34. 运行结果: Enter three (3) floating point numbers 4.7 Integer Part is 4 Fraction Part is 0.7 8.913 Integer Part is 8 Fraction Part is 0.913 -4.7518 Integer Part is -4 Fraction Part is -0.7518 34
  • 35. 35例: 输出数组元素的内容、地址#include #include using namespace std; void Array_Ptr(long *P, int n) { int i; cout << "In func, address of array is " << unsigned long(P) << endl; cout << "Accessing array in the function using pointers" << endl; for (i = 0; i < n; i++) { cout << " Address for index " << i << " is " << unsigned long(P+i); cout << " Value is " << *(P+i) << endl; } } 指针与函数
  • 36. void main(void) { long list[5] = {50, 60, 70, 80, 90}; cout << "In main, address of array is " << unsigned long(list) << endl; cout << endl; Array_Ptr(list,5); }
  • 37. 运行结果: In main, address of array is 6684132 In func, address of array is 6684132 Accessing array in the function using pointers Address for index 0 is 6684132 Value is 50 Address for index 1 is 6684136 Value is 60 Address for index 2 is 6684140 Value is 70 Address for index 3 is 6684144 Value is 80 Address for index 4 is 6684148 Value is 9037
  • 38. 38指向常量的指针做形参#include using namespace std; const int N=6; void print(const int *p,int n); void main() { int array[N]; for(int i=0;i>array[i]; print(array,N); } 指 针
  • 39. void print(const int *p, int n) { cout<<"{"<<*p; for(int i=1;i
  • 40. 指针与函数—— 指针参数 作用1:通过将数据区的地址传递给函数,使函数能够改动该地址处的数据 例如: int addTo(int data,int *agg) { return *agg+=data; } 可以如下方式使用函数: int total=10; cout << addTo(5,&total);
  • 41. 指针与函数 作用2:减少参数传递过程中的数据复制量 如果仅以“作用2”为目的,应将参数说明为常值指针,如 void show(const int *p,int n){ for(int i=0;i
  • 42. 指针与函数如果参数是指向数组的指针,也可以按数组方式进行说明,例如: void show(const int p[],int n){ for(int i=0;i
  • 43. 43指针型函数当函数的返回值是地址时,该函数就是指针形函数。 声明形式 存储类型 数据类型 *函数名() 指针与函数
  • 44. 44声明形式 存储类型 数据类型 (*函数指针名)(); 含义: 数据指针指向数据存储区,而函数指针指向的是程序代码存储区。指向函数的指针 指针与函数
  • 45. 45例:函数指针#include using namespace std; void print_stuff(float data_to_ignore); void print_message(float list_this_data); void print_float(float data_to_print); void (*function_pointer)(float); void main() { float pi = (float)3.14159; float two_pi = (float)2.0 * pi; 指针与函数
  • 46. 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); print_float(pi); }46
  • 47. void print_stuff(float data_to_ignore) { cout<<"This is the print stuff function.\n"; } void print_message(float list_this_data) { cout<<"The data to be listed is " <
  • 48. 运行结果: This is the print stuff function. This is the print stuff function. The data to be listed is 6.283180 The data to be listed is 13.000000 The data to be printed is 3.141590 The data to be printed is 3.141590 48
  • 49. 引用变量定义一个引用(reference)就是为一个变量、函数等对象规定一个别名。 定义引用变量的一般格式是: 类型修饰符 &别名=所代表的对象; 引 用
  • 50. 引用变量 例如: int i=0; int &ir=i; ir=2; //等同于i=2; int *p=&ir; //等同于int *p=&i; 引 用
  • 51. 引用变量进一步的例子: int a[10],*p=a; int &ra1=a[6]; //代表a[6] int (&ra2)[10]=a; //代表数组a int *&rp1=p; //代表指针变量p int &rp2=*p; //代表p所指向的那个对象, //即数组元素a[0] 引 用
  • 52. 引用变量引用是初始化对象的别名,共享初始化对象具有的存储空间; 必须对引用变量初始化; 主要应用在对函数形参的说明中。 引 用
  • 53. 指针参数例子: template void swap(T *a,T *b){ T c = *a; *a = *b; *b = c; } 调用方式:int x=3,y=5; swap(&x,&y); 指针参数与引用参数比较
  • 54. 引用..引用参数例子: template void swap(T &a,T &b){ T c = a; a = b; b = c; } 调用方式:int x=3,y=5; swap(x,y);
  • 55. 数据的分配区域“栈存储区” ---- 静态分配或预分配 “堆存储区” ---- 动态分配 动态存储分配
  • 56. 动态空间管理—— 数据利用内存空间的几种情况 静态空间:静态变量所用的空间,在编译时分配,生存期:应用程序运行的整个期间; 自动空间(堆空间):自动变量所用的空间,在运行到定义该变量所在的块时分配,但在编译时即已确定大小,生存期:从定义处开始到块结束处为止;
  • 57. 动态空间管理栈空间:函数参数和函数返回值所用的空间,在函数被调用时分配,但在编译时即已确定大小,生存期:函数被调用的整个期间; 动态空间:动态数据所用的空间,用 new 申请时分配,生存期:从申请时开始,直到用 delete 释放时为止。
  • 58. 动态空间管理..#include int a; void show(int n){ static int b; cout<
  • 59. 59动态申请内存操作符newnew 类型名(初值列表) 功能:在程序执行期间,申请用于存放类型对象的内存空间,并依初值列表赋以初值。 结果值:成功:返回类型指针,指向新分配的内存。失败:0(NULL) 动态存储分配
  • 60. 动态申请内存操作符new返回的是地址,对于非数组可同时进行初始化; new int(5); new char*(&x); new int [m+1][N+1]; >对于多维数组,仅有第一维可为变量,其余维数必须为常数。 new int [2] [3] [4]; 则返回值类型为 int(*)[3][4] >多维数组返回值为一个指向低一级数组的指针。 动态存储分配
  • 61. 61释放内存操作符deletedelete 指针P 功能:释放指针P所指向的内存。P必须是new操作的返回值。 delete p1; delete [ ]p2; 注: > 仅是释放空间,p1、p2任可以指向其它的对象 > 指针变量指向一块动态分配的数组空间,则该指针变量可以作为数组名使用,采用下标方式访问每个元素,但它不是数组名,所以可以修改它的值。 动态存储分配
  • 62. 释放内存操作符deleteint n,i ; cin>>n; int *p = new int [n]; i = *p-3; cout<<*p<<‘ ‘<
  • 63. 动态空间管理示例: int *p1,**p2; p1=new int(5); p2=new (int *); *p2=new int(7); cout<
  • 64. 动态空间管理..*p1**p2*p2p15p27
  • 65. 65动态创建多维数组new 类型名T[下标表达式1][下标表达式2]…; 如果内存申请成功,new运算返回一个指向新分配内存首地址的指针,是一个T类型的数组,数组元素的个数为除最左边一维外各维下标表达式的乘积。例如: char (*fp)[3]; fp = new char[2][3]; 动态存储分配
  • 66. char (*fp)[3];fpfp+1fp[0][0]fp[0][1]fp[0][2]fp[1][0]fp[1][1]fp[1][2]66
  • 67. 动态空间管理示例: int *ap=new int[10]; double (*Matrix)[20]= new double[20][20]; …… delete []ap,[]Matrix;
  • 68. 动态空间管理第一维的说明可以是任意表达式,而从第二维开始就必须是常量表达式。例如(假定 m,n 都是变量): int *p1=new int[n]; //正确 int (*p2)[6]=new int[n][6];//正确 int (*p3)[n]=new int[m][n]; //错 int (*p4)[n]=new int[10][n];//错
  • 69. 69例:动态创建多维数组#include using namespace std; void main() { float (*cp)[9][8]; int i,j,k; cp = new float[8][9][8]; for (i=0; i<8; i++) for (j=0; j<9; j++) for (k=0; k<9; k++) *(*(*(cp+i)+j)+k)=i*100+j*10+k; //通过指针访问数组元素 动态存储分配
  • 70. for (i=0; i<8; i++) { for (j=0; j<9; j++) { for (k=0; k<8; k++) //将指针cp作为数组名使用, //通过数组名和下标访问数组元素 cout<
  • 71. The End第六章71