Contents

C指针越界

指针越界

在 C 语言中,指针越界是指针指向了其合法访问范围之外的内存地址,这种行为会导致未定义行为(Undefined Behavior, UB),是 C 语言中最常见也最危险的错误之一。 示例代码如下

#include <stdio.h>
#include <stdlib.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5}; // 数组arr有5个元素,索引0~4
    int *ptr = arr; // ptr初始指向arr[0](合法范围的起点)
    
    // 标准C中允许的不安全操作
    ptr += 10;  // 越界指针操作 ptr现在指向arr[0]往后第10个int的位置(远超范围)
    printf("Value: %d\n", *ptr);  // 未定义行为
    
    return 0;
}

1. 什么是指针越界?

指针的 “合法访问范围” 通常与它所指向的内存块相关(如数组、动态分配的内存等)。当指针通过算术运算(如+-)或直接赋值,指向了该内存块之外的地址时,就发生了 “指针越界”。

2. 指针越界本质:内存访问范围超限

C 语言中,数组的内存是连续分配的。对于int arr[5],其占用的内存范围是: &arr[0](首地址) 到 &arr[4](最后一个元素地址)。

指针ptr的合法访问范围本应限定在这个区间内。当ptr += 10后,ptr指向的地址已经超出了arr所占用的内存范围,此时ptr成为 “越界指针”。

3. 越界指针解引用的危害(未定义行为)

C 语言标准不要求编译器检查指针是否越界,也不定义越界后解引用(如*ptr)的行为。这意味着:运行结果完全不可预测,可能出现多种情况:

  1. 输出 “垃圾值” 越界指针可能指向一块未被使用的内存(如栈上的 “空闲区域”),此时*ptr会读取到该区域的随机数据(之前程序遗留的脏数据)。
  2. 修改其他变量的值 :若越界指针指向了其他变量的内存地址,对其赋值(如*ptr = 100)会意外修改该变量的值,导致程序逻辑混乱。
  3. 程序崩溃(段错误):若越界指针指向了操作系统保护的内存区域(如内核空间、未分配的虚拟内存),解引用时会触发 “段错误(Segmentation Fault)”,程序直接终止。
  4. “看似正常” 的假象

4. 常见指针越界场景

除了示例中的 “指针算术越界”,还有以下常见情况:

  1. 数组索引越界

    数组访问本质是指针算术(arr[i]等价于*(arr + i)),因此arr[10](对于arr[5])也是一种指针越界。

  2. 动态内存越界

    使用malloc/calloc分配内存后,指针超出分配的大小:

int *ptr = malloc(5 * sizeof(int)); // 分配5个int的空间
ptr[5] = 10; // 越界(合法索引0~4)
  1. 指针指向已释放的内存(野指针):

    内存被free后,指针未置空,继续使用也可能导致越界(该内存可能已被系统分配给其他变量):

int *ptr = malloc(4);
free(ptr); // 内存释放后,ptr变为野指针
*ptr = 10; // 越界(访问已释放的内存)

5. 如何避免指针越界?

  1. 明确内存范围:始终记录指针指向的内存块大小(如数组长度、动态分配的字节数)。
  2. 访问前检查:通过条件判断限制指针访问范围(如if (i < 5) { arr[i] = ... })。
  3. 使用工具检测:借助编译器(如gcc -fsanitize=address)、静态分析工具(如 Clang Static Analyzer)或调试器(如 GDB)检测越界行为。

总结:指针越界的核心问题是 “访问了不属于自己的内存”,其后果完全不可控。在 C 语言中,程序员必须主动保证指针操作在合法范围内,这是写出可靠 C 程序的基础。