指针
内容简介
指针是保存内存地址的变量。它让程序可以间接访问对象,是理解数组、字符串、函数参数、动态内存、系统接口和底层编程的关键。
本篇只讲主线必会:取地址、解引用、空指针、数组关系、函数参数和常见危险。更细的数组退化、指针运算、二级指针、函数指针、void* 和别名边界见 C语言指针细节、CandCpp指针进阶。
用法
定义、取地址、解引用
#include <stdio.h>
int main(void)
{
int value = 10;
int *p = &value;
printf("%p\n", (void*)p); // value 的地址
printf("%d\n", *p); // 通过地址读取 value
*p = 20; // 通过地址修改 value
printf("%d\n", value);
return 0;
}理解三件事:
&value取变量地址。int *p表示p指向int。*p解引用,访问地址上的int对象。
空指针
int *p = NULL; // C 常见写法int *p = nullptr; // C++ 推荐写法空指针表示“不指向任何有效对象”。空指针可以比较,不能解引用。
指针和数组
int arr[3] = {1, 2, 3};
int *p = arr;
printf("%d\n", *p); // 1
printf("%d\n", *(p + 1)); // 2
printf("%d\n", p[2]); // 3数组名在很多表达式中会退化为首元素地址。完整规则见 C语言指针细节。
指针作函数参数
C 的参数是按值传递。如果要让函数修改调用者的变量,可以传变量地址。
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}调用:
int x = 1;
int y = 2;
swap(&x, &y);函数只读数据时,加 const:
void print_value(const int *p)
{
if (p != NULL) {
printf("%d\n", *p);
}
}最佳代码实践
- 指针定义后立即初始化,不确定指向哪里时设为
NULL或nullptr。 - 解引用前确认指针不是空指针,并确认指向对象仍然活着。
- 数组传参时额外传长度,不要在函数里用
sizeof(arr)猜数组长度。 - 谁申请内存,谁负责释放;释放后不要继续访问旧地址。
- C++ 中优先使用 RAII、智能指针、
std::vector、std::string管理资源。 - 函数只需要读取指针指向的数据时,加
const。
错误用法
空指针解引用
int *p = NULL;
*p = 10; // 错误:空指针不能解引用野指针
int *p;
*p = 10; // 错误:p 没有初始化,指向未知位置内存泄漏
#include <stdlib.h>
int *p = malloc(sizeof(int));
*p = 10;
// 错误:没有 free(p)返回局部变量地址
int* bad(void)
{
int value = 10;
return &value; // 错误:函数结束后 value 生命周期结束
}注意事项
p++改变指针指向的位置,(*p)++改变指针指向的值。- 所有对象指针大小在常见平台上通常相同,因为保存的都是地址;32 位程序常见 4 字节,64 位程序常见 8 字节。
- “地址数值存在”不等于“可以安全访问”,还要看生命周期、类型、对齐和范围。
- C++ 中
nullptr比NULL更安全。 - 指针细节后续连接 CandCpp指针进阶、C语言指针细节、C语言系统栈与过程调用、CandCpp底层知识、RAII 和 智能指针。
学习路径
- 上一节:CandCpp函数
- 当前阶段:CandCPP基础
- 下一节:CandCpp指针进阶