我是一个新手程序员,试图在夏季学期开始之前先掌握一些课程,并且在尝试用C ++创建快速联合算法时遇到了这个问题。

我一直试图弄清楚为什么我的程序创建两个相同的数组,尽管有两个单独的for循环旨在创建两个不同的数组。每当我的程序运行完成并输出id []和sz []时,它总是在两个数组的每个索引处输出1作为元素。

class quickUnionUF{
private:
    int id[];
    int sz[];
    int root(int);
public:
    quickUnionUF(int, int);
    bool connected(int, int);
    void unionPoint(int, int);
    void print();
};

quickUnionUF::quickUnionUF(int n, int b){
    id[n];
    sz[b];
    for(int i=0;i<n;i++){
        id[i] = i;
    }
    for(int j=0;j<b;j++){
        sz[j] = 1;
    }
}


例如,如果我创建quickUnionUF(5,5);

id []现在应包含元素:

0、1、2、3、4

sz []包含以下元素:

1,1,1,1,1

但是,该程序使用以下元素创建一个数组sz []和array id []:

1,1,1,1,1

为什么会这样呢?

最佳答案

您的代码提示了两个非常重要的错误:


C ++不能像Java一样工作。 int id[]不是对垃圾收集堆上任意大小的数组的引用。相反,它是一个未定义大小的成员数组,用于实现动态数组(和类似功能)in C99。除非您确切知道自己在做什么,否则永远不要使用此语法,因为几乎可以肯定否则会出错。
id[n]根本不分配数组。相反,它仅索引id并丢弃结果。


听你的编译器!

首先,由于只有结构的最后一个成员可能是灵活的数组类型,因此您的代码不应编译。实际上c叫:

main.cpp:53:9: error: field has incomplete type 'int []'
    int id[];


MSVC ls叫:

1>main.cpp(54): error C2229: class 'quickUnionUF' has an illegal zero-sized array


而且g ++仅警告(嗯,g ++有时会接受奇怪的东西):

main.cpp:53:12: warning: ISO C++ forbids zero-size array ‘id’ [-Werror=pedantic]
    int id[];


注意:即使允许灵活的数组成员,g ++在编译时也是错误的。这是在C996.7.2.1§16和C116.7.2.1§18中定义的,它们都以(强调是我的)开头:


  作为一种特殊情况,结构中具有多个命名成员的最后一个元素可以
  数组类型不完整;这称为灵活数组成员。 [...]


怎么了?

好吧,假设您仍然可以编译代码,则基本上意味着以下几点:

创建一个整数对齐的对象,但根本没有元素。看看以下测试程序:

quickUnionUF q;
::std::cout << sizeof(quickUnionUF) << "\n";
::std::cout << &q << "\n" << &q.id[0] << "\n" << &q.sz[0] << "\n";


唯一能够完全编译该编译器的编译器(gcc 4.9.0)得到以下结果:

0
0x7fff1bf6274c
0x7fff1bf6274c
0x7fff1bf6274c


因此,这是一个零字节的对象(是的,这是非法的C ++,因为每个C ++对象的大小都大于0),并且每个数组的第一个元素都位于相同的位置(对象之外!)。记住,您声明idsz的元素为零!

因此,您正在写入相同的任意位置。您可以认为这是缓冲区溢出的极端情况:通过将5个整数写入零大小的缓冲区,您正在从第一个零大小的缓冲区到第二个零大小的缓冲区溢出到完全不受您控制的内存中。

这也解释了您观察到的结果:第二个循环只是覆盖了第一个循环(并且仍然通过破坏堆栈来完成)。

我该如何解决?

只需使用vector。您可以告诉它how big you want it,并且当您索引到某个位置而不是您时可以ask it to tell you

关于c++ - C++中的数组创建问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23477966/

10-12 12:38
查看更多