指针递减赋值后读取值异常的原因及解决办法
问题
尝试在递减指针的同时,为指针指向的地址赋值。赋值时显示值已正确设置,但再次读取时却无法得到正确的值。请问这是什么原因,该如何解决?
以下是尝试的代码:
int a = 0; int* sp = &a; int* start_sp = &a; for (int i = 0; i <= n; i++) { *sp = i; printf("%d, %d\n", *sp, sp); sp--; } sp = start_sp; printf("\n"); for (int i = 0; i <= n; i++) { printf("%d, %d\n", *sp, sp); sp--; }
得到的输出是:
0, 6291028 1, 6291024 2, 6291020 3, 6291016 4, 6291012 0, 6291028 1, 6291024 0, 6291020 6283584, 6291016 0, 6291012
原因与解决方法
核心原因
- 非法访问未分配内存:你仅声明了单个
int变量a,它只占用一块int大小的内存(示例中的6291028)。第一次循环中sp--后,指针指向的是a内存地址之前的区域——这些内存不属于你的程序,要么是未分配的空闲内存,要么被系统/其他程序占用。 - 未定义行为的假象:第一次循环中给非法地址赋值后立刻读取能显示“正确值”,只是因为此时该内存区域还没被其他操作覆盖,但这属于C语言中的未定义行为——标准不保证对非法内存的读写结果,任何后续操作都可能篡改这些数据。
- 内存被后续操作篡改:当程序完成第一个循环、执行重置指针等操作时,系统或程序的其他部分可能已经修改了这些非法内存区域的数据,导致第二次读取时得到错误或随机值。
解决办法
要实现连续的指针读写,必须先分配属于程序的合法内存,有两种常用方式:
1. 使用固定大小数组
如果n是编译时已知的常量,直接声明对应大小的数组:
// 假设n为4,可根据实际需求调整 int n = 4; int arr[n + 1]; // 分配n+1个int的连续内存 int* sp = &arr[n]; // 指向数组末尾,递减时依次填充前面的元素 int* start_sp = sp; for (int i = 0; i <= n; i++) { *sp = i; printf("%d, %p\n", *sp, (void*)sp); // 用%p打印指针是标准做法 sp--; } sp = start_sp; printf("\n"); for (int i = 0; i <= n; i++) { printf("%d, %p\n", *sp, (void*)sp); sp--; }
2. 动态分配内存
如果n是运行时才确定的值,用malloc动态分配内存,记得用完后释放:
int n = 4; // 分配n+1个int的内存,检查分配是否成功 int* arr = (int*)malloc((n + 1) * sizeof(int)); if (arr == NULL) { printf("内存分配失败\n"); return 1; } int* sp = &arr[n]; int* start_sp = sp; // 读写逻辑和数组版本一致 for (int i = 0; i <= n; i++) { *sp = i; printf("%d, %p\n", *sp, (void*)sp); sp--; } sp = start_sp; printf("\n"); for (int i = 0; i <= n; i++) { printf("%d, %p\n", *sp, (void*)sp); sp--; } free(arr); // 释放动态分配的内存,避免内存泄漏
注意:打印指针时必须使用%p格式符,并将指针强制转换为void*,这是C语言标准规定的正确方式,用%d打印指针属于非标准行为,可能导致输出错误。
内容的提问来源于stack exchange,提问作者DaBoat
相关产品推荐
相关产品推荐

