地址 = 指针,指针变量 = 存储指针的变量。
int a = 10; // 定义变量a,在内存中占4个字节(int类型)
int* pa = &a; // pa是指针变量,存储a的首字节地址(&a取a的地址)
*pa = 20; // 通过指针pa找到a的内存单元,修改值为20(*是解引用操作符)
pa
:指针变量(存放地址的变量),简称 “指针”。*pa
:通过指针访问内存中的数据,类似 “按门牌号打开抽屉”。指针类型(如int*
、char*
)决定了两件大事:
int a = 0x11223344; // a的内存数据(4字节):0x11 0x22 0x33 0x44(小端模式)
int* p1 = &a; // int*指针,解引用时操作4字节
char* p2 = &a; // char*指针,解引用时操作1字节
*p1 = 0x00000000; // 整个a被赋值为0(修改4字节)
*p2 = 0x55; // 仅修改a的第一个字节为0x55(a变为0x55223344)
int*
能一次操作 4 字节,char*
只能操作 1 字节,类型决定解引用的 “权限范围”。int arr[3] = {1, 2, 3};
int* p_int = arr; // p_int指向arr[0],地址假设为0x1000
char* p_char = (char*)arr; // p_char指向arr[0],地址0x1000
p_int++; // 地址变为0x1004(int占4字节,+1走4字节)
p_char++; // 地址变为0x1001(char占1字节,+1走1字节)
printf("int指针地址:%p\n", (void*)p_int); // 输出:0x1004(指向arr[1])
printf("char指针地址:%p\n", (void*)p_char); // 输出:0x1001(指向arr[0]的第二个字节)
int*
+1 跳 4 字节,char*
+1 跳 1 字节)。int* p; // 危险!p未初始化,是野指针(指向随机地址)
*p = 10; // 解引用野指针,可能导致程序崩溃
✅ 正确做法:指针定义时要么指向合法地址,要么置空:
int a = 10;
int* p = &a; // 指向合法变量
// 或
int* p = NULL; // 置空指针(NULL表示空地址)
char a = 'A'; // a占1字节
int* p = &a; // 危险!用int*指针指向char变量
*p = 0x1234; // 试图修改4字节,但a只占1字节,导致内存越界
✅ 原则:指针类型要与指向的数据类型匹配,避免越权操作。
printf("int*大小:%d\n", sizeof(int*)); // 输出:4(32位平台)
printf("char*大小:%d\n", sizeof(char*)); // 输出:4(32位平台)
✅ 真相:所有指针变量的大小只由平台决定(32 位 4 字节,64 位 8 字节),与类型无关!
#include
int main() {
// 1. 定义变量和指针
int num = 100; // 普通变量
int* ptr = # // 指针指向num的地址
// 2. 通过指针修改值
printf("修改前:%d\n", num); // 输出:100
*ptr = 200; // 解引用指针,修改num的值
printf("修改后:%d\n", num); // 输出:200
// 3. 指针大小验证
printf("指针大小(32位平台):%d字节\n", sizeof(ptr)); // 输出:4
// 4. 指针步长演示
int arr[2] = {1, 2};
int* p_arr = arr;
printf("p_arr+1地址:%p\n", (void*)(p_arr + 1)); // 地址增加4字节(int大小)
return 0;
}
概念 | 说明 |
---|---|
指针 | 内存单元的地址(相当于 “门牌号”) |
指针变量 | 存储地址的变量,大小由平台决定(32 位 4 字节,64 位 8 字节) |
解引用 | *指针 表示通过地址访问数据,权限由指针类型决定(如int* 操作 4 字节) |
指针步长 | 指针 + 1 的跨度等于指向类型的大小(char* +1 跳 1 字节,int* +1 跳 4 字节) |
易错点 | 未初始化指针(野指针)、类型不匹配、误解指针大小 |
printf("%p", &变量)
打印地址,观察指针移动时的变化规律。掌握指针,就像掌握了直接操作内存的 “钥匙”,是 C 语言进阶的关键!动手试试代码,你会发现指针其实没那么难~ ️