strcpy, strncpy, strlcpy的区别

strcpystrncpystrlcpy都是C语言中的字符串复制函数,但它们在处理字符串时有一些重要的区别:

  1. strcpy: strcpy函数会将源字符串(src)中的字符复制到目标字符串(dest)中,直到遇到源字符串的结束符’’。如果目标字符串的空间不足以容纳源字符串,就会导致缓冲区溢出。

  2. strncpy: strncpy函数会将源字符串(src)中的字符复制到目标字符串(dest)中,最多复制n个字符。当src的长度小于n时,dest的剩余部分将用空字节填充。但是,如果n大于src的长度,strncpy不会在dest的末尾添加’’结束符,这可能会导致问题。

当src的长度小于n时,strncpy会将src的所有字符复制到dest,然后在dest的剩余部分用空字节(‘’)填充,直到复制了n个字符。这意味着如果src的长度小于n,dest字符串将以’’结束。
然而,如果n大于或等于src的长度,strncpy会将src的所有字符复制到dest,但不会在dest的末尾添加’’结束符。这可能会导致问题,因为如果后续的代码试图访问dest作为一个以’’结束的字符串,可能会导致读取未初始化的内存或超出dest的边界。

  1. strlcpy: strlcpy函数是strcpy函数的一个更安全的版本。在已知目标地址空间大小的情况下,strlcpy会将源字符串(src)中的字符复制到目标字符串(dest)中,最多复制dsize-1个字符,并在复制结束后在目标字符串的末尾添加’’结束符。这样可以防止缓冲区溢出。

这是一个strlcpystrncpy的使用示例:

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

int main () {
    char buf[5];
    char src[10] = "12345678";

    // 使用strlcpy
    strlcpy(buf, src, sizeof(buf));
    printf("%s
", buf); // 输出1234

    // 使用strncpy
    strncpy(buf, src, sizeof(buf));
    printf("%s
", buf); // 输出12345,没有以结束字符结尾

    return 0;
}

在这个示例中,使用strlcpybuf字符串的最终结果是"1234",以结束字符结尾。而使用strncpybuf字符串的最终结果是"12345",并没有以结束字符结尾。

总的来说,strlcpy提供了一种更安全的方式来复制字符串,可以有效防止缓冲区溢出的问题。


这些函数的原型如下:

  1. strcpy:
#include <string.h>
char *strcpy(char *dest, const char *src);

其中,dest是目标字符串指针,src是源字符串指针。strcpy函数会将src所指的由NULL结束的字符串复制到dest所指的数组中,返回指向dest字符串的起始地址。

  1. strncpy:
#include <string.h>
char *strncpy(char *dest, const char *src, size_t n);

其中,dest是目标字符串指针,src是源字符串指针,n是要复制的字符个数。strncpy函数会将srcn个字符拷贝到dest。当src的长度小于n时,dest的剩余部分将用空字节填充。但是,如果n大于src的长度,strncpy不会在dest的末尾添加’’结束符。

  1. strlcpy:
#include <string.h>
size_t strlcpy(char *dest, const char *src, size_t dsize);

其中,dest是目标字符串指针,src是源字符串指针,dsize是目标地址空间大小。strlcpy会将src中的字符复制到dest中,最多复制dsize-1个字符,并在复制结束后在dest的末尾添加’’结束符。

请注意,这些函数在使用时需要确保目标字符串有足够的空间来存放源字符串,以防止缓冲区溢出。


参考NuttX的代码如下:

FAR char *strcpy(FAR char *dest, FAR const char *src)
{
  FAR char *tmp = dest;
  while ((*dest++ = *src++) != '');
  return tmp;
}

FAR char *strncpy(FAR char *dest, FAR const char *src, size_t n)
{
  FAR char *ret = dest;     /* Value to be returned */
  FAR char *end = dest + n; /* End of dest buffer + 1 byte */

  /* Copy up n bytes, breaking out of the loop early if a NUL terminator is
   * encountered.
   */

  while ((dest != end) && (*dest++ = *src++) != '')
    {
    }

  /* Note that there may be no NUL terminator in 'dest' */

  /* Pad the remainder of the array pointer to 'dest' with NULs */

  while (dest != end)
    {
      *dest++ = '';
    }

  return ret;
}

size_t strlcpy(FAR char *dst, FAR const char *src, size_t dsize)
{
  FAR const char *osrc = src;
  size_t nleft = dsize;

  if (nleft != 0)
    {
      while (--nleft != 0)
        {
          if ((*dst++ = *src++) == '')
            {
              break;
            }
        }
    }

  if (nleft == 0)
    {
      if (dsize != 0)
        {
          *dst = '';
        }

      while (*src++ != '');
    }

  return src - osrc - 1;
}