65.9K
CodeProject 正在变化。 阅读更多。
Home

C++ 中的指针用法: 从初学者到高级

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (39投票s)

2005年9月7日

7分钟阅读

viewsIcon

300318

downloadIcon

2102

本文深入探讨了 C++ 中的指针概念和语法。文章采用了分级的方法来提高难度,为初学者提供了大量插图和示例,并为高级用户提供了测试“多维指针的动态内存分配”等知识的机会。

目录

总览

第一部分:C++ 指针入门

第二部分:动态内存分配与数组的关联

第三部分:函数指针和解析(长)指针声明

总览

第一章:引言:目标、目标受众和文章修订

C++ 是一种编程语言,它兼具低级和高级编程语言的特性。它允许直接访问内存地址,但也提供了高级的面向对象编程功能。它还与 C 向后兼容。C++ 提供的灵活性伴随着巨大的复杂性。我写这篇文章的目的是为了揭开 C++ 指针带来的复杂性。就个人而言,一旦我深入理解了指针,学习 C++ 中其余必要知识就变得非常容易了。

本文面向 C++ 的初学者和中级用户。然而,对于任何想要测试自己 C++ 指针语法知识的人来说,它都会有所帮助。特别是,“第十一章:解析(长)指针声明”和“第九章:动态内存分配:多维指针”这两章将会非常有益。

自本文上一版本以来,我做了两项重大更改。C++ 语法现在通过图像进行着色,并添加了一些插图以使示例更容易理解。整篇文章使用了十几个以上的示例来说明核心概念。在阅读时亲自练习这些示例会很有帮助。源代码包含在下载版本中。所有示例都已在 GNU C++ 编译器 v3.4 下进行了测试。

请将您对改进文章和进行必要更正的建议发送至 varunhome@gmail.com。您还可以通过 我的网页找到更多技巧。请点击标记为“Technical Articles”的链接。

第一部分:C++ 指针入门

第二章:& 和 * 运算符

指针是存储另一个变量地址的变量。在 C++ 中处理指针时,有两个重要的运算符:地址(&)运算符和值(*)运算符。它们在 C++ 中被重载了,因此可以在不同上下文中具有不同的用途。

指针会消耗多少存储空间?使用 sizeof(ptr)(不带 '*' 运算符)来确定您系统上使用的内存。无论数据类型如何,无论指针指向单个变量还是数组,作为一般规则,指针必须使用相同的内存空间。

& 运算符给出变量的地址,* 运算符给出指定地址处变量的值。例如:

第三章:指针:第一个示例

这是一个使用 C++ 中指针的简单示例:

一张图表,说明上面示例中不同变量之间的关系,应该有助于阐明这些概念。

第四章:指针数组

就像我们有变量数组一样,我们也有指针数组。例如:

int *p[5];

声明了一个包含五个指向整数变量的指针的数组。更多关于指针语法的信息将在“第十一章:解析(长)指针声明”中提供。每个指针依次存储一个整数的内存地址。每个指针甚至可以存储一个整数数组的基地址。让我们通过一个例子来理解指针数组的用法。

第二部分:动态内存分配与数组的关联

第五章:内存的动态分配:一维指针

在上面的示例中,我们没有为指针 ptr[2] 所指向的数据分配内存。这是因为它指向的数组 ch3 内存已经被分配了。但是,在某些情况下,我们可能希望一个指针变量指向一个未命名的内存位置。我们通过使用 newdelete 运算符来实现这一点。这是一个简单的示例,随后是一个更复杂的示例:

有一点需要记住的是在类中使用动态内存分配。当我们在 C++ 中创建一个类时,编译器会自动创建四个成员函数,即使我们不创建它们:

  1. 默认(无参)构造函数。
    classname& classname ()
  2. 拷贝构造函数。
    classname& classname (classname&)
  3. 赋值(=)运算符。
    classname& operator=(classname&)
  4. 析构函数。
    ~classname ()

当我们复制一个包含指针的类时,指针会被复制,但指针指向的数据不会被复制。因此,始终要记住使用动态内存分配复制数据,并将其存储在类副本的指针中。因此,在重载拷贝构造函数时,您应该也最好重载赋值运算符。

第六章:C++ 中数组与指针语法的关联

数组和指针语法在 C++ 中通常是可互换的。下一个示例强化了在前一个示例中简要涵盖的这些关联。

第七章:多维指针

就像我们可以有 N(2, 3, 4, ...)维变量一样,我们也可以有多维指针。下面展示了一个简单的示例:

您会发现上面的语法经常用于将参数传递给函数和接受返回值。让我们通过一个例子来理解这一点:

上面的代码的使用可以从下图轻松理解。您应该尝试自己绘制一张图表来理解“第九章:动态内存分配:多维指针”中的示例。

第八章:使用指针从函数返回值

我假设您已经知道了在下一个示例中使用的这些关键字:

  1. exit (int):结束程序。
  2. break:停止循环执行。
  3. continue:停止当前循环迭代,从下一个值继续。
  4. return:用于停止函数执行。在返回 void 的函数中也可以不带参数使用。

第九章:动态内存分配:多维指针

这是另一个更复杂的动态内存分配示例。我们将为大小为 [3][4] 的二维数组分配空间,并使用指针对其进行操作。

当使用三维指针创建大小为 [2][3][4] 的数组时,上面的示例看起来如下:

当动态内存分配失败时,会抛出异常。您通常会想捕获异常并中止程序执行。然而,在 C++ 中使用异常之前(或者如果您使用 new 的 nothrow 版本),每当动态分配失败时,指针都会存储一个 NULL 值。在这种情况下,将使用以下检查:

int *ptr = new int; 

if(!ptr) 
{ //error }

第三部分:函数指针和解析(长)指针声明

第十章:函数指针入门

就像我们有基本数据类型的指针一样,我们也有类和结构的指针。它们的用法与基本数据类型的指针完全相同。这就是为什么我们在这里不讨论如何使用它们的原因。我们将专注于函数指针的用法。

函数指针是指向函数的指针。当我们在编译程序时不知道将要调用的函数时,就会使用它们。它们通常用于 GUI 库,在收到特定信号(输入)时执行指定函数。定义函数指针的规则与其他指针相同。然而,声明看起来非常不同。

第十一章:解析(长)指针声明

本章解释了解析指针声明的规则。这些对于函数指针尤其重要。

  1. 从将标识指针的名称开始,这称为标识符。
  2. 向右移动,直到遇到右括号 [符号 = ")" ] 或到达末尾。如果 () 括号用于向函数传递参数,则不要停止。遇到数组括号 [ ] 时也不要停止。
  3. 现在移动到标识符的左侧,继续解析声明。一直向左移动,直到找到左括号 [符号 "(" ] 或到达末尾。如果括号用于向函数传递参数,则不要停止。
  4. 整个解释应该是一个流畅的长句。

以下是一些示例,以便更好地理解该过程:

第十二章:函数指针和 typedef

让我们看一个函数指针的例子。

让我们用 typedef 声明来实现相同的示例来结束。

© . All rights reserved.