如何使用memcpy()在C语言中将数组复制到另一个数组

6

我正在尝试从另一个数组 a 复制一个数组 (temp)

但是我发现并没有得到想要的结果。

图1

int main()
{
    typedef int arr_1[3];
    arr_1 arr[4];
    arr_1 *temp;
    arr_1 a[3] = {1, 2, 3};
    memset(&temp, 0, sizeof(temp));
    memcpy(temp, a, sizeof(temp));
}

但是当我尝试使用下面这样的简单程序时,

图-2

 main()
    {
    int abc[3], def[3];
    def[3] = {1, 2, 3};
    memcpy(abc, def, sizeof(abc));
    }

对我来说,上面的代码(fig-2)非常好用。 但是fig-1对我来说不起作用。两者几乎相同。 但是为什么fig-1不能工作呢?


5
sizeof(temp) 表示一个指向 int[3] 的指针的大小。 - Daniel Fischer
@所有人:Johnny Mnemonic的提示对我很有用。我只是用temp = (arr_1*)malloc(sizeof(arr_1));替换了memset。然后它就对我起作用了。 - Rasmi Ranjan Nayak
5个回答

9

因为temp不是数组,而是指针,所以sizeof(temp)与数组没有任何关系。

您需要将memcpy更改为使用sizeof(a)。在复制之前,您还需要为temp赋一个合理的值,否则程序会具有未定义的行为。


@AlokSave:Johnny Mnemonic的提示对我很有用。我只是用temp = (arr_1*)malloc(sizeof(arr_1));替换了memset。然后它就对我起作用了。 - Rasmi Ranjan Nayak

5

例如,您必须使用 malloc()temp 分配内存。目前它只是一个未初始化的指针。


4
我知道我来晚了。但是当我读到之前的回答时,我想:“你不需要这些变量。”
以你的简单示例为例:
int abc[3], def[3]; //abs is destination and def is source
def[3] = {1, 2, 3};
memcpy(abc, def, 3*sizeof(int)); //you can do sizeof(int) as you have here an array of int.

但最好使用变量"const int array_size = 3"或者"#define ARRAY_SIZE 3"来定义数组大小。然后您只需要将"3"替换为"ARRAY_SIZE",这样就可以完成相同的工作并避免大小错误。

对于您的实际问题,您可以执行以下操作:

#define ARRAY_SIZE 3

typedef int arr_1[ARRAY_SIZE];
arr_1 arr[ARRAY_SIZE+1];//it is useless here
arr_1 *temp = (arr_1 *) malloc(sizeof(arr_1)); //it is your destination, but you have a pointer of array
arr_1 a[ARRAY_SIZE] = {1, 2, 3};//it is your source

//by doing sizeof((*temp)[0])
//you do not care about the type of you array pointer
//you are sure to take the good size --> it fills your array with 0
memset((*temp), 0, (ARRAY_SIZE+1)*sizeof((*temp)[0])); 

//same logic
//but you destination is (*temp) because you have a pointer of array
//it means that your array arr and a have the same type
memcpy((*temp), a, ARRAY_SIZE * sizeof(a[0]));  

//by the way, the las cell of arr is still 0
//and a pointer is close to an array. If you do "tmp = a;" it works.
//but it is not a copy, you just give the a's reference to tmp

2

前面的回答已经概括如下:

您应该使用大小为sizeof(a)的内存为tmp分配内存。然后使用大小为sizeof(a)memcpy

arr_1 a[3] = {1, 2, 3};
arr_1 *temp = malloc(sizeof(a));
memcpy(temp, a, sizeof(a));

不要忘记在你的程序中使用free(temp);时释放无用的temp


1

您还可以考虑使用助手功能。
请参见提交45ccef8提交60566cb(由René Scharfe(rscharfe于2016年9月25日创建)。
(由Junio C Hamano -- gitster --提交b1f0a85中合并,于2016年10月3日)

它使用COPY_ARRAY,一个安全方便的助手来复制数组,补充ALLOC_ARRAYREALLOC_ARRAY
因此,您可以使用COPY_ARRAY(temp, a, 1);代替memcpy(temp, a, sizeof(a));
用户只需指定源、目标和元素数量;元素大小会自动推断。
它检查大小和元素数量的乘积是否溢出。推断出的大小首先传递给 st_mult,允许在编译时进行除法运算。
作为基本类型安全检查,它确保源和目标元素的大小相同。这也是在编译时评估的。 COPY_ARRAY 用于初始化数组时,如果要复制 0 个元素,则可以安全地将源指针设置为 NULL
在某些情况下,原始的 memcpy(3) 不支持它——编译器可以假设只有有效的指针传递给它,并且可以在此类调用后优化掉 NULL 检查。
#define COPY_ARRAY(dst, src, n) copy_array((dst), (src), (n), sizeof(*(dst)) + \
    BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
static inline void copy_array(void *dst, const void *src, size_t n, size_t size)
{
    if (n)
        memcpy(dst, src, st_mult(size, n));
}

它使用BUILD_ASSERT_OR_ZERO,作为一个表达式(其中@cond是必须为真的编译时条件),断言一个构建时依赖。
如果条件不为真或无法被编译器评估,则编译将失败。
#define BUILD_ASSERT_OR_ZERO(cond) \
(sizeof(char [1 - 2*!(cond)]) - 1)

例子:

#define foo_to_char(foo)                \
     ((char *)(foo)                     \
      + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))

引入了内联函数st_mult,详见提交320d0b4

static inline size_t st_mult(size_t a, size_t b)
{
    if (unsigned_mult_overflows(a, b))
        die("size_t overflow: %"PRIuMAX" * %"PRIuMAX,
            (uintmax_t)a, (uintmax_t)b);
    return a * b;
}

st_mult是检测size_t溢出的辅助函数之一,其中包括unsigned_mult_overflows

对我们提供给xmalloc等函数的size_t变量进行计算可能很危险,因为整数溢出可能导致我们分配比我们意识到的要小得多的块。

我们已经有unsigned_add_overflows(),但让我们添加unsigned_mult_overflows()

/*
 * Returns true if the multiplication of "a" and "b" will
 * overflow. The types of "a" and "b" must match and must be unsigned.
 * Note that this macro evaluates "a" twice!
 */
#define unsigned_mult_overflows(a, b) \
((a) && (b) > maximum_unsigned_value_of_type(a) / (a))

这里使用了maximum_unsigned_value_of_type: 用于检测无符号溢出的辅助工具 (来自提交 1368f6)

表达式(a + b < a)可以很好地检测无符号整数是否溢出,但更明确的方法是

unsigned_add_overflows(a, b)

可能更容易阅读。

定义这样一个宏,大致扩展为 ((a) < UINT_MAX - (b))。 因为该扩展仅在sizeof()表达式之外使用每个参数一次, 所以可以安全地用于具有副作用的参数。

#define bitsizeof(x) (CHAR_BIT * sizeof(x))

#define maximum_unsigned_value_of_type(a) \
(UINTMAX_MAX >> (bitsizeof(uintmax_t) - bitsizeof(a)))

使用CHAR_BIT表示char类型中的位数(与架构有关)


您可以在Git 2.23(2019年第三季度)中看到一个示例。

请参见提交921d49b提交177fbab(2019年6月15日),由René Scharfe(rscharfe提交。
(由Junio C Hamano -- gitster --提交e8d2590中合并,于2019年7月9日)

使用COPY_ARRAY来复制数组

将调用memcpy(3)的代码转换为使用COPY_ARRAY,这可以使代码更加简短和简单。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接