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

使用指针在函数中复制数组仅部分生效,原因是什么?

通用数组复制函数的元素复制问题分析

你尝试实现通用数组复制函数时,遇到了第三个元素未被复制的问题,以下是问题根源和修正方案:

问题代码

#include <stdio.h>

#define ARRAY_LENGTH 3

void *copy_array(const void *arr[], const void *new_arr[], size_t arr_len, size_t type_size) {
    for (int i = 0; i < arr_len ; ++i) {
        *(new_arr + (i * type_size)) = *(arr + (i * type_size));
    }
}

void print_int_array(int * array, int length) {
    for (int i = 0; i < length; ++i) {
        printf("element %d = %d\n", i, array[i]);
    }
}

int main() {
    int arr[ARRAY_LENGTH]     = {12, 3,4};
    int new_arr[ARRAY_LENGTH] = {0, 0, 0};

    print_int_array(arr, ARRAY_LENGTH);
    print_int_array(new_arr, ARRAY_LENGTH);

    copy_array(&arr, &new_arr, ARRAY_LENGTH, sizeof(new_arr[0]));

    print_int_array(arr, ARRAY_LENGTH);
    print_int_array(new_arr, ARRAY_LENGTH);
    return 0;
}

控制台输出

element 0 = 12
element 1 = 3
element 2 = 4
element 0 = 0
element 1 = 0
element 2 = 0
element 0 = 12
element 1 = 3
element 2 = 4
element 0 = 12
element 1 = 3
element 2 = 0

问题根源

  1. 参数类型不匹配
    函数定义的const void *arr[]是指向void指针的数组,但你传入的&arr和&new_arr是数组的地址(类型为int (*)[ARRAY_LENGTH]),类型强制转换后导致后续指针操作完全偏离预期。

  2. 指针运算逻辑错误
    循环中new_arr + (i * type_size)的运算步长是sizeof(void*)(32位系统为4字节,64位为8字节),而非你想要的字节偏移。比如i=1时,1*4=4会让指针直接跳过4个void*的位置,超出目标数组的有效范围。

  3. 赋值逻辑错误
    你试图直接赋值指针地址,但实际需要复制的是数组元素的内容,而非指针本身。


修正方案

重新设计通用数组复制函数,核心是用void*接收数组首地址,通过char*做字节级偏移,确保类型无关的内容复制:

修正后的代码

#include <stdio.h>
#include <string.h>

#define ARRAY_LENGTH 3

// 通用数组复制函数
void copy_array(const void *src, void *dest, size_t arr_len, size_t type_size) {
    // 逐元素复制,用char*实现字节级偏移
    for (size_t i = 0; i < arr_len; ++i) {
        const char *src_elem = (const char*)src + i * type_size;
        char *dest_elem = (char*)dest + i * type_size;
        memcpy(dest_elem, src_elem, type_size);
    }
    // 也可以用memcpy一次性复制整个数组,效率更高:
    // memcpy(dest, src, arr_len * type_size);
}

void print_int_array(int *array, int length) {
    for (int i = 0; i < length; ++i) {
        printf("element %d = %d\n", i, array[i]);
    }
}

int main() {
    int arr[ARRAY_LENGTH]     = {12, 3, 4};
    int new_arr[ARRAY_LENGTH] = {0, 0, 0};

    printf("原数组:\n");
    print_int_array(arr, ARRAY_LENGTH);
    printf("复制前的新数组:\n");
    print_int_array(new_arr, ARRAY_LENGTH);

    // 传入数组首地址(数组名自动退化为指针)
    copy_array(arr, new_arr, ARRAY_LENGTH, sizeof(new_arr[0]));

    printf("复制后的原数组:\n");
    print_int_array(arr, ARRAY_LENGTH);
    printf("复制后的新数组:\n");
    print_int_array(new_arr, ARRAY_LENGTH);
    return 0;
}

关键修正点

  • 将函数参数改为const void *src和void *dest,直接接收数组首地址
  • 通过char*转换实现字节级偏移,确保指针移动符合预期
  • 使用memcpy复制元素内容,保证类型无关的通用性
  • 调用时传入arr和new_arr(数组名自动退化为首元素指针),而非数组的地址&arr/&new_arr

修正后的输出

原数组:
element 0 = 12
element 1 = 3
element 2 = 4
复制前的新数组:
element 0 = 0
element 1 = 0
element 2 = 0
复制后的原数组:
element 0 = 12
element 1 = 3
element 2 = 4
复制后的新数组:
element 0 = 12
element 1 = 3
element 2 = 4

内容的提问来源于stack exchange,提问作者Mads Vind Knudsen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 14:45:39