一、变量与指针
在 C 语言中,变量用于存储数据,指针用于存储地址,通过地址可以访问或修改目标对象。
int a = 10;
int *p = &a;
| 表达式 | 含义 | 示例结果 |
|---|---|---|
a | 访问变量的值 | 10 |
&a | 获取变量的地址 | 0x1000 |
p | 获取指针保存的地址 | 0x1000 |
*p | 解引用,访问指向的值 | 10 |
&p | 获取指针变量自身的地址 | 取决于实际地址 |
其中,0x1000 是假设的地址。
指针有两种常见操作:
*p = 20; // 修改指针指向的对象,a 变成 20
p = &b; // 修改指针的指向(假设 b 已定义)
注意:修改指针的指向,不会改变原来指向的变量值。
二、sizeof 的作用
sizeof 是 C 语言运算符,用于获取类型或对象占用的字节数,结果类型为 size_t。
int a = 10;
int *p = &a;
sizeof(a); // 4
sizeof(p); // 8
sizeof(*p); // 4
以上假设 int 占 4 字节,指针占 8 字节。
| 表达式 | 含义 |
|---|---|
sizeof(a) | 变量 a 所占的字节数 |
sizeof(p) | 指针变量自身所占的字节数 |
sizeof(*p) | 指针指向的数据类型所占的字节数 |
需要区分:
*p:访问指向的数据值。sizeof(*p):计算指向的数据类型的大小。
sizeof(char) 恒为 1,但一个字节不一定是 8 位,实际位数由 CHAR_BIT 表示。int 和指针的大小由具体实现决定。
三、数组与指针的区别
int arr[] = {10, 20, 30, 40};
int *p = arr;
假设 int 占 4 字节,指针占 8 字节:
sizeof(arr); // 16,整个数组的大小
sizeof(arr[0]); // 4,单个元素的大小
sizeof(p); // 8,指针自身的大小
arr[0]; // 10,读取第一个元素
p[1]; // 20,读取第二个元素
数组不是指针。 数组存储多个元素,而指针存储指向对象的地址。
数组名在大多数表达式中会转换为指向首元素的指针,但 sizeof(arr) 不会发生这种转换。
数组元素个数可以这样计算:
size_t count = sizeof(arr) / sizeof(arr[0]);
注意:数组作为函数参数传递时,形如 int arr[] 的参数实际被调整为 int *arr,此时 sizeof(arr) 得到的是指针大小。
四、指针运算
指针加 1,并不意味着地址只增加 1 字节,而是移动一个所指向类型的元素大小。
int arr[] = {10, 20, 30, 40};
int *p = arr;
*p; // 10
*(p + 1); // 20
p[2]; // 30
在 int 占 4 字节的平台上,p + 1 通常比 p 的地址前进 4 字节。
指针运算与下标访问的关系:
p[n] == *(p + n)
指针运算必须遵守数组边界规则,不能任意访问内存。
五、常见问题
1. sizeof(char) 一定是多少?
恒为 1。一个 C 字节包含多少 bit 由 CHAR_BIT 决定,至少为 8 bit。
2. 64 位系统的指针一定占 8 字节吗?
不一定。指针大小取决于目标平台、ABI 和编译器实现,不能仅凭 CPU 位数判断。
3. 程序中的地址一定是物理 RAM 地址吗?
不一定。C 语言中的指针值不保证直接等于物理地址。具体取决于处理器架构、内存映射和运行环境。
4. 如何设计跨平台的通信数据包?
使用 uint8_t、uint16_t 等固定宽度类型定义字段,明确字节序和数据布局,并避免直接把存在填充字节的结构体作为通信数据发送。
总结:
变量:保存数据,具有类型、值和存储位置。
指针:保存用于定位目标对象或函数的值。
**&**:获取对象地址。*****:对指针解引用,访问目标对象。**sizeof**:获取类型或对象占用的字节数。指针类型:决定如何访问目标数据,以及指针运算的步长。