C++ 字符a[n][m]和amp;字符a[][m]?

C++ 字符a[n][m]和amp;字符a[][m]?,c++,arrays,multidimensional-array,char,C++,Arrays,Multidimensional Array,Char,还有,为什么在第二种情况下,当我提供m>我的列值时,它不打印垃圾?有什么具体原因吗 #include <iostream> using namespace std; int main() { char a[2][5] = {{'a', 'b', 'c', 'd', 's'}, {'e', 'f', 'g', 'h', 'q'}}; cout << a[0] << endl; // abcdsefghq!V cout <<

还有,为什么在第二种情况下,当我提供m>我的列值时,它不打印垃圾?有什么具体原因吗

#include <iostream>
using namespace std;

int main()
{
    char a[2][5] = {{'a', 'b', 'c', 'd', 's'}, {'e', 'f', 'g', 'h', 'q'}};
    cout << a[0] << endl; // abcdsefghq!V
    cout << a[1] << endl; // efghq!V
    
    char a1[][6] = {{'a', 'b', 'c', 'd', 's'}, {'e', 'f', 'g', 'h', 'q'}};
    cout << a1[0] << endl; // abcds
    cout << a1[1] << endl; // efghq

    return 0;
}
#包括
使用名称空间std;
int main()
{
字符a[2][5]={{'a',b',c',d',s'},{'e',f',g',h',q'};

cout
char a[2][5]
明确指定行数。
char a1[][6]
告诉编译器暗示来自初始值设定项的行数

比如说,

char b[10][5] = {"a", "b", "c"};
创建10行,因为该数字已显式指定,但

char b1[][5] = {"a", "b", "c"};
仅创建3行,因为初始值设定项中有3行


第二种情况下,每行有6个字符,每行指定5个字符。剩余的1个字符初始化为零,并用作C样式字符串的终止符。另一方面,第一种情况下,每行只有5个字符,并且5个字符已完全指定,因此在中没有终止的空字符数组。将其打印为C样式字符串将导致危险的超出范围访问。

a
的情况下,当打印
a[0]
a[1]
时,它们的类型为
char[5]
,在传递到
标题时会衰减为
char*

字符a[n][m]和字符a[][m]之间有区别吗

不,只要在第二种情况下,您在初始化中提供
n


但是,在您的问题中,实际情况并非如此。在您的问题中,您有一个
字符a[2][5]
,并用字符填充。因为这些字符都不是空终止符,所以将这些行传递给
cout
具有未定义的行为。
cout
要求字符数组(c字符串)具有空终止符


在第二种情况下,您有一个
字符a[][6]
,并为初始化提供了两行,每行5个字符。这使得类型a
字符a[2][6]
,但由于您只为6个字符提供了5个初始值设定项,编译器会自动将缺少的第六个字符(空终止符)归零,因此将这些行传递给
cout
可以正常工作。

这里有一些不同的操作

首先,如果您给出一个显式数组大小,但未在初始值设定项中指定所有元素,则剩余元素将被零初始化。例如:

int a[5] = {1, 2, 3};  // equivalent to {1, 2, 3, 0, 0}
这是两个示例之间的主要区别-一个显式指定大小,另一个根据初始值设定项推断大小

接下来,数组“衰减”为指针,因此
char[]
的行为类似于
char*
,也称为c-string。c-string必须以null结尾。在第一个示例中,您打印垃圾是因为缺少null结尾符。在第二个示例中,您不会打印垃圾,因为数组有一个(隐藏的)null终止符,因为最后一个元素已初始化为零

字符a[n][m]和字符a[][m]之间有区别吗

取决于上下文。第一个是m字符数组的n个数组。第二个是m字符数组的未知边界数组。因此,它们是不同的类型

然而,给定一个大括号的init列表(如示例中所示),未知边界的数组将调整为一个已知边界的数组,其中边界是从初始值设定者的数量推导出来的。如果推导出的初始值设定者的数量是n,则调整后的类型将与char[n][m]完全相同

简言之,答案是:一般来说,区别在于前者是已知边界的数组,后者是未知边界的数组,但在这个上下文中,将未知边界的数组调整为已知边界的数组后没有区别


还有为什么不打印垃圾

使用数组调用流插入运算符时,操作数将衰减为指向第一个元素的指针。流要求
char*
参数是指向以null结尾的字符数组的指针。违反此前提条件会导致未定义的行为

a
中的数组不包含空终止符。程序的行为未定义



应避免未定义的行为。切勿将非空终止数组传递给字符流

如果给出明确的数组大小,但未在初始值设定项中指定所有元素,则其余元素将被零初始化。
char[]
转换为
char*
,因此零初始化元素就像c字符串中的空终止符。问题是终止零!当代码有ub时,危险不是得到“垃圾”,而是得到看起来合理的输出。我不知道这个“垃圾”故事从何而来,这只是误导,没有帮助。“我期望垃圾,但输出很好,为什么?”忽略了未定义行为的要点。