如何在C语言中使用指针?

2025年3月17日 | 阅读 8 分钟

指针就像普通变量一样,但它们存储的是另一个变量或另一个指针的地址,而不是变量的值。指针可以存储不同数据类型的变量的地址——整数、字符,甚至是数组。当一个指针存储了一个变量的地址时,我们就说这个指针指向该变量。本文将为初学者讲解指针的基础知识。

语法

要点理解

  • * -> 解引用运算符 -> 表示“值在此”。
  • & -> 地址运算符 -> 表示“地址在此”
  • "*" 给出指针所指向变量中存储的值。使用"&" 给出变量或指针的地址。
  • 变量或实体的地址取决于操作系统或机器。除非它在数组中且已知基地址和数据类型,否则我们无法预测实体的地址。
How to use Pointers in C language

示例

这里,p 是一个整数数据类型的指针。

  • 特定数据类型的指针只能存储该数据类型实体的地址。如果我们尝试存储另一个数据类型变量的地址,它会发出警告。

示例

警告

warning: assignment to 'int *' from incompatible pointer type 'float *

要点

  1. 指针总是存储整数,因为它们存储的是地址,而地址不能为负数或分数。
  2. 指针总是被初始化为null,而null指针的值为0。
    int *p = null;
    然后,我们赋予它想要的地址,以便没有混淆,因为声明的变量总是需要初始化为0,指针也是如此。
  3. 在这里,如果一个指针被初始化为NULL,它就不指向任何实体。

简单的示例程序

输出

Value of  b =50
Address of  b =6487572
Address of  ptr =6487576
Value of  ptr =50
The pointer stores =6487572

正如你所见,b 的值和 *ptr 的值是相同的,因为 ptr 存储的是 b 的值。变量 b 的地址与指针中的值相同。指针本身的地址是独立的。

How to use Pointers in C language

引用和解引用运算符

引用:使用"&"获取实体的地址。

解引用使用运算符"*"访问指针中的值。

  • 因此,"&"和"*"也称为引用和解引用运算符。
How to use Pointers in C language

指针算术

假设一个整数指针指向地址为500的变量

表达求值
ptr = ptr + 1ptr = 500 + 1*4 = 504
ptr++ 或 ++ptr504 + 1*4 = 508
ptr = ptr + 4508 + 4*4 = 524
ptr = ptr - 2524 - 2*4 = 516
ptr -- 或 --ptr516 - 1*4 = 512

请记住,4是整数数据类型的大小。

另一个例子

代码

输出

How to use Pointers in C language

指向指针的指针

如定义中所述,指针可以存储另一个指针的地址,这时它被称为双指针。它也称为指针的指针。

How to use Pointers in C language

语法

示例程序

输出

a = 65
address of a = 6487572
ptr1 = 6487572
address ptr1 = 6487560
*ptr1 = 65
ptr2 = 6487560
*ptr2 = 6487572
**ptr2 = 65

指向数组的指针

  • 对于数组,数组的基地址是存储第一个元素(索引为0)的地址。
  • 当我们声明一个数组时,编译器会分配内存来包含所有数组元素并给出基地址。
How to use Pointers in C language

这里,ptr 是指向数组第一个元素 (arr[0]) 的指针

要点理解

对于一个数组

int arr[4],一个指针 ptr 指向 arr[0],那么

  • &arr[0] 等同于 ptr。
  • arr[0] 等同于 *ptr。
  • &arr[1] 等同于 ptr+1,而 arr[1] 等同于 *(ptr+1)。
  • &arr[2] 等同于 ptr+2,而 arr[2] 等同于 *(ptr+2)。
How to use Pointers in C language

示例程序

输出

Enter 6 numbers: 2 3 4 5 6
0
Sum = 20

理解

这里,x[6] 是数组,默认情况下 x 是指向其基地址的指针。因此,正如上面提到的,我们可以说 x+i 而不是 x[i]。

使用我们自己的数组指针

输出

*ptr = 3
*(ptr+1) = 4
*(ptr-1) = 2

指针作为函数参数

前提:值传递(函数)

要将参数从函数调用传递到函数声明,我们可以使用值传递(传递值),这是第二种也是更有效的方法——引用传递,我们传递地址给指针。

示例程序

输出

a = 10
b = 20

*m and *n = 10 and 20
Now, *m = 20 and *n = 10

After Swapping:

a = 20
b = 10

理解

这里,我们定义了一个名为“swap”的函数来交换两个变量“a”和“b”的值。我们将“a”和“b”的值分别设为10和20。我们使用两个指针 *m 和 *n 定义了函数。现在,我们将这两个参数的地址传递给指针参数。因此,在函数调用中,我们将“&a”和“&b”传递给声明中的 *m 和 *n。现在,我们使用指针的“* (值在此)”来交换值。

  • 如果我们使用“值传递”,对引用变量(参数)所做的任何更改都不会影响原始变量(实参)。
  • 但是,当我们使用“引用传递”时,对引用变量所做的任何更改都会影响原始变量。

这可以在函数声明中观察到。“a”和“b”的值会随着 *m 和 *n 的值一起被修改。

指向结构的指针

前提:C 语言中的结构

当我们想使用变量访问结构中的成员时,我们使用“.”运算符。

如果我们声明一个结构类型的指针,那么我们使用“->”运算符来访问结构的成员。

示例

此处,

employeePtr -> age 等同于 (*employeePtr).age

employeePtr -> weight 等同于 (*employeePtr).weight

示例程序

输出

NAME: Rishab
NUMBER: 100
RANK: 1

自引用结构

这些是包含一个或多个指向自身结构作为其成员的指针的结构。

How to use Pointers in C language

为了更清楚地说明,指向相同类型结构的结构是“自引用结构”。

示例程序

输出

30
40

指针的特点

  1. 节省内存空间
  2. 执行时间更快,因为直接访问值的内存地址。
  3. 有助于表示多维数组和其他数据结构
  4. 用于文件处理
  5. 高效访问内存 - 动态内存分配。

关于指针的面试题

1. 你认为这个程序的输出是什么?

解决方案

执行时,此程序会产生编译错误。

error: invalid use of void expression

这是因为“vptr”是一个 void 指针。Void 指针不能被解引用。如果我们要解引用,我们需要先进行类型转换。

Void 指针:没有与之关联的数据类型的指针。

2. 这个程序的输出是什么?

答案

这里,变量 k 是一个指向“i”的双指针。但是,k 被递增了。递增后,最终值是某个垃圾值,不是任何其他变量的地址。因此,这可能会导致分段错误或打印出垃圾值。

3. 这个程序的输出会是什么?

答案

这里,指针 j 指向 i。但是,在下一步,j 被递增了。现在,j 既没有地址也没有值。相反,它存储着一个垃圾值,因为我们没有为变量“i”地址旁边的地址初始化任何内容。

4. 值传递和引用传递之间有什么区别?

序号传值调用按引用调用
1.在函数声明的参数中会为函数调用中的实参创建副本,并传递值。这里,实参的地址被传递给函数声明中的指针形参,因此传递的是值。
2.函数中的更改仅限于函数本身。实参的值不会改变。通过函数内的修改,实参和引用形参都会被修改。
3.实参和形参属于不同的内存位置实参和形参在相同的内存空间中创建

5. 指针在任何编程语言中最显著的用途是什么?

答案:指针在许多场景下都有用途。但在此众多用途中,一些显著的用途包括:

  1. 用于实现动态内存分配。
  2. 用于实现不同的数据结构。
  3. 用于执行系统级编程。
  4. 用于实现引用传递
  5. 用于访问数组元素,无需复杂的语法和混淆。