#include <iostream>
using namespace std;
void myStrcpy(char [], char []);
int main(int argc, const char * argv[]) {
char c1[] = "htako";
char c2[] = "Mark";
myStrcpy(c1, c2);
cout << c2 << endl;
return 0;
}
void myStrcpy (char c1[], char c2[]) {
int i = 0;
while(c1[i] != ' ') {
c2[i] = c1[i];
cout << c1[i] << " ::: " << i << endl;
i++;
}
}
当我逐步完成调试器时,一切正常,直到 i = 4,在第 4 次交互时,它从(第 3 次迭代)htak 变为 htakohtako。我不明白为什么它在上次迭代中复制了整个单词。当我在第四次迭代中打印出 c1[i] 时,它会按预期打印出一个 o,但最后这个额外的 htako 从何而来?
你的问题的答案与内存的布局有关。如果检查内存,您将看到:
c2 c1
M, a, r, k, , h, t, a, k, o,
您的代码中有 2 个问题。
- 您有一个缓冲区溢出
c2
只有 5 个字节(Mark + 空终止符),但您正在覆盖空终止符,因为c1
的长度为 6 个字节(htako + 空终止符) - 您不是空终止字符串
您看到字符串似乎在增长,因为您覆盖了 null 终止符。在其他情况下,您的程序可能会崩溃。
代码有两个问题:
- 您正在使用基于 C 的字符串,而忘记将终止 null 字符写入
c2
c2
中没有足够的空间用于该空字符。
要解决第一个问题,请在 while 循环后添加c2[i] = 0;
。
要修复第二个问题,请使用char c2[6] = "Mark";
请注意,这里需要6个才能容纳来自"htako"的 5 个字符 + 终止空字符。
更详细地说:char c1[] = "htako";
实际上定义了长度为 6 的 char 数组:
{ 'h', 't', 'a', 'k', 'o', }
.
char c2[] = "Mark";
定义长度为 5 的较短字符数组:
{ 'M', 'a', 'r', 'k', }
因此,当您的 while 循环在将 c1 复制到 c2 后结束时,您有 c2 的位置:
{ 'h', 't', 'a', 'k', 'o' }
请注意,您没有终止空字符。此外,cince c2 被隐式声明为长度为 5,您没有空间添加它。因此,当您将修改后的 c2 输出到 cout 时,由于您使用的是 char[],cout 实际上接收没有长度的char *
,并且根据 C 字符串约定,通过搜索终止空字符来确定字符串的长度。由于您没有该空字符,因此 cout 将超过搜索它的c2
结束,并且访问有效 ares 之外的数据是C++程序的未定义行为。在您的特定机器上,堆栈会增长,因此 c1 恰好在 c2 之后,您会看到打印的"htakohtako"。但实际上,您的程序也可能因SEGV而失败或做任何令人不快的事情。这种类型的错误称为缓冲区溢出,是许多安全漏洞的根源。不惜一切代价避免这种情况。
但实际上,std::string
在这里更合适和安全的选择,除非你只是在玩弄 C 字符串在内部的工作方式。