欢迎光临散文网 会员登陆 & 注册

第七讲 指针与引用 (没咋听懂)

2021-02-04 21:06 作者:你算是哪块小饼干吖  | 我要投稿

第七讲  指针与引用

一  指 针

1  指针变量的定义与使用

  • 指针的定义格式 格式: 目标数据对象类型 * 指针变量名称; 例一:定义 p 为指向整数的指针: int * p; 例二:定义 p 为指向结构体类型的指针: struct POINT{ int x, y; }; POINT * p;

  • 多个指针变量的定义 例三: int * p, * q; 例四: typedef int * PINT; PINT p, q;

  • 取址操作符“&” 获取数据对象的地址,可将结果赋给指针变量 示例: int n = 10; int * p; p = &n; int * q; q = p;

  • 引领操作符“*” 获取指针所指向的目标数据对象 例一: int m, n = 10; int * q = &n; m = *q; 使得 m 为 10 例二(接上例): *q = 1;使得 n 为 1  

  • 指针的意义与作用 a.作为函数通信的一种手段 使用指针作为函数参数,不仅可以提高参数传递效率, 还 可以将该参数作为函数输出集的一员,带回结果 b.作为构造复杂数据结构的手段 使用指针构造数据对象之间的关联,形成复杂数据结构 c.作为动态内存分配和管理的手段 在程序执行期间动态构造数据对象之间的关联 d.作为执行特定程序代码的手段 使用指针指向特定代码段,执行未来才能实现的函数  


2  指针与函数

  • 数据交换函数

    例:编写程序互换两个整型数据对象的值,要求使用函数实现数据对象值的互换

     #include <iostream>
     using namespace std;
     void Swap( int * x, int * y );
     int main()
     {
     int m = 10, n = 20;
     #ifndef NDEBUG
     cout << "main (before swapped): m = " << m << "; n = " << n << endl;
     #endif
     Swap( &m, &n ); /* 调用Swap函数互换目标数据对象的值 */
     #ifndef NDEBUG
     cout << "main (after swapped): m = " << m << "; n = " << n << endl;
     #endif
     return 0;
     }
     void Swap( int * x, int * y )
     {
     int t;
     if( !x || !y ){
     cout << "Swap: Parameter(s) illegal." << endl;
     exit(1);
     }
     #ifndef NDEBUG
     cout << "Swap (before swapped): *x = " << *x << "; *y = " << *y << endl;
     #endif
     t = *x;
     *x = *y;
     *y = t;
     #ifndef NDEBUG
     cout << "Swap (after swapped): *x = " << *x << "; *y = " << *y << endl;
     #endif
     }


  • 常量指针与指针常量

    常量指针:指向常量的指针 性质:不能通过指针修改目标数据对象的值,但可以改变指针值,使其指向其他地方 示例一: int n = 10; const int * p = &n; 典型使用场合:作为函数参数,表示函数内部不能修改指针所指向的目标数据对象值 示例二: void PrintObject( const int * p ); 指针常量:指针指向的位置不可变化 性质:不可将指针指向其他地方,但可改变指针所指向的目标数据对象值 示例三: int n = 10; int * const p = &n; 指针常量和其他常量一样,必须在定义时初始化 常量指针常量:指向常量的指针常量(指针的双重只读属性) 性质:指针值不可改变,指向的目标数据对象值也不可改变 示例四: const int n = 10; const int * const p = &n; 典型使用场合:主要作为函数参数使用  

  • 返回指针的函数

    指针类型可以作为函数返回值 函数内部返回某个数据对象的地址 调用函数后将返回值赋值给某个指针 特别说明: 不能返回函数内部定义的局部变量地址 程序示例 int global = 0; int * ReturnPointer() { return &global; }


3  指针与复合数据类型  

  • 指针与数组 数据对象地址的计算指针关系运算 可以测试两个指针是否相等 例一:设 p、 q 为指针,则 p == q 测试两个指针是否指向同一个目 标数据对象 空指针: NULL 指针值 0:表示指针不指向任何地方,表示为 NULL 例二:设 p 为指针,则 p = NULL 表示 p 不指向任何目标数据对象 例三(测试指针 p 是否有意义): if( p != NULL ) 等价于 if( p ) 使用指针前一定要测试其是否有意义!  

    作为函数参数的指针与数组

    指针与数组的可互换性

    多维数组参数的传递


  • 指针与结构体 指向结构体的指针 指针作为结构体类型的成员  

二  字符串

  • 字符数组

    字符数组的定义:与普通数组定义格式相同 示例: char s[9] = { 'C', 'P', 'P', '-', 'P', 'r', 'o', 'g' ,‘/0’};

  • 字符指针

  • 字符串整体

  • C标准字符串库:"cstring"

  • C++字符串类:"string"

