c++——阐述指针和引用

阐述指针和引用

​ C++最大的优点之一是,您既可使用它来编写不依赖于机器的高级应用程序,又可使用它来编写与硬件紧密协作的应用程序。事实上,C++让您能够在字节和比特级调整应用程序的性能。要编写高效地利用系统资源的程序,理解指针和引用是必不可少的一步。

在本章中,您将学习:
• 什么是指针;
• 什么是自由存储区;
• 如何使用运算符 new 和 delete 分配和释放内存;
• 如何使用指针和动态分配编写稳定的应用程序;
• 什么是引用;
• 指针和引用的区别;
• 什么情况下使用指针,什么情况下使用引用。

​ 第八章主要讨论了C++中的指针和引用,这两个概念是C++中非常重要的部分,它们允许程序员更直接地操作内存。以下是第八章的学习笔记概述:

8.1 什么是指针

  • 指针定义:指针是存储另一个变量内存地址的变量。指针是一个变量,与所有变量一样,指针也占用内存空间。
  • 声明指针:使用 PointedType * PointerVariableName; 格式声明。
  • 初始化指针:通常初始化为 NULLnullptr,防止未定义行为。

8.1.1 声明指针

  • 指针需要明确指向的类型,如 int *pInt; 表示指向 int 类型的指针。
  • 与大多数变量一样,除非对指针进行初始化,否则它包含的值将是随机的。您不希望访问随机的 内存地址,因此将指针初始化为 NULL。NULL 是一个可以检查的值,且不会是内存地址
  • 与您学过的所有数据类型一样,除非对指针进行初始化,否则它包含的将是垃圾值。对 指针来说,这种垃圾值非常危险,因为指针包含的值被视为地址。未初始化的指针可能 导致程序访问非法内存单元,进而导致程序崩溃。

8.1.2 使用引用运算符(&)获取地址

  • 使用 & 运算符获取变量的内存地址。
  • 前面的输出表明, int 变量 age 的地址为 0x0045FE00,而 sizeof(int)为 4,因此 0x0045FE00-0x0045FE04 的 4 字节内存由 int 变量 age 占用。

8.1.3 使用指针存储地址

  • 声明指针并使用 &variable 初始化,使其存储变量的地址。

8.1.4 使用解除引用运算符(*)访问指向的数据

  • 使用 *pointer 来访问或修改指针指向的数据。

8.1.5 将 sizeof() 用于指针的结果

  • sizeof 运算符对指针使用时,返回指针本身的大小,与指针所指向的类型无关。
  • 您知道,指针是包含内存地址的变量。因此无论指针指向哪种类型的变量,其内容都是一个地址 —一个数字。在特定的系统中,存储地址所需的字节数是固定的。因此,将 sizeof( )用于指针时,结 果取决于编译程序时使用的编译器和针对的操作系统,与指针指向的变量类型无关
  • 程序清单 8.6 的输出表明,将 sizeof 用于指针的结果为 4 字节,但在您的系统上结果可 能不同。这里的输出是使用 32 位编译器编译代码时得到的,如果您使用的是 64 位编 译器,并在 64 位系统上运行该程序,可能发现将 sizeof 用于指针的结果为 64 位,即 8 字节。

8.2 动态内存分配

  • 使用 newdelete:动态分配和释放内存。
  • 内存泄露:忘记使用 delete 释放内存导致的问题。
  • 如果在程序中使用下面这样的数组声明:

    int myNums[100]; // a static array of 100 integers

    程序将存在两个问题。 1.这限制了程序的容量,无法存储 100 个以上的数字。 2.如果只需存储 1 个数字,却为 100 个数字预留存储空间,这将降低系统的性能。

    导致这些问题的原因是,数组的内存分配是静态和固定的。 要编写根据用户需要使用内存资源的应用程序,需要使用动态内存分配。这让您能够根据需要分 配更多内存,并释放多余的内存。为帮助您更好地管理应用程序占用的内存,C++提供了两个运算符 —new 和 delete。指针是包含内存地址的变量,在高效地动态分配内存方面扮演了重要角色。

8.2.1 使用 new 和 delete 动态地分配和释放内存

  • new Type 分配单个元素的内存。
  • new Type[numElements] 分配数组的内存。
  • delete 释放单个元素的内存。
  • delete[] 释放数组的内存。
  • 不再使用分配的内存后,如果不释放它们,这些内存仍被预留并分配给您的应用程序。这将减少 可供其他应用程序使用的系统内存量,甚至降低您的应用程序的执行速度。这被称为内存泄露,应不 惜一切代价避免这种情况发生。
  • 运算符 new 和 delete 分配和释放自由存储区中的内存。自由存储区是一种内存抽象,表 现为一个内存池,应用程序可分配(预留)和释放其中的内存。

8.2.2 将递增和递减运算符(++ 和 --)用于指针的结果

  • 指针递增 ++ 移动到下一个元素的地址。
  • 指针递减 -- 移动到上一个元素的地址。
  • 将指针递增或递减的结果 将指针递增或递减时,其包含的地址将增加或减少指向的数据类型的 sizeof(并不一定是 1 字节)。 这样,编译器将确保指针不会指向数据的中间或末尾,而只会指向数据的开头。 如果声明了如下指针:Type* pType = Address; 则执行++pType 后,pType 将包含(指向)Address + sizeof(Type)。

8.2.3 将关键字 const 用于指针

  • const 指针的不同类型和使用场景。
  • 通过将变量声明为 const 的,可确保变量的取值在整个生命周期内都固定为初始值。 这种变量的值不能修改,因此不能将其用作左值。 指针也是变量,因此也可将关键字 const 用于指针。然而,指针是特殊的变量,包含内存地址,还 可用于修改内存中的数据块。因此,const 指针有如下三种。
  • 在这里插入图片描述

