更改指针类型引发写入访问异常,求内存缓冲区写入问题排查
解决缓冲区写入访问异常:指针算术的常见误区
看来你在测试缓冲区边界写入时踩了指针类型的坑——这种问题我见过不少,核心是没搞清楚指针算术是基于指向类型的大小,而不是字节数。先把你的代码补全(推测你原本想写end = start + ...),再一步步分析:
你的原代码(补全推测部分)
#include <Windows.h> #include <stdint.h> int main() { size_t size = 19200; int16_t* start = (int16_t*) VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); // 推测你原本想计算缓冲区末尾指针,但写法错误 int16_t* end = start + size; // 这里就是坑! // 尝试向末尾附近写入 int16_t* ptr = end - 10; // 假设想写末尾前10个元素 for (int i = 0; i < 20; i++) { *(ptr + i) = 0x1234; // 这里可能触发访问异常 } VirtualFree(start, 0, MEM_RELEASE); return 0; }
问题根源:指针算术的类型依赖
当你对int16_t*类型的指针做加减时,编译器会自动乘以sizeof(int16_t)(也就是2)来计算实际字节偏移。比如:
start + size实际计算的是(uint8_t*)start + size * sizeof(int16_t)- 你申请的内存只有19200字节,但这个偏移会达到
19200*2=38400字节,直接超出了申请的内存范围,写入自然会触发访问异常。
正确的缓冲区边界计算方法
有两种可靠的方式来计算缓冲区的末尾指针:
方法1:基于元素个数计算
先算出缓冲区能容纳的int16_t元素总数,再用指针算术:
size_t element_count = size / sizeof(int16_t); // 19200 / 2 = 9600 int16_t* end = start + element_count; // 指向缓冲区末尾的下一个位置(合法的尾后指针)
方法2:用字节指针计算(更直观,适合边界校验)
如果你习惯用字节数来思考,可以先转换成uint8_t*(字节类型指针)计算偏移,再转回来:
uint8_t* start_byte = (uint8_t*)start; uint8_t* end_byte = start_byte + size; int16_t* end = (int16_t*)end_byte; // 注意:VirtualAlloc返回的内存是对齐的,所以转换安全
修正后的完整代码
#include <Windows.h> #include <stdint.h> int main() { size_t size = 19200; int16_t* start = (int16_t*) VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); // 先检查VirtualAlloc是否成功(容易忽略的点!) if (start == NULL) { return GetLastError(); } // 正确计算缓冲区尾后指针 size_t element_count = size / sizeof(int16_t); int16_t* end = start + element_count; // 向末尾前10个位置开始写20个元素(测试边界) int16_t* write_ptr = end - 10; for (int i = 0; i < 20; i++) { // 额外做边界校验,避免溢出(可选但推荐) if (write_ptr + i >= end) { break; // 或者处理溢出逻辑 } *(write_ptr + i) = 0x1234; } VirtualFree(start, 0, MEM_RELEASE); return 0; }
额外提醒
- 永远要检查
VirtualAlloc的返回值,如果内存分配失败,start会是NULL,后续操作直接触发异常。 - 尾后指针(
end = start + element_count)是合法的(可以比较,但不能解引用),用来判断指针是否越界非常方便。
内容的提问来源于stack exchange,提问作者Mknsri
相关产品推荐
相关产品推荐

