C 奇怪的数组行为
在了解到C 奇怪的数组行为,c,arrays,memcpy,memset,C,Arrays,Memcpy,Memset,在了解到strncmp和strlcpy在我的操作系统(Linux)上都不可用后,我想我可以尝试自己编写它 我找到了libc维护者Ulrich Drepper的一段话,他用mempcpy发布了strlcpy的替代方案。我也没有mempcpy,但它的行为很容易复制。首先,这是我的测试用例 #include <stdio.h> #include <string.h> #define BSIZE 10 void insp(const char* s, int n) {
strncmp
和strlcpy
在我的操作系统(Linux)上都不可用后,我想我可以尝试自己编写它
我找到了libc维护者Ulrich Drepper的一段话,他用mempcpy
发布了strlcpy的替代方案。我也没有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;
}
您可以在内部表示(创建的行insp()
)中看到混入了一些噪声,例如第一次拷贝后的检查中的printf()
格式字符串,以及第二次拷贝中的外来0x01
字符串被完整地复制,并且它正确地处理了过长的源字符串(现在让我们忽略将0作为长度传递给copy\u string
的可能问题,我稍后会解决这个问题)
但是为什么在我的目的地中有外来数组内容(来自格式字符串)?这就好像目的地实际调整了大小以匹配新的长度。字符串的结尾用\0标记,之后的内存可以是任何内容,除非您的操作系统故意将其清空,否则它就是任意留下的随机垃圾
请注意,在这种情况下,“问题”不在复制字符串中,您正复制10个字符-但主代码中“first”之后的内存是随机的。因为您不是在源代码大小处停止,而是在destiny大小处停止,恰好比源代码大,因此,您正在复制源字符串加上一点垃圾 您可以很容易地看到您正在复制源字符串及其null终止符。但是,由于您要复制10个字节,并且字符串“First”和“Second”都小于10个字节,因此您也要复制超出它们的额外字节。如果
memcpy(dest,src,n-1)
和src
在长度上不都小于n-1,则使用会调用未定义的行为
例如,First\0
长度为六个字符,但您从中读取了n-1
(9)个字符;超出字符串文字结尾的内存内容是未定义的,读取该内存时程序的行为也是未定义的。额外的“内容”存在,因为您已将缓冲区大小传递给memcpy
。它将复制那么多字符,即使源代码更短
我会做一些不同的事情:
void copy_string(char *dest, char const *src, size_t n) {
*dest = '\0';
strncat(dest, src, n);
}
与strncpy
不同,strncat
被定义为按照大多数人的合理预期工作。在本例中,我指的是printf中的字符串文字,即“b='%s',它与我的数组“b”混合在一起,数组的目标是strlcpy()
和strlcat()在自由许可下是很容易得到的:哦,上帝,我没有想到MycPy.()不停在“0”,愚蠢,愚蠢的我。人们经常期望<代码> StnCAT/<代码>作为<代码> StLCAT/<代码>,也就是说,他们希望它占用目标缓冲区的全长,实际上,它会占用可用于连接的剩余长度。实际上,您需要if(n>0)strncat(dest,src,n-1)
(假设n
是目标缓冲区的大小)。
void copy_string(char *dest, char const *src, size_t n) {
*dest = '\0';
strncat(dest, src, n);
}