Ala*_*orm 3 c++ arrays pointers
我正在帮朋友做一些C++的家庭作业.我警告说,我所做的那种编程(PHP,Perl,Python)与C++有很大的不同,并且我无法保证我不会说出可怕的谎言.
我能够回答他的问题,但不是没有绊倒我自己的动态背景.当我重新认识C++数组语义时,我做了一些像这样的蠢事(简化示例让我的问题更加清晰)
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char easy_as_one_two_three[] = {'A','B','C'};
int an_int = 1;
//I want an array that has a length of the value
//that's currently in an_int (1)
//This clearly (to a c++ programmer) doesn't do that.
//but what is it doing?
char breaking_things[an_int];
cout << easy_as_one_two_three << endl;
return 1;
}
Run Code Online (Sandbox Code Playgroud)
当我编译并运行该程序时,它会产生以下输出
ABC????
Run Code Online (Sandbox Code Playgroud)
但是,如果我注释掉我的虚假阵列声明
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char easy_as_one_two_three[] = {'A','B','C'};
int an_int = 1;
//I want an array that has a length of the value
//that's currently in an_int (1)
//This clearly (to a c programmer) doesn't do that.
//but what is it doing?
//char breaking_things[an_int];
cout << easy_as_one_two_three << endl;
return 1;
}
Run Code Online (Sandbox Code Playgroud)
我得到了我期望的输出:
ABC
Run Code Online (Sandbox Code Playgroud)
那么,到底发生了什么?我(隐约地)理解当你创建一个数组时,你指向一个特定的内存地址,当你给一个数组一个长度时,你告诉计算机"为我保留下一个X块".
我不明白的是,当我在数组声明中使用变量时,我告诉计算机做什么,为什么它对一个完全独立的数组产生影响?
编译器是g ++,版本字符串是
science:c++ alanstorm$ g++ -v
Using built-in specs.
Target: i686-apple-darwin9
Configured with: /var/tmp/gcc/gcc-5493~1/src/configure --disable-checking -enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.0/ --with-gxx-include-dir=/include/c++/4.0.0 --with-slibdir=/usr/lib --build=i686-apple-darwin9 --with-arch=apple --with-tune=generic --host=i686-apple-darwin9 --target=i686-apple-darwin9
Thread model: posix
gcc version 4.0.1 (Apple Inc. build 5493)
Run Code Online (Sandbox Code Playgroud)
Ama*_*osh 12
更新:Neil在他对这个问题的评论中指出,如果用g ++ 编译-Wall和-pedantic标记,你会得到错误.
error: ISO C++ forbids variable-size array
你得到的ABC????是因为它打印了array(ABC)的内容并继续打印,直到遇到a \0.
如果有阵列{'A','B','C', '\0'};,输出将ABC如预期的那样.
在C99中引入了可变长度数组 - 但这似乎并不适用于C++.
这是未定义的行为.即使您注释掉虚假声明,打印输出也不总是您所期望的(ABC).尝试给出一些可打印字符的ASCII值(在32到126之间),an_int而不是1,你会看到差异.
an_int output
------------------------
40 ABC(
65 ABCA
66 ABCB
67 ABCC
296 ABC(
552 ABC(
1064 ABC(
1024*1024 + 40 ABC(
Run Code Online (Sandbox Code Playgroud)
看到这里的模式?显然它将an_intchar 的最后一个字节(LSB)解释为打印,然后以某种方式找到null char并停止打印.我认为"某种程度上"必须对an_int填充零的MSB部分做一些事情,但我不确定(也不能得到任何结果来支持这个论点).
更新:它是关于MSB填充零.我得到了以下结果.
ABC(对于40 - (3个零字节和一个40),
ABC((对于10280(即(40 << 8)+ 40) - (2个零字节和两个40),
ABC(((对于2631720(即(10280 << 8)+ 40) - (1个零字节和3个40s),
ABC((((°¿®对于673720360(即(2631720 << 8)+ 40) - 没有零字节,因此打印随机字符,直到找到零字节.
ABCDCBA0á´¿á´¿®for(((((65 << 8)+ 66)<< 8)+ 67)<< 8)+ 68;
这些结果是在具有8位原子元素大小和1字节地址增量的小端处理器上获得的,其中32位整数40(十六进制为0x28)表示为0x28-0x00-0x00-0x00(最低地址处的LSB).结果可能因编译器和编译器以及平台而异.
现在,如果您尝试取消注释虚假声明,您会发现所有输出都是表单ABC-randomchars-char_corresponding_to_an_int.这又是未定义行为的结果.
这不会"重新认识"你"使用c ++数组语义",因为在C++中它只是非法的.在C++中,只能使用由Integral Constant Expressions(ICE)定义的大小来声明数组.在您的示例中,大小不是ICE.它只能编译,因为GCC特定的扩展.
从C的角度来看,这在C99版本的语言中实际上是完全合法的.它确实产生了一个长度为1的所谓可变长度数组.所以你的"清晰"注释是不正确的.