一、变量与指针

在 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**:获取类型或对象占用的字节数。

  • 指针类型:决定如何访问目标数据,以及指针运算的步长。