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

为何栈上int数组交换内存地址仅部分生效?malloc版却正常?

栈数组与动态数组交换地址的差异问题解析

问题描述

出于学习目的,尝试使用数组指针交换两个整数数组的内存地址,但遇到奇怪问题:创建栈上int数组(int fArr[size])并通过swapArr函数交换时,仅一半元素发生变化;改为动态分配(int *fArr = malloc(sizeof(int) * size))后,交换完全正常。请问这是为什么?将&int[]强制转换为int**是否会引发问题?

相关代码

int main(void) {
    ...

    int fArr[size];
    int sArr[size];
    initArr(fArr, sArr, size);
    
    ...

    swapArr((int **)&fArr, (int **)&sArr, size);
}

void initArr(int fArr[], int sArr[], size_t size) {
    srand(time(NULL));
    for (size_t i = 0; i < size; i++) {
        fArr[i] = rand() % 1000;
        sArr[i] = rand() % 1000;
    }
}

void swapArr(int **fArr, int **sArr, size_t size) {
    int *temp = *fArr;
    *fArr = *sArr;
    *sArr = temp;
}

运行输出

Array : 0x7ffcdb611cf0
521, 210, 426, 263

Array : 0x7ffcdb611ce0
553, 314, 17, 16

------- After Swap -------

Array : 0x7ffcdb611cf0
553, 314, 426, 263

Array : 0x7ffcdb611ce0
521, 210, 17, 16

原因解析

1. 栈数组的本质与类型不匹配问题

栈上的数组fArr是数组类型(int[size]),而非指针类型。&fArr的实际类型是int(*)[size](指向size个int的数组指针),但你强制转换成了int**(指向int指针的指针),这是典型的类型不匹配,会触发未定义行为。

2. 为什么仅一半元素变化?

以size=4、64位系统(指针占8字节)、int占4字节为例:栈上的fArr和sArr是连续分配的内存块,每个占16字节。当你执行*fArr = *sArr时,由于*fArr被当作int*(从int**解引用),实际是把sArr的首地址(8字节)写入到fArr的起始位置——这会覆盖fArr的前2个int元素。同理,*sArr = temp会把原fArr的首地址写入sArr的起始位置,覆盖sArr的前2个int元素,最终表现为前两个元素“交换”,后两个保持不变。

3. 动态数组为何正常?

动态分配的int *fArr本身就是指针类型,存储的是堆内存的首地址。&fArr的类型是int**,和swapArr的参数类型完全匹配,此时执行swapArr里的指针交换操作,本质是交换两个指针变量的值,让它们指向对方的堆内存块,所以整个数组都会被“交换”(实际是指针指向变更),表现完全正常。

4. 正确的栈数组交换方式

栈数组的地址是编译期确定的,无法修改。如果要交换栈数组的内容,需要逐个元素交换,或者用memcpy整体复制:

void swapArrContent(int fArr[], int sArr[], size_t size) {
    int temp[size];
    memcpy(temp, fArr, sizeof(int)*size);
    memcpy(fArr, sArr, sizeof(int)*size);
    memcpy(sArr, temp, sizeof(int)*size);
}

内容的提问来源于stack exchange,提问作者yusfux

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 04:20:28