8.2.4 将指针传递给函数

  • 如何通过指针向函数传递数据,并控制函数对数据的修改能力。

  • 指针是一种将内存空间传递给函数的有效方式,其中可包含函数完成其工作所需的数据,也可包 含操作结果。将指针作为函数参数时,确保函数只能修改您希望它修改的参数很重要。例如,如果函 数根据以指针方式传入的半径计算圆的面积,就不应允许它修改半径。为控制函数可修改哪些参数以 及不能修改哪些参数,可使用关键字 const

8.2.5 数组和指针的类似之处

  • 数组名本身就是一个指向数组首元素的指针。
  • 换句话说,数组类似于在 固定内存范围内发挥作用的指针。可将数组赋给指针,如第 11 行所示,但不能将指针赋给数组,因为 数组是静态的,不能用作左值。myNumbers 是不能修改的。
  • 使用运算符 new 动态分配的指针仍需使用运算符 delete 来释放,虽然其使用语法与静态 数组类似。牢记这一点很重要。 如果忘记这样做,应用程序将泄露内存,这很糟糕。
  • 在这里插入图片描述

8.3 使用指针时常犯的编程错误

  • 内存泄露:忘记释放动态分配的内存。这可能是 C++应用程序最常见的问题之一:运行时间越长,占用的内存越多,系统越慢。如果在 使用 new 动态分配的内存不再需要后,程序员没有使用配套的 delete 释放,通常就会出现这种情况。

  • 指针指向无效的内存单元:未初始化或错误的内存访问。使用运算符*对指针解除引用,以访问指向的值时,务必确保指针指向了有效的内存单元,否则程 序要么崩溃,要么行为不端。这看起来合乎逻辑,但一个非常常见的导致应用程序崩溃的原因就是无 效指针。指针无效的原因很多,但主要归结于糟糕的内存管理。

  • 悬浮指针:使用已经释放的内存地址。悬浮指针(也叫迷途或失控指针) 使用 delete 释放后,任何有效指针都将无效。换言之,在程序清单 8.13 中,即便在第 22 行前指针 isSunny 是有效的,但第 22 行调用 delete 后,它也变成无效的了,不应再使用。 为避免这种问题,很多程序员在初始化指针或释放指针后将其设置为 NULL,并在使用运算符*对 指针解除引用前检查它是否有效(将其与 NULL 比较)。

8.3.4 检查使用 new 发出的分配请求是否得到满足

  • 在前面的代码中,我们都假定 new 将返回一个指向内存块的有效指针。事实上,除非请求分配的 内存量特大,或系统处于临界状态,可供使用的内存很少,否则 new 一般都能成功
  • 有些应用程序需 要请求分配大块的内存(如数据库应用程序),因此最好不要假定内存分配能够成功。C++提供了两种 确认指针有效的方法,默认方法是使用异常(这也是前面一直使用的方法),即如果内存分配失败,将 引发 std::bad_alloc 异常。这导致应用程序中断执行,除非您提供了异常处理程序,否则应用程序将崩 溃,并显示一条类似于“异常未处理”的消息。在这里插入图片描述

8.4 指针编程最佳实践

  • 初始化指针。
  • 仅在指针有效时使用。
  • 使用 new 分配的内存,必须使用 delete 释放。
  • 释放内存后,不再访问该内存。

8.5 引用是什么

  • 引用定义:引用是另一个变量的别名。
  • 使用 & 声明引用,如 Type& reference = variable;

8.5.1 是什么让引用很有用

  • 引用用于函数参数,避免复制,提高效率。

8.5.2 将关键字 const 用于引用

  • const 引用不能修改其指向的变量的值。

  • //可能需要禁止通过引用修改它指向的变量的值,为此可在声明引用时使用关键字 const:
    int original = 30; 
    const int& constRef = original; 
    constRef = 40; // Not allowed: constRef can’t change value in original 
    int& ref2 = constRef; // Not allowed: ref2 is not const
    const int& constRef2 = constRef; // OK 
    

8.5.3 按引用向函数传递参数

  • 使用引用传递可以避免复制大对象,提高性能。

  • 引用的优点之一是,可避免将形参复制给形参,从而极大地提高性能。然而,让被调用的函数直 接使用调用函数栈时,确保被调用函数不能修改调用函数中的变量很重要。为此,可将引用声明为 const 的,如程序清单 8.19 所示。const 引用参数不能用作左值,因此试图给它们赋值将无法通过编译。

  • 在这里插入图片描述

  • 在前一个程序中,使用同一个参数来接受输入和存储结果,但这里使用了两个参数,一个用于接 受输入,另一个用于存储运算结果。为禁止修改传入的值,必须使用关键字 const 将其声明为 const 引 用,如第 3 行所示。这让 number 自动变为输入参数—其值不能修改的参数。 您可以尝试修改第 5 行,使其像程序清单 8.18 那样返回平方值: number *= number; 这将导致编译错误,指出 const 值不能修改。这说明 const 引用将参数标识为输入参数,并禁止对 其进行修改。乍一看,这可能微不足道,但在多名程序员合作编程时,编写第一个版本的人和改进的 人可能不同,通过使用 const 引用可提高编程质量。

ber; 这将导致编译错误,指出 const 值不能修改。这说明 const 引用将参数标识为输入参数,并禁止对 其进行修改。乍一看,这可能微不足道,但在多名程序员合作编程时,编写第一个版本的人和改进的 人可能不同,通过使用 const 引用可提高编程质量。
在Microsoft Word中插入目录,可以通过以下步骤实现:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值