在@dbush的回答基础上进一步扩展:
我认为代码仍然非常脆弱。
#include <stdio.h>
#include <string.h>
int main() {
char src[40];
char src2[40];
char dest[20];
这里第一个陷阱被创建:dest比两个源都要小。虽然这可以处理,但需要在随后的代码中更加小心谨慎。最好让目标始终足够大以容纳源。
memset(dest, '\0', sizeof(dest)); //Good
但是,最好也将其他数组初始化为0。
memset(src, '\0', sizeof(src));
memset(src2, '\0', sizeof(src2));
顺带一提:当然您可以使用数组初始化语法来避免使用memset的麻烦:
char src[40] = {0}
char src2[40] = {0}
char dest[20] = {0}
下面两行代码存在潜在的危险,因为实际情况中这两个字符串可能不是字符串常量(即用户输入等)。甚至对于字符串常量也没有提供长度检查……更好的做法是:
// strcpy(src, "This is a string");
// strcpy(src2, "That");
strncpy(src, "This is a string", sizeof(src)- 1);
strncpy(src2, "That", sizeof(src2) -1);
那样我们可以确保不会造成任何溢出。我们还要确保 src 和 src2 中的字符串被正确地以空字符结尾。现在,将 src/src2 复制到 dest 也是危险的。我们必须确保不会溢出 dest。
//strncpy(dest, src, strlen(src));
//strncpy(dest, src2, strlen(src2));
更好的写法:
strncpy(dest, src, sizeof(dest) - 1);
strncpy(dest, "That is a long rubbish string that easily could overflow dest", sizeof(dest) -1);
我们只复制dest可以容纳的内容并保留空终止符。
现在来替换前X个字符。同样,我们必须确保没有溢出发生。我们使用strlen来确定src2中空终止字符串的实际大小,但需要使用/评估dest的最大大小。因此,strlen和sizeof的混合使用。
memcpy仅供娱乐。您也可以同样使用strncpy。
memcpy(dest, src2, strlen(src2) < sizeof(dest) ? strlen(src2) : sizeof(dest));
printf("Final copied string : %s\n", dest);
}
所以整个安全实现看起来像这样:
#include <stdio.h>
#include <string.h>
int main() {
char src[40] = {0};
char src2[40] = {0};
char dest[20] = {0};
strncpy(src, "This is a string", sizeof(src)- 1);
strncpy(src2, "That is a long rubbish string and sooooooooooooooooooooooooo much more", sizeof(src2) -1);
strncpy(dest, src, sizeof(dest) - 1);
memcpy(dest, src2, strlen(src2) < sizeof(dest) ? strlen(src2) : sizeof(dest));
printf("Final copied string : %s\n", dest);
}
请注意,使用sizeof只在char类型上等同于strlen;在其他类型上需要进行更多操作。
strncpy(dest, src, sizeof(src));
使用源字符串的大小作为限制是无效的。重要的是目标字符串的大小。dest
只能容纳长度不超过11个字符的字符串,而src
可以容纳长度达39个字符的字符串。由于src
包含一个超过11个字符的字符串,因此会出现缓冲区溢出,导致未定义行为。 - Gerhardhstrncpy()
的长度参数不大于源字符串的实际长度,则strncpy()
不会复制终止符,这正是OP想要的。 - John Bollinger