指针的性质是理解其行为和使用方式的核心,主要包括以下几个方面:
1. 指针是存储地址的变量
指针的本质是一个变量,但其存储的不是数据本身,而是另一个变量(或内存单元)的内存地址。
- 例如:
int a = 10; int* p = &a;
中,p
存储的是a
的内存地址(如0x7ffd6b6a45c4
),而非10
。
2. 指针具有明确的类型
指针的类型由其指向的数据类型决定(格式为 类型*
),且类型决定了指针的访问规则:
-
步长
:指针的算术运算(
+n
/-n
)的偏移量由类型决定(偏移n × 类型大小
字节)。- 例如:
int*
指针+1
偏移 4 字节(32 位系统),char*
指针+1
偏移 1 字节。
- 例如:
-
解引用权限:解引用(
*p
)时,编译器会根据指针类型解析内存中的数据(如int*
会读取 4 字节作为整数)。
3. 指针的大小与系统位数相关,与指向类型无关
在同一操作系统和架构下,所有指针的大小固定,取决于系统的地址总线宽度:
- 32 位系统:指针大小为 4 字节(可表示地址范围
0~2³²-1
)。 - 64 位系统:指针大小为 8 字节(可表示地址范围
0~2⁶⁴-1
)。 - 例如:
int*
、char*
、double*
在 64 位系统中均占 8 字节。
4. 指针可进行有限的算术运算
指针支持 +
、-
、++
、--
等算术运算,但运算结果与普通数值不同:
- 运算对象只能是整数(表示偏移的元素个数)。
- 结果是 “新的地址”:
p + n
表示指向p
所指元素之后的第n
个同类型元素。 - 不支持
*
、/
等运算(无实际意义)。
5. 指针可指向指针(多级指针)
指针本身也是变量,因此可以有 “指向指针的指针”(二级指针)、“指向二级指针的指针”(三级指针)等,形成多级间接访问:
- 例如:
int a = 10; int* p = &a; int**pp = &p;
中,pp
是二级指针,** pp
等价于a
。 - 用途:在函数中修改指针本身(如动态分配内存时传递指针的地址)。
6. 指针可以为空(NULL)
指针可以被赋值为 NULL
(C 中定义为 (void*)0
,C++11 后推荐 nullptr
),表示不指向任何有效内存:
- 作用:避免 “野指针”(未初始化的指针),是指针初始化的安全选择。
- 注意:对
NULL
指针解引用(*NULL
)会导致程序崩溃(未定义行为)。
7. 指针与数组的关联性
数组名本质是指向首元素的 “常量指针”(不可被重新赋值),因此指针与数组访问可相互替代:
- 数组元素
arr[i]
等价于*(arr + i)
或*(p + i)
(p
是指向数组首元素的指针)。 - 区别:指针是变量(可被赋值),数组名是常量(不可被赋值)。
8. 指针的 const 修饰限制可修改性
const
与指针结合时,会限制指针的 “指向” 或 “指向的数据” 的可修改性:
const int* p
:指向常量的指针,p
可改指向,但不能通过p
修改所指数据。int* const p
:指针常量,p
的指向不可改,但可通过p
修改所指数据。const int* const p
:指向常量的指针常量,两者均不可改。
9. 指针可作为函数参数 / 返回值
- 作为参数:实现 “传地址调用”,允许函数修改外部变量(突破值传递的限制)。
- 作为返回值:可返回动态分配的内存地址或静态变量地址(禁止返回局部变量地址,因其生命周期随函数结束而结束)。
10. 指针可能成为 “野指针”(危险性质)
野指针是指向无效内存的指针(如未初始化的指针、指向已释放内存的指针):
- 危害:解引用野指针可能导致程序崩溃、数据损坏或安全漏洞。
- 避免方式:指针初始化时设为
NULL
;释放内存后及时置空;不返回局部变量地址。
总结:指针的核心性质围绕 “地址存储”“类型关联”“内存操作” 展开,其灵活性和危险性并存,理解这些性质是正确使用指针的基础。