【问题标题】:How to copy arrray to array using memcpy() in C如何在 C 中使用 memcpy() 将数组复制到数组
【发布时间】:2013-03-28 15:04:01
【问题描述】:

我正在尝试从另一个数组 a 复制一个数组 (temp)。 但我有它没有发生。

Fig-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));
}

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

Fig-2

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

上面的代码(fig-2) 对我来说真的很好用。 但是fig-1 不适合我。两者几乎相同。 但是为什么fig-1 不起作用??

【问题讨论】:

  • sizeof(temp) 是指针的大小(指向int[3])。
  • @All:Johnny Mnemonic 技巧对我有用。我刚刚用temp = (arr_1*)malloc(sizeof(arr_1)); 替换了memset。它对我有用

标签: c


【解决方案1】:

因为temp 不是数组,它是一个指针,因此sizeof(temp) 与数组完全没有关系。

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

【讨论】:

  • @AlokSave:Johnny Mnemonic 技巧对我有用。我刚刚用temp = (arr_1*)malloc(sizeof(arr_1)); 替换了memset。它对我有用
【解决方案2】:

您必须为temp 分配内存,例如malloc()。现在它只是一个未初始化的指针。

【讨论】:

    【解决方案3】:

    我知道,我迟到了。但是当我阅读以前的答案时,我认为“你不需要所有这些变量”

    使用您的简单示例:

    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
    

    【讨论】:

      【解决方案4】:

      作为之前答案的总结:

      您应该为 tmp 分配内存,大小 = sizeof(a)。然后memcpy 大小 = sizeof(a)

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

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

      【讨论】:

        【解决方案5】:

        您还可以考虑使用辅助函数。
        请参阅commit 45ccef8commit 60566cb(2016 年 9 月 25 日)René Scharfe (rscharfe)
        (由 Junio C Hamano -- gitster -- 合并到 commit b1f0a85,2016 年 10 月 3 日)

        它使用COPY_ARRAY, a safe and convenient helper 来复制数组, 补充ALLOC_ARRAYREALLOC_ARRAY

        因此,您可以使用COPY_ARRAY(temp, a, 1);,而不是memcpy(temp, a, sizeof(a));

        用户只需指定来源、目的地和元素数量;自动推断元素的大小。

        它检查大小和元素计数的乘积是否溢出。
        推断的大小首先传递给st_mult,它允许除法 在编译时完成。

        作为基本的类型安全检查,它确保源的大小和 目标元素是相同的。这是在编译时评估的 也是。

        COPY_ARRAY 可以安全地使用NULL 作为源指针,如果 0 个元素是 被复制。
        该约定在某些情况下用于初始化数组。
        Raw 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));
        }
        

        它使用声明构建时依赖关系的macro 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))
        

        The inline function st_multcommit 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: helper for detecting unsigned overflow(来自commit 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 being the number of bits in char(取决于架构)


        您可以查看 Git 2.23(2019 年第三季度)的示例

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

        使用COPY_ARRAY 复制数组

        memcpy(3) 的调用转换为使用COPY_ARRAY,这样可以缩短和 稍微简化了代码。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-07-13
          • 2017-11-13
          • 2020-04-22
          • 2020-02-24
          • 2020-04-02
          • 2023-02-09
          • 2015-06-05
          • 1970-01-01
          相关资源
          最近更新 更多