C ++中的数组创建问题

时间:2014-05-05 17:15:44

标签: c++ arrays

我是一名新手程序员,试图在夏季学期开始前在某些课程上抢先一步,并且在尝试用C ++创建Quick Union算法时遇到了这个问题。

我一直试图弄清楚为什么我的程序会创建两个相同的数组,尽管有两个独立的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 []和数组id []

1,1,1,1,1

有关为何发生这种情况的任何想法?

2 个答案:

答案 0 :(得分:4)

标准C ++没有无大小的数组成员。 在C ++中使用std::vector<int>作为动态大小的数组。

#include <vector>
class quickUnionUF{
private:
    std::vector<int> id;
    std::vector<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;
    }
}

答案 1 :(得分:3)

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

  1. C ++不像Java那样工作。 int id[] 对垃圾收集堆上任意大小的数组的引用。它是一个未定义大小的成员数组,用于实现动态数组(和类似功能)in C99。你不应该使用这种语法,除非你确切地知道你在做什么,因为它几乎可以保证是错误的。

  2. id[n]根本不分配数组。相反,它只是索引id并丢弃结果。

  3. 收听您的编译器!

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

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

    MSVC嚎叫:

    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中定义,两者都以(重点是我的)开头:

      

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

    发生了什么事?

    好吧,假设您无论如何都要编译代码,它基本上意味着以下内容:

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

    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),并且每个数组的第一个元素位于相同的位置(OUTSIDE YOUR OBJECT!)。请记住,您声明idsz元素!

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

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

    我该如何解决这个问题?

    只需使用vector即可。您可以告诉它how big you want it,当您索引某个不属于您的位置时,您可以ask it to tell you