文章

拷贝函数

拷贝函数

该文记录 C/C++ 基础拷贝函数使用及区别。

拷贝函数

1 strcpy

1
char *strcpy( char *dest, const char *src );

复制 src 所指向的空终止字节字符串,包含空终止符,到首元素为 dest 所指的字符数组。

2 strncpy

1
2
3
4
5
6
7
8
9
10
char *strncpy( char *dest, const char *src, size_t count )
{
  char *start = dest;
  while (count && (*dest++ = *src++))
      count--;
  if (count)
      while (--count)
          *dest++ = '\0';
  return(start);
}

复制 src 所指向的字符数组的至多 count 个字符(包含空终止字符,但不包含后随空字符的任何字符)到 dest 所指向的字符数组。

  • 若在完全复制整个 src 数组前抵达 count ,则结果的字符数组不是空终止的。

  • 若在复制来自 src 的空终止字符后未抵达 count ,则写入额外的空字符到 dest ,直至写入总共 count 个字符。
  • 若字符数组重叠,若 destsrc 不是指向字符数组的指针(包含若 destsrc 为空指针),若 dest 所指向的数组大小小于 count ,或若 src 所指向的数组大小小于 count 且它不含空字符,则行为未定义。

3 memcpy

1
2
3
4
5
6
7
8
9
10
void* memcpy( void *dest, const void *src, size_t count )
{
        void * ret = dest;
        /*
         * copy from lower addresses to higher addresses
         */
        while (count--)
                *dest++ = *src++;
        return(ret);
}

src 所指向的对象复制 count 个字符到 dest 所指向的对象。两个对象都被转译成 unsigned char 的数组。 若访问发生在 dest 数组结尾后则行为未定义。若对象重叠(这违背 restrict 契约) (C99 起),则行为未定义。若 destsrc 为非法或空指针则行为未定义。

4 memmove

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void* memmove( void* dest, const void* src, size_t count )
{
        void * ret = dest;
        if (dest <= src || dest >= (src + count)) {
                /*
                 * Non-Overlapping Buffers
                 * copy from lower addresses to higher addresses
                 */
                while (count--)
                        *dest++ = *src++;
                }
        else {
                /*
                 * Overlapping Buffers
                 * copy from higher addresses to lower addresses
                 */
                dest += count - 1;
                src += count - 1;
                while (count--)
                        *dest-- = *src--;
                }
        return(ret);
}

src 所指向的对象复制 count 个字节到 dest 所指向的对象。两个对象都被转译成 unsigned char 的数组。对象可以重叠:如同复制字符到临时数组,再从该数组到 dest 一般发生复制。若出现 dest 数组末尾后的访问则行为未定义。若 destsrc 为非法或空指针则行为未定义。

5 注意

5.1 memcpy与memmove

memcpy 是从前往后复制,memmove 会判断是否地址覆盖然后选择从前往后复制还是从后往前复制。

  • 情况一:两个不相邻地址。直接使用 memcpy
  • 情况二:相邻地址,目标地址在源地址前面或目标地址在源地址后面相距超过复制长度。使用 memcpy
  • 情况三:相邻地址,目标地址在源地址后面且相距小于复制长度,必须使用 memmove 防止数据覆盖。

参考

[1] https://zh.cppreference.com/w/c/string/byte

[2] memcpy与memmove的区别

本文由作者按照 CC BY 4.0 进行授权