在得知strncmp
与我的操作系统(Linux)不同的strlcpy
之后,我认为我可以尝试自己编写。
我发现了libc维护者Ulrich Drepper的一句话,他使用strlcpy
发布了mempcpy
的替代方案。我也没有mempcpy
,但它的行为很容易复制。首先,这是我的测试用例
#include <stdio.h>
#include <string.h>
#define BSIZE 10
void insp(const char* s, int n)
{
int i;
for (i = 0; i < n; i++)
printf("%c ", s[i]);
printf("\n");
for (i = 0; i < n; i++)
printf("%02X ", s[i]);
printf("\n");
return;
}
int copy_string(char *dest, const char *src, int n)
{
int r = strlen(memcpy(dest, src, n-1));
dest[r] = 0;
return r;
}
int main()
{
char b[BSIZE];
memset(b, 0, BSIZE);
printf("Buffer size is %d", BSIZE);
insp(b, BSIZE);
printf("\nFirst copy:\n");
copy_string(b, "First", BSIZE);
insp(b, BSIZE);
printf("b = '%s'\n", b);
printf("\nSecond copy:\n");
copy_string(b, "Second", BSIZE);
insp(b, BSIZE);
printf("b = '%s'\n", b);
return 0;
}
这就是结果:
Buffer size is 10
00 00 00 00 00 00 00 00 00 00
First copy:
F i r s t b =
46 69 72 73 74 00 62 20 3D 00
b = 'First'
Second copy:
S e c o n d
53 65 63 6F 6E 64 00 00 01 00
b = 'Second'
您可以在内部表示(创建的行insp()
)中看到混合了一些噪音,例如第一次复制后检查中的printf()
格式字符串,以及外部0x01第二份副本。
字符串被完整地复制并正确处理太长的源字符串(让我们忽略将0作为长度传递给copy_string
的可能问题,我现在将解决这个问题)。
但是为什么我的目的地里面有外来数组内容(来自格式字符串)?就好像目的地实际上是RESIZED以匹配新的长度。
答案 0 :(得分:4)
字符串的结尾标有\ 0,之后的内存可以是任何内容,除非你的操作系统故意将它空白然后它就是那里留下的随机垃圾。
请注意,在这种情况下,'问题'不在copy_string中,你正在复制10chars - 但主代码中'first'之后的内存只是随机的。
答案 1 :(得分:2)
因为你没有停止在源大小,你停止在命运大小,这恰好比源大,所以你正在复制源字符串加上一点垃圾。
您可以轻松地看到您正在使用其null终结符复制源字符串。但是,由于你要记忆10个字节,并且“First”和“Second”两个字符串都短于10个字节,你还要复制额外的字节。
答案 2 :(得分:1)
如果memcpy(dest, src, n-1)
和dest
的长度不是src
,n-1
的使用会调用未定义的行为。
例如,First\0
的长度为六个字符,但您可以从中读取n-1
(9)个字符;字符串文字末尾的内存内容是未定义的,当你读取内存时程序的行为也是如此。
答案 3 :(得分:0)
因为你已经将缓冲区大小传递给memcpy
,所以会有额外的“东西”。它会复制那么多字符,即使源更短也是如此。
我做的事情有点不同:
void copy_string(char *dest, char const *src, size_t n) {
*dest = '\0';
strncat(dest, src, n);
}
与strncpy
不同,strncat
定义为大多数人合理期望的工作方式。