为何栈上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

