strcpy
,strncpy
和strlcpy
都是C语言中的字符串复制函数,但它们在处理字符串时有一些重要的区别:
-
strcpy:
strcpy
函数会将源字符串(src)中的字符复制到目标字符串(dest)中,直到遇到源字符串的结束符’\0’。如果目标字符串的空间不足以容纳源字符串,就会导致缓冲区溢出。 -
strncpy:
strncpy
函数会将源字符串(src)中的字符复制到目标字符串(dest)中,最多复制n
个字符。当src
的长度小于n
时,dest
的剩余部分将用空字节填充。但是,如果n
大于src
的长度,strncpy
不会在dest
的末尾添加’\0’结束符,这可能会导致问题。
当src的长度小于n时,strncpy会将src的所有字符复制到dest,然后在dest的剩余部分用空字节(‘\0’)填充,直到复制了n个字符。这意味着如果src的长度小于n,dest字符串将以’\0’结束。
然而,如果n大于或等于src的长度,strncpy会将src的所有字符复制到dest,但不会在dest的末尾添加’\0’结束符。这可能会导致问题,因为如果后续的代码试图访问dest作为一个以’\0’结束的字符串,可能会导致读取未初始化的内存或超出dest的边界。
- strlcpy:
strlcpy
函数是strcpy
函数的一个更安全的版本。在已知目标地址空间大小的情况下,strlcpy
会将源字符串(src)中的字符复制到目标字符串(dest)中,最多复制dsize-1
个字符,并在复制结束后在目标字符串的末尾添加’\0’结束符。这样可以防止缓冲区溢出。
这是一个strlcpy
和strncpy
的使用示例:
#include <string.h>
#include <stdio.h>
int main () {
char buf[5];
char src[10] = "12345678";
// 使用strlcpy
strlcpy(buf, src, sizeof(buf));
printf("%s\n", buf); // 输出1234
// 使用strncpy
strncpy(buf, src, sizeof(buf));
printf("%s\n", buf); // 输出12345,没有以结束字符结尾
return 0;
}
在这个示例中,使用strlcpy
的buf
字符串的最终结果是"1234\0",以结束字符结尾。而使用strncpy
的buf
字符串的最终结果是"12345",并没有以结束字符结尾。
总的来说,strlcpy
提供了一种更安全的方式来复制字符串,可以有效防止缓冲区溢出的问题。
这些函数的原型如下:
- strcpy:
#include <string.h>
char *strcpy(char *dest, const char *src);
其中,dest
是目标字符串指针,src
是源字符串指针。strcpy
函数会将src
所指的由NULL结束的字符串复制到dest
所指的数组中,返回指向dest
字符串的起始地址。
- strncpy:
#include <string.h>
char *strncpy(char *dest, const char *src, size_t n);
其中,dest
是目标字符串指针,src
是源字符串指针,n
是要复制的字符个数。strncpy
函数会将src
前n
个字符拷贝到dest
。当src
的长度小于n
时,dest
的剩余部分将用空字节填充。但是,如果n
大于src
的长度,strncpy
不会在dest
的末尾添加’\0’结束符。
- strlcpy:
#include <string.h>
size_t strlcpy(char *dest, const char *src, size_t dsize);
其中,dest
是目标字符串指针,src
是源字符串指针,dsize
是目标地址空间大小。strlcpy
会将src
中的字符复制到dest
中,最多复制dsize-1
个字符,并在复制结束后在dest
的末尾添加’\0’结束符。
请注意,这些函数在使用时需要确保目标字符串有足够的空间来存放源字符串,以防止缓冲区溢出。
参考NuttX的代码如下:
FAR char *strcpy(FAR char *dest, FAR const char *src)
{
FAR char *tmp = dest;
while ((*dest++ = *src++) != '\0');
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++) != '\0')
{
}
/* 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++ = '\0';
}
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++) == '\0')
{
break;
}
}
}
if (nleft == 0)
{
if (dsize != 0)
{
*dst = '\0';
}
while (*src++ != '\0');
}
return src - osrc - 1;
}