C++ 为什么我可以使用以0大小启动的数组:Char ch[0];
这是我的代码:C++ 为什么我可以使用以0大小启动的数组:Char ch[0];,c++,arrays,char,C++,Arrays,Char,这是我的代码: #include<iostream> using namespace std; int main(){ char ch[0]; cin >> ch; cout << ch; return 0; } 产出1: abcdefghijklmnopqrstuvwxyza (工作很好,但我不知道为什么) 输入2: abcdefghijklmnopqrstuvwxyzab 输出2: abcdefghijklmnopqr
#include<iostream>
using namespace std;
int main(){
char ch[0];
cin >> ch;
cout << ch;
return 0;
}
产出1:
abcdefghijklmnopqrstuvwxyza
(工作很好,但我不知道为什么)
输入2:
abcdefghijklmnopqrstuvwxyzab
输出2:
abcdefghijklmnopqrstuvwxyzab_
(请求输入)
输入3:
abcdefghijklmnopqrstuvwxyzabc
输出3:
(运行时错误)
当output2请求输入时,我们将input2,
输出与输出2相同(再次请求输入),
当我们把input1或input2放进去时,output1或output2也会出现
有人能解释这种现象吗?为什么会发生这种情况?大小为0的数组无效: 如果存在常数表达式(5.19),则其应为积分常数表达式,且其值应大于零 如果编译器接受它,那么它只是一个非标准扩展。GCC接受它,但如果您添加
-pedantic
选项,则会发出诊断:
warning: ISO C++ forbids zero-size array ‘arr’ [-pedantic]
尽管如此,读入非标准的零大小数组无疑会给您带来未定义的行为。大小为0的数组无效: 如果存在常数表达式(5.19),则其应为积分常数表达式,且其值应大于零 如果编译器接受它,那么它只是一个非标准扩展。GCC接受它,但如果您添加
-pedantic
选项,则会发出诊断:
warning: ISO C++ forbids zero-size array ‘arr’ [-pedantic]
尽管如此,读入非标准的零大小数组无疑会给您带来未定义的行为。您需要一个可以存储输入值的数组,这绝对无法处理
char ch[0];
这肯定是一个分段
错误
$./a.out
12345678901234567890
Segmentation fault (core dumped)
您需要将
ch
定义为输入所需的大小。您需要一个可以存储输入值的数组,这绝对无法处理
char ch[0];
这肯定是一个分段
错误
$./a.out
12345678901234567890
Segmentation fault (core dumped)
您需要将
ch
定义为输入所需的大小。基本上char ch[0]
;是内存中定义的地址。
您将其传递给Cin,它开始从输入到它的字符处写入。
然后你传递同一个地址,它会试图理解它。
基本上打印每个字符,直到它运行到0
你必须做一些深入的调查,看看你为什么会看到这种行为,但这完全是浪费时间。行为是未定义的,不能保证它在任何方面都是可重复的。基本上
charch[0]
;是内存中定义的地址。
您将其传递给Cin,它开始从输入到它的字符处写入。
然后你传递同一个地址,它会试图理解它。
基本上打印每个字符,直到它运行到0
你必须做一些深入的调查,看看你为什么会看到这种行为,但这完全是浪费时间。行为是未定义的,不能保证它在任何方面都是可重复的。正如stfrabbit指出的,标准明确禁止声明大小为零的数组。但是,
gcc
允许将这类事情作为扩展,我们不会对此进行讨论
发生了什么事?嗯,当需要寻找
操作符>
和操作符的可接受重载时,正如stfrabbit指出的,标准明确禁止声明大小为零的数组。但是,gcc
允许将这类事情作为扩展,我们不会对此进行讨论
发生了什么事?好的,当需要寻找操作符>>
和操作符的可接受重载时,大多数编译器只会将数组设置为具有真实的开始地址,但不会占用任何空间,因此堆栈或结构中的后续变量将从它们在0大小的数组根本不存在时所具有的相同地址开始。这经常被用作结构的最后一个成员,在该结构中,当分配n个字节时,该结构被填充。然后,作为最后一个成员的数组可以被索引以访问该填充,而无需指针数学
例如
structfoo
{
INTA;
int b;
charc[0];
};
foo*f=malloc(sizeof(foo)+50);
对于(int i=0;i<50;++i)
f->c[i]=57;
sizeof foo很可能是8,但这并不重要,因为c是该结构的结束地址,而不管该结构是如何字节对齐/填充的
一些Win32 API利用了这一点。大多数编译器只会将数组设置为具有实际的开始地址,但不会占用任何空间,因此堆栈或结构中的后续变量将从它们在0大小的数组根本不存在时所具有的相同地址开始。这经常被用作结构的最后一个成员,在该结构中,当分配n个字节时,该结构被填充。然后,作为最后一个成员的数组可以被索引以访问该填充,而无需指针数学
例如
structfoo
{
INTA;
int b;
charc[0];
};
foo*f=malloc(sizeof(foo)+50);
对于(int i=0;i<50;++i)
f->c[i]=57;
sizeof foo很可能是8,但这并不重要,因为c是该结构的结束地址,而不管该结构是如何字节对齐/填充的
一些Win32 API利用了这一点。您遇到了典型的缓冲区溢出问题。虽然定义零大小的数组是不符合要求的,但实际情况是,您在堆栈上得到了一个默认对齐大小的变量(通常为4或8)
因此,当您开始读取该变量时,您将数据放在堆栈上,它开始覆盖堆栈帧。这不是很明显立即,但它破坏了您返回的地址
因此,代码执行read(精细),然后write(精细),然后尝试返回。如果返回地址已被破坏,则会出现分段错误。否则,这种情况可能会继续下去,而不会引起注意。在上一个示例中,您没有得到输出的原因是由于缓冲输出-程序在退出之前没有得到刷新缓冲区的更改(正如从main返回后所做的那样)
下面是一个示例,您如何看到您的代码覆盖了st