复制一个字符串
所需头文件
#include <string.h>
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy. Beware of buffer overruns! (See BUGS.)
strcpy函数从src指针指向的内存区域复制字符串,包括字符串结束符\0,到dest所指向的内存,两个字符串不可以重叠,目标字符串dest必须足够大来容纳复制过来的字符串,注意buffer溢出(详见BUGS)
The strncpy() function is similar, except that at most n bytes of src are copied. Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated. If the length of src is less than n, strncpy() writes additional null bytes to dest to ensure that a total of n bytes are written.
strncpy函数类似,区别是最多从src复制n个字节,如果src字符串的前n个字节没有字符串结束符,那么字符串dest将不会包含字符结束符,如果src的长度小于n,那么strncpy将会写null字节到dest以确保总共有n个字节复制到dest。
下面是strncpy的一个简单实现:
A simple implementation of strncpy() might be:
char *
strncpy(char *dest, const char *src, size_t n)
{
size_t i;
for (i = 0; i < n && src[i] != '\0'; i++)
dest[i] = src[i];
for ( ; i < n; i++)
dest[i] = '\0';
return dest;
}
The strcpy() and strncpy() functions return a pointer to the destination string dest.
strcpy和strncpy函数都返回指向目的字符串dest的指针
Some programmers consider strncpy() to be inefficient and error prone. If the programmer knows (i.e., includes code to test!) that the size of dest is greater than the length of src, then strcpy() can be used.
一些程序员认为strncpy效率不高,而且容易犯错。如果程序员能够确保dest的大小足够容纳src,那么最好使用strcpy
One valid (and intended) use of strncpy() is to copy a C string to a fixed-length buffer while ensuring both that the buffer is not overflowed and that unused bytes in the target buffer are zeroed out (perhaps to prevent information leaks if the buffer is to be written to media or transmitted to another process via an interprocess communication technique).
一个值得使用strncpy的情况是复制一个c字符串到一个长度固定的buffer,同时确保buffer不会溢出和目标字符串中没有使用过的字节都是0值的
If there is no terminating null byte in the first n bytes of src, strncpy() produces an unterminated string in dest. You can force termination using something like the following:
如果src的前n个字节没有字符串结束符,那么strncpy将会使dest字符串是无截断的,你可以使用下面的方法强行截断:
strncpy(buf, str, n);
if (n > 0)
buf[n - 1]= '\0';
(Of course, the above technique ignores the fact that information contained in src is lost in the copying to dest.)
当然,上面的方法忽略了复制到dest的src字符串是有信息丢失这个事实
Some systems (the BSDs, Solaris, and others) provide the following function:
size_t strlcpy(char *dest, const char *src, size_t size);
This function is similar to strncpy(), but it copies at most size-1 bytes to dest, always adds a terminating null byte, and does not pad the target with (further) null bytes. This function fixes some of the problems of strcpy() and strncpy(), but the caller must still handle the possibility of data loss if size is too small. The return value of the function is the length of src, which allows truncation to be easily detected: if the return value is greater than or equal to size, truncation occurred. If loss of data matters, the caller must either check the arguments before the call, or test the function return value. strlcpy() is not present in glibc and is not standardized by POSIX, but is available on Linux via the libbsd library.
一些系统(BSDs,Solaris和其他)提供了下面的函数:
size_t strlcpy(char *dest, const char *src, size_t size);
这个函数类似与strncpy,但是最多复制size-1字节到dest,总是会加上一个字符串结束符,不会使目标字符串是无截断的,这个函数解决了strcpy和strncpy的一些问题,但是调用者同样需要处理size过小导致数据丢失的问题,函数的返回值是src的长度,这样让截断能够容易被检测出来,如果返回值大于或等于size,那么就是发生了截断,如果发生了数据丢失,调用者必须在调用之前检查参数,同时必须检测函数的返回值,strlcpy没有在glibc中实现,而且也不是POSIX标准函数,但是可以在linux中通过libbsd库来使用
If the destination string of a strcpy() is not large enough, then anything might happen. Overflowing fixed-length string buffers is a favorite cracker technique for taking complete control of the machine. Any time a program reads or copies data into a buffer, the program first needs to check that there's enough space. This may be unnecessary if you can show that overflow is impossible, but be careful: programs can get changed over time, in ways that may make the impossible possible.
如果strcpy的目标字符串不够大,那么所有情况都可能发生,溢出固定长度的字符串是黑客们常用的拿到计算机控制权的方法,任何时间,程序在读或者复制字符串到缓冲区的时候必须检查是否有足够空间,除非你能保证不可能发生溢出,但是请小心:程序是实时的,它们可以把不可能变成可能。
testcase如下:
#include <stdio.h>
#include <string.h>
int main(void)
{
char dest[10];
const char *src1 = "abc";
const char *src2 = "hello world!";
strcpy(dest, src1);
printf("dest = %s\n", dest);
memset(dest, 0x00, 10);
strncpy(dest, src2, 10);
printf("dest = %s\n", dest);
dest[9] = 0;
printf("dest = %s\n", dest);
memset(dest, 0x00, 10);
strcpy(dest, src2);
printf("dest = %s\n", dest);
return 0;
}
测试结果如下:
cheny.le@cheny-ThinkPad-T420:~/cheny/testCode$ ./a.out
dest = abc
dest = hello worl@
dest = hello wor
dest = hello world!
可以看到dest的大小是10个字节,而src1字符串是“abc”3个字节,所以肯定是不会发生溢出的,strcpy足矣,但是src2字符串“hello world!”12个字节,使用strncpy复制10个字节的话,将会使dest字符串变成非截断的,也就是说dest字符串将不会有预期的\0来结束字符串,所以就会像第二个结果一样有乱码,为了确保字符串是正常截断的,就必须把最后一个字节复制为0强行截断,这样子就会导致strncpy复制的10个字节有丢失,可以看到第三个结果只存储了src2复制过来的9个字节,这样会导致数据丢失,最后一个结果表面上看起来是正常的,但是需要弄清楚的是dest总共只申请了10个字节,却装了12个字节的字符串,所以说后面的2个字节其实是发生了溢出,如果后面两个字节的内存恰好是其他变量在使用的话,那么这种溢出发生的后果将不可想象,这是黑客们最喜欢的方法了,大家需要注意一下!