C 语言指针
- 指针的基本概念
- 在C语言中,指针是一种特殊的变量,它存储的是内存地址。通过指针,我们可以直接访问和操作内存中的数据,这为程序提供了更灵活和高效的内存管理方式。
- 每个变量在内存中都有一个地址,指针变量就是用来存储这些地址的。例如,假设有一个整型变量
num,系统会为num分配一块内存空间,这个空间的地址就可以存储在一个指针变量中。
- 指针变量的声明和初始化
- 声明语法:
数据类型 *指针变量名;,这里的数据类型表示指针所指向的数据的类型。例如,int *ptr;声明了一个指向整型数据的指针变量ptr。 - 初始化:在使用指针之前,需要将其初始化为一个有效的内存地址。可以使用取地址运算符
&获取变量的地址来初始化指针。例如:
- 声明语法:
#include <stdio.h>
int main() {
int num = 10;
int *ptr; // 声明一个指向整型的指针
ptr = # // 将指针初始化为变量 num 的地址
return 0;
}
- 在上述代码中,
ptr = #将ptr指向了num的内存地址。此时,ptr就可以用来间接访问num的值。
- 通过指针访问数据
- 可以使用间接访问运算符
*(也称为解引用运算符)通过指针来访问它所指向的变量的值。例如:
- 可以使用间接访问运算符
#include <stdio.h>
int main() {
int num = 10;
int *ptr;
ptr = #
printf("通过指针访问的值: %d\n", *ptr); // 使用解引用运算符访问指针指向的值
return 0;
}
- 在这个例子中,
*ptr表示访问ptr所指向的内存地址中的值,即num的值,所以输出为10。
- 指针的算术运算
- 指针可以进行一些算术运算,如加法、减法。指针的算术运算与它所指向的数据类型的大小相关。例如,一个指向整型的指针加1,实际上是将指针的值增加
sizeof(int)个字节(在大多数系统中,sizeof(int)为4字节)。
- 指针可以进行一些算术运算,如加法、减法。指针的算术运算与它所指向的数据类型的大小相关。例如,一个指向整型的指针加1,实际上是将指针的值增加
#include <stdio.h>
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // 数组名本身就是数组首元素的地址
printf("指针指向的第一个元素: %d\n", *ptr);
ptr++; // 指针移动到下一个元素的地址
printf("指针移动后指向的元素: %d\n", *ptr);
return 0;
}
- 在上述代码中,
ptr初始指向数组arr的首元素。ptr++使ptr指向下一个元素的地址,所以两次输出分别为数组的第一个和第二个元素。
- 指针与数组的关系
- 在C语言中,数组名可以看作是一个常量指针,它指向数组的首元素。例如,
int arr[5];中,arr就等价于&arr[0]。可以通过指针来访问数组元素,并且指针的算术运算在处理数组时非常有用。
- 在C语言中,数组名可以看作是一个常量指针,它指向数组的首元素。例如,
#include <stdio.h>
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, *(ptr + i));
}
return 0;
}
- 在这个循环中,
*(ptr + i)等价于arr[i],通过指针的算术运算依次访问数组的每个元素并输出。
- 多级指针
- 指针变量本身也占用内存空间,所以也有地址。可以定义一个指针来指向另一个指针,这就是多级指针。最常见的是二级指针,声明方式为
数据类型 **指针变量名;。例如:
- 指针变量本身也占用内存空间,所以也有地址。可以定义一个指针来指向另一个指针,这就是多级指针。最常见的是二级指针,声明方式为
#include <stdio.h>
int main() {
int num = 10;
int *ptr1 = #
int **ptr2 = &ptr1;
printf("通过二级指针访问的值: %d\n", **ptr2);
return 0;
}
- 在上述代码中,
ptr1指向num,ptr2指向ptr1。**ptr2先通过ptr2找到ptr1的地址,再通过ptr1找到num的地址,从而访问到num的值。
指针是C语言中一个强大而复杂的特性,熟练掌握指针对于编写高效、灵活的C程序至关重要,但同时也需要小心使用,避免出现指针悬挂、空指针引用等错误。
指针与寻常变量的区别
- 平常变量对内存数据的操作
- 变量的本质:在C语言中,当定义一个变量时,系统会为其分配一块内存空间。例如,定义
int num = 10;,系统会在内存中分配一块适合存储整数的空间,并将10存储在这块空间中。变量名num实际上是这块内存空间的标识符。 - 操作方式:通过变量名来访问和修改这块内存中的数据。如
num = 20;就是将新的值20写入到num所代表的内存空间中。这种操作是直接的,编译器会根据变量的类型和作用域等信息来确定对哪个内存位置进行操作。而且,变量只能访问其自身所占据的内存空间,访问范围有限。
- 变量的本质:在C语言中,当定义一个变量时,系统会为其分配一块内存空间。例如,定义
- 指针对内存数据的操作
- 指针的本质:指针是一种特殊的变量,它存储的是另一个变量的内存地址。例如,
int num = 10; int *ptr = #,这里ptr是一个指针变量,它存储了num变量的内存地址。 - 操作方式:通过指针,我们可以间接访问和修改其他变量的内存数据。例如,
*ptr = 30;这条语句通过ptr指针间接修改了num所占据的内存空间中的值,此时num的值变为30。指针的强大之处在于它的灵活性,它可以通过改变自身存储的地址值,指向不同的内存空间,从而操作不同的变量。比如可以动态分配内存(如使用malloc函数),然后用指针指向这块动态分配的内存进行操作,这在处理不确定大小的数据结构(如链表、动态数组)时非常有用。指针还可以用于数组的操作,通过指针偏移来访问数组中的元素,这比使用数组下标有时更加灵活高效。
- 指针的本质:指针是一种特殊的变量,它存储的是另一个变量的内存地址。例如,
- 两者的区别总结
- 访问方式:平常变量是直接访问内存,而指针是间接访问内存。
- 灵活性:指针可以灵活地指向不同的内存地址,操作不同的变量或内存区域,平常变量只能固定地操作其自身对应的内存空间。
- 使用场景:平常变量适用于简单、直接的数据存储和访问场景;指针则在需要动态内存管理、数据结构构建(如链表、树等)以及函数间复杂数据传递等场景中发挥重要作用。
解引用运算符(*)简要解析
解引用运算符(通常用 * 表示,不同语言语法可能略有差异)是编程中用于访问指针/引用所指向的目标对象的核心运算符,核心作用是“穿透指针/引用,获取其背后的实际数据”。
核心用途
- 访问指针指向的变量值:指针存储的是目标变量的内存地址,
*指针变量可直接读取或修改该地址对应的变量内容; - 访问引用关联的原对象:引用本质是原对象的“别名”,解引用(部分语言可省略显式
*)可操作原对象本身。
简单示例(以C/C++为例)
int a = 10;
int* p = &a; // p是指针,存储a的内存地址(&是取地址运算符)
// 解引用p,获取a的值(输出10)
printf("%d", *p);
// 解引用p,修改a的值(此时a变为20)
*p = 20;
关键注意事项
- 不能对空指针(NULL) 解引用:空指针不指向有效内存,强行解引用会导致程序崩溃;
- 不能对非指针/引用类型解引用:例如直接对普通变量(如
*a,若a不是指针)使用,会编译报错; - 部分语言的简化:Java、Python等无显式指针,引用的“解引用”是隐式的(直接通过引用变量操作原对象);C#中
ref/out参数类似引用,访问时无需显式解引用。
核心逻辑:解引用是“从内存地址到实际数据”的映射操作,是指针/引用类型操作目标数据的关键手段。

浙公网安备 33010602011771号