编程嵌入式开发工程师

请谈谈C语言中指针算术的工作机制:地址是如何计算的,类型的大小如何影响运算结果,以及在处理不同类型指针时会出现哪些细微问题?

用 Hintsage AI 助手通过面试

答案。

指针算术是C语言的一项基本特性,使得内存操作灵活,但也潜在危险。

问题背景

指针算术源于低级语言的特性,旨在直接处理数组和结构化数据。C中的所有指针都“知道”它们指向的类型的大小。

问题

许多开发者错误地认为,将1加到指针上时,地址只会增加1个字节。实际上,增加的量是sizeof(类型)。在处理不同数据类型时,尤其是不同大小的结构体,容易在内存访问时出错。同时,指针算术与void*是不可进行的——这是一个常见错误。

解决方案

所有指针的算术操作都考虑到对应类型的大小,从而使对数组的操作高效。例如:

#include <stdio.h> int arr[4] = {10, 20, 30, 40}; int *p = arr; printf("%d\n", *(p + 2)); // 输出30

这里的(p + 2)将指针向前移动2 * sizeof(int)个字节,而不仅仅是2个字节。

关键特点:

  • 当向指针添加数字时,该数字会乘以类型的大小。
  • 指针相减会确定两者之间的元素数量,而不是字节数。
  • 对void指针和不兼容类型的指针进行算术运算是不可行的。

迷惑性问题。

可以对void指针执行递增/递减操作吗?

不可以,C标准禁止与void进行算术运算。必须先将指针转换为具体类型,例如(char),然后再进行算术运算。

void *vp = arr; char *cp = (char *)vp; cp++;

如果将超过数组大小的值加到指向结构或数组的指针上,会发生什么?

这将导致超出有效内存范围(未定义行为)。C不会检查数组边界——这由程序员负责。

可以直接将两个指针相加吗?

不可以,指针相加是禁止的,且没有意义。仅允许减去属于同一个数组的两个指针。

常见错误和反模式

  • 由于计算指针错误而超出数组边界。
  • 对void*进行算术运算而未转换为其他类型。
  • 不理解按字节增加和按类型大小增加之间的区别。

实际案例

负面案例

一位年轻开发者在处理int数组的指针时,以固定字节数移动指针,忘记了类型大小。

优点:

  • 实现快速。

缺点:

  • 由于访问错误地址和破坏内存,程序崩溃。

正面案例

一位经验丰富的开发者总是使用(ptr + n)这样的表达式,依赖编译器根据类型大小进行缩放。

优点:

  • 程序稳定且可移植(元素大小可能变化)。

缺点:

  • 需要理解和记住指针算术的工作原理。