三  动态存储管理

  • C格式: malloc/free

    malloc 函数的一般用法 首先定义特定类型的指针变量: char * p; 调用 malloc 函数分配内存: p = (char *)malloc(11); 参数表示所需要分配的存储空间大小,以字节为单位 例:若要分配能够保存 10 个字符的字符串,分配 11 个字节(字 符串结束标志也要分配空间) 将返回值转换为 char * 类型赋值给原指针,使 p 指向新分配空间 的匿名目标数据对象  

    free 函数的一般用法 传递一个指向动态分配内存的目标数据对象的指针 示例一: char * p; p = (char *)malloc(11); free(p); 示例二: int * p = ( int * )malloc( 10 * sizeof( int ) ); free( p ); 示例二分配能够容纳 10 个整数的连续存储空间,使 p 指向该空间的基地址,最后调用 free 函数释放 p 指向的整个空间 特别说明:有分配就有释放 free 函数释放的是 p 指向的目标数据对象的空间,而不是 p 本身的存储空间 调用 free 函数后, p 指向的空间不再有效,但 p 仍指向它 为保证在释放目标数据对象空间后,不会再次使用 p 访问,建议按照下述格式 书写代码: free( p ); p = NULL;

  • C++格式: new/delete

    new/new[ ] 操作符

    动态创建单个目标数据对象 分配目标对象: int * p; p = new int; *p = 10; 分配目标对象: int * p; p = new( int ); *p = 10; 分配目标对象并初始化: int * p; p = new int(10); // 将 *p 初 始化为 10 分配目标对象并初始化: int * p; p = new(int)(10); 动态创建多个目标数据对象 分配数组目标对象: int * p; p = new int[8]; // 分配 8 个元素 的整数数组  

    delete/delete[ ] 操作符

    释放单个目标数据对象 释放目标对象: int * p; p = new int; *p = 10; delete p; 释放多个目标数据对象 释放数组目标对象: int * p; p = new int[8]; delete[] p; 不是delete p[ ]!  

  • 空悬指针问题 所有权的重叠:指针赋值操作导致两个指针数据对象指向同样的目 标数据对象,即两个指针都声称“自己拥有目标数据对象的所有权” 示例: int *p, *q; q = ( int* )malloc( sizeof(int) ); p = q; 产生原因:如果在程序中通过某个指针释放了目标数据对象,另一 指针并不了解这种情况,它仍指向不再有效的目标数据对象,导致 空悬指针 示例: free( p ); p = NULL; // q 为空悬指针,仍指向原处

    解决方案 确保程序中只有惟一一个指针拥有目标数据对象,即只有它负责目标数据对象的存储管理,其它指针只可访问,不可管理;若目标数据对象仍有存在价值,但该指针不再有效,此时应进行所有权移交 在一个函数中,确保最多只有一个指针拥有目标数据对象,其它指针即使存在,也仅能访问,不可管理 如果可能,在分配目标数据对象动态内存的函数中释放内存,如main函数分配的内存在 main 函数中释放退一步,如果上述条件不满足,在分配目标数据对象动态内存的函数的主调函数中释放内存,即将所有权移交给上级函数级级上报,层层审批  

四  引 用  

1  引用类型

  • 引用的定义 定义格式: 数据类型& 变量名称 = 被引用变量名称; 示例: int a; int & ref = a;

  • 引用的性质 引用类型的变量不占用单独的存储空间 为另一数据对象起个别名,与该对象同享存储空间

  • 特殊说明 引用类型的变量必须在定义时初始化 此关联关系在引用类型变量的整个存续期都保持不变 对引用类型变量的操作就是对被引用变量的操作  

2  引用作为函数参数  

  • 引用的最大意义:作为函数参数 参数传递机制:引用传递,直接修改实际参数值 使用格式: 返回值类型 函数名称( 类型 & 参数名称); 函数原型示例: void Swap( int & x, int & y ); 函数实现示例: void Swap( int & x, int & y ){ int t; t = x; x = y; y = t; return; } 函数调用示例: int main(){ int a = 10, b = 20; Swap( a, b ); return 0; }

3  引用作为函数返回值  

  • 常量引用:仅能引用常量,不能通过引用改变目标对象值;引用本身 也不能改变引用对象

  • 引用作为函数返回值时不生成副本 函数原型示例: int & Inc( int & dest, const int & alpha ); 函数实现示例: int & Inc( int & dest, const int & alpha ){ dest += alpha; return dest; } 函数调用示例:引用类型返回值可以递增 int main(){ int a = 10, b = 20, c; Inc( a, b ); c = Inc(a, b)++; return 0; }


第七讲 指针与引用 (没咋听懂)的评论 (共 条)

分享到微博请遵守国家法律