You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

执行MemCopy2函数后指针地址为何变化?添加局部变量后地址不变的原因

内存拷贝后指针地址异常的原因解析

问题背景

我编写了MemCopy2函数,用于从内存区域拷贝数据到另一区域,为避免内存重叠,采用从数组高位到低位的顺序拷贝。代码如下:

#include<stdio.h>
#include<stdint.h>
void MemCopy2(uint8_t * Src, uint8_t * Dest, uint32_t Len)
{   
    uint32_t count;

    for (count = Len; count > 0; count--)
    {
        Dest[count-1] = Src[count-1];
    }

}

int main()
{

    uint32_t A[2] = { 0xABCD1234, 0x567890AB };
    uint32_t * Ptr = (uint16_t*)&A + 1;  // CD 
    
    printf("%d \n", Ptr);
    
    MemCopy2((uint8_t*)&A, (uint8_t*)Ptr, sizeof(A));

    printf("%d \n", Ptr);

    return 0;
}

现象描述

执行MemCopy2函数前后打印Ptr的地址,结果为:

6487570 
6444664 

可见Ptr的地址发生了变化。但如果在main函数中数组A初始化前添加局部变量int i=6;,再次执行后打印结果为:

6487554 
6487554 

此时Ptr的地址保持不变。我猜测可能与栈的入栈出栈、局部变量的存储有关,想知道具体原因。

原因分析

核心问题是代码存在内存越界的未定义行为,直接修改了Ptr变量本身,具体细节如下:

  1. 指针计算的偏移逻辑
    代码里uint32_t * Ptr = (uint16_t*)&A + 1;的逻辑是:把数组A的地址强制转为uint16_t*类型后,偏移1个uint16_t的长度(即2字节)。最终Ptr指向的是数组A起始地址+2字节的位置,也就是A[0]的第3、4字节(对应数值0xCD的存储位置)。

  2. 栈布局的差异导致不同结果
    C语言中局部变量存在栈上,栈的增长方向通常是从高地址向低地址:

    • 无int i=6;时,栈的布局大概是[函数返回地址][Ptr变量][数组A](地址从高到低排列)。sizeof(A)是8字节,当执行MemCopy2从A的起始地址拷贝8字节到Ptr指向的位置时,拷贝的范围是A+2到A+10字节——这个范围刚好覆盖了Ptr变量的存储位置,所以拷贝过程中Ptr的值被修改,打印出的地址自然变化。
    • 添加int i=6;后,栈布局变为[函数返回地址][Ptr变量][int i][数组A]。此时拷贝的8字节范围A+2到A+10只会覆盖数组A和变量i的区域,碰不到Ptr的存储位置,所以Ptr的值不会被修改,打印地址保持不变。
  3. 未定义行为的本质
    你的代码中,目标地址Dest和源地址Src存在重叠,且拷贝长度超出了数组A的边界,属于非法的内存越界访问。这种行为在C语言中是未定义的——不同的栈布局、编译器优化都会导致不同的运行结果,这就是为什么添加一个局部变量就会出现完全不同的表现。

内容的提问来源于stack exchange,提问作者Nguyễn Minh Tiến

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 20:48:37