C 语言指针详解:概念、原理、运算与实例
1. 指针的特点
指针的优势:
- 高效访问内存数据(间接访问)
- 提供另一种访问变量的方式(通过地址访问)
- 可以直接操作底层硬件(操作寄存器)
- 实现复杂数据结构必备(链表、树、图等)
- 函数参数传递高效(传地址而不是大块数据)
2. 指针与内存地址的概念
内存地址
-
计算机给内存的每个字节都编号,如:
0x0000000012345678 -
本质上是一个 整数
指针变量
用来存储内存地址的变量,就是指针变量。
例如:
int a = 100;
printf("%p\n", &a); // 打印 a 的地址
64 位系统下:
所有指针大小都是:
8 字节(64 bit)
无论它指向 int、char 还是 double。
3. 指针的两个关键运算符:& 和 *
& 取地址运算符
作用:获得变量的内存首地址
int a = 100;
int* p = &a;
注意:
❌ 不能对表达式取地址
❌ 不能对常量取地址
&(a+1) // 错误
&10 // 错误
* 解引用运算符
作用:
- 找到指针存储的地址
- 根据指针的类型读取对应大小的内存数据
- 使用该数据(读或写)
int a = 100;
int* p = &a;
printf("%d\n", *p); // 100
*p = 200; // 修改 a 的值
* 和 & 是互逆的
*p == a
&(*p) == p
*(&a) == a
4. 指针的定义与初始化
基本格式:
基类型 *指针名;
例如:
int* p;
char* cp;
double* dp;
❗ 未初始化的指针 = 野指针(危险)
int *p; // p 内部是垃圾地址
printf("%d\n", *p); // 未定义行为,可能崩溃
正确写法:
int *p = NULL;
int a = 10;
p = &a; // 赋予有效地址后才能解引用
5. 示例:指针基础操作
int a = 100;
printf("&a address %p\n", &a);
printf("sizeof(&a) = %lu\n", sizeof(&a)); // 指针大小=8字节
int* p = &a;
printf("*p = %d\n", *p);
*p = 200; // 修改 a 的值
6. 指针与数组
数组名可以看作数组首地址:
int b[5] = {1,2,3,4,5};
int* p = b; // 等价于 p = &b[0]
指针访问数组元素:
*(p+0) == b[0]
*(p+1) == b[1]
*(p+2) == b[2]
这是因为:
p + 1 = p 的地址 + sizeof(int)
7. 指针算术运算
指针 + 1
不是加 1
是加 一个基类型大小:
如 int = 4 字节:
p + 1 = p 地址 + 4
示例:
int a = 100;
int *p = &a;
printf("%p\n", p);
printf("%p\n", p + 1);
8. 指针遍历数组
方法 1:不改变指针本身
for(int i=0;i<5;i++)
{
printf("%d\n", *(p+i));
}
方法 2:使用 p++(会改变 p 的位置)
for(int i=0;i<5;i++)
{
printf("%d\n", *(p++));
}
循环后 p 指向:
b[5](越界位置)
9. 指针相减
两个指针相减,得到的是:
两个指针之间相差的“元素个数”
示例:
int b[5]={1,2,3,4,5};
int* p = b;
int* q = &b[2];
printf("q - p = %ld\n", q - p); // 2
10. 今日代码总结
打印地址并解引用
int a = 100;
int* p = &a;
printf("%p %d\n", p, *p);
野指针示例(错误用法)
int *p;
printf("%d\n", *p); // 未定义行为
指针访问数组
int b[5] = {1,2,3,4,5};
int *p = b;
for(i=0;i<5;i++)
printf("%d %d\n", i, *(p+i));
指针自增
for(i=0;i<5;i++)
printf("%d %d\n",i,*(p++));

被折叠的 条评论
为什么被折叠?



