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);
}