关于C#:为什么在strcat()之前首先必须先strcpy()?

Why do i first have to strcpy() before strcat()?

为什么此代码会产生运行时问题:

1
2
3
char stuff[100];
strcat(stuff,"hi");
strcat(stuff,"there");

但这不是吗?

1
2
3
char stuff[100];
strcpy(stuff,"hi");
strcat(stuff,"there");

strcat将查找空终止符,将其解释为字符串的结尾,然后在其中附加新文本,覆盖过程中的空终止符,并在连接末尾写入新的空终止符。

1
char stuff[100];  // 'stuff' is uninitialized

空终止符在哪里? stuff未初始化,因此它可能以NUL开头,或者其中可能没有NUL。

在C ++中,您可以执行以下操作:

1
char stuff[100] = {};  // 'stuff' is initialized to all zeroes

现在您可以执行strcat了,因为'stuff'的第一个字符是空终止符,因此它将附加到正确的位置。

在C中,您仍然需要初始化'stuff',可以通过两种方法完成:

1
2
3
4
char stuff[100]; // not initialized
stuff[0] = '\\0'; // first character is now the null terminator,
                 // so 'stuff' is effectively""
strcpy(stuff,"hi");  // this initializes 'stuff' if it's not already.


在第一种情况下,stuff包含垃圾。 strcat要求目标和源都包含正确的以空字符结尾的字符串。

1
strcat(stuff,"hi");

将扫描stuff以查找终止的'\\0'字符,并开始复制"hi"。如果找不到它,它将在数组末尾运行,并且可能会发生任何不良情况(即行为未定义)。

避免问题的一种方法是这样的:

1
2
3
4
char stuff[100];
stuff[0] = '\\0';      /* ensures stuff contains a valid string */
strcat(stuff,"hi");
strcat(stuff,"there");

或者,您可以将stuff初始化为空字符串:

1
char stuff[100] ="";

它将用<零>填充stuff的所有100个字节(增加的清晰度可能值得解决任何较小的性能问题)。


因为stuff在调用strcpy之前未初始化。在声明stuff不是空字符串之后,它是未初始化的数据。

strcat将数据追加到字符串的末尾-也就是说,它将在字符串中找到空终止符,并在其后添加字符。未初始化的字符串不保证具有空终止符,因此strcat可能会崩溃。

如果要如下初始化stuff,则可以执行strcat:

1
2
3
char stuff[100] ="";
strcat(stuff,"hi");
strcat(stuff,"there");

Strcat将字符串追加到现有字符串。如果字符串数组为空,则无法继续查找字符串('\\0')的结尾,这将导致运行时错误。

根据Linux手册页,简单的strcat通过以下方式实现:

1
2
3
4
5
6
7
8
9
10
11
12
   char*
   strncat(char *dest, const char *src, size_t n)
   {
       size_t dest_len = strlen(dest);
       size_t i;

       for (i = 0 ; i < n && src[i] != '\\0' ; i++)
           dest[dest_len + i] = src[i];
       dest[dest_len + i] = '\\0';

       return dest;
   }

如在此实现中所看到的,除非dest初始化为正确的c字符串值,否则strlen(dest)将不会返回正确的字符串长度。您可能很幸运在char stuff[100];拥有一个第一个零值的数组,但是您不应该依赖它。


另外,我建议不要使用strcpystrcat,因为它们会导致一些意想不到的问题。

使用strncpystrncat,因为它们有助于防止缓冲区溢出。