copied/truncated 字符数组中的奇怪符号

Weird symbols in copied/truncated character array

#include <iostream>
using namespace std;

void truncate(char* s1, char* s2, int n) {
    for (int i = 0; i < n; i++) {
        s2[i] = s1[i];
    }
}

int main() {
    char s1[15] = "Hello World";
    char s2[10];
    int n{ 5 };
    truncate(s1, s2, n);
    cout << s2; // this should display: Hello
}

当我在 Visual Studio 中 运行 时,我得到这个输出:

Hello╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠Hello World

但是当我运行它使用在线编译器(在线GDB)时,输出是正常的:

Hello

我知道它与 [=14=] 终止符有关,但我就是想不通。

您的 truncate 函数不会将 所需的 nul terminator character 添加到目标 (s2) 字符串。因此,当您在 main 中调用 cout 时,它将继续打印字符,直到它在 garbage-initialized 数据之后的某个未指定位置找到预期的 nul(零)字符 pre-exists 在 s2 本地数组的部分中,您的函数未明确设置。 (这是未定义的行为,实际上几乎可以显示任何内容;如果 cout 调用试图读取它没有所需访问权限的内存,程序也可能崩溃)。

要更正此问题,只需将 nul(零或 '[=21=]')字符添加到 truncate 函数中的字符串末尾即可。假设您没有超出数组的边界,您可以使用循环索引的“剩余”值 i 来访问所需的元素;但是,为此,您需要声明 for 循环范围的 int i 外部

void truncate(char* s1, char* s2, int n)
{
    int i; // Must be declared outside the FOR loop ...
    for (i = 0; i < n; i++) {
        s2[i] = s1[i];
    }
    s2[i] = '[=10=]'; // ... so we can use it here.
}

注意:另一种方法(但显然被你的老师禁止)是将 mains2 数组的所有元素设置为零,before 调用你的 truncate 函数:

char s2[10] = ""; // Set ALL elements to zero

一些编译器(似乎包括您使用的在线编译器)会“隐式”将未初始化的局部数组的元素设置为零;但是永远不要依赖这个:它不是 C++ 标准的一部分并且编译器不需要强制执行此类行为。