C++中2D布尔数组的初始化

5

我不经常使用C语言,最近遇到了二维数组初始化问题而感到困惑。我需要调试别人的代码,但卡在了以下代码(原始代码):

const int location_num = 10000;
bool **location_matrix;
if (node_locations)
    {
        location_matrix = (bool **)malloc(location_num*sizeof(bool *));
        if (!location_matrix)
        {
                cout<<"error 1 allocating location_matrix" << endl;
                exit;
        }
        for (i=0; i<location_num; i++)
        {
                location_matrix[i] = (bool *) malloc(location_num*sizeof(bool ));
                if (!location_matrix[i])
                {
                        cout<<"error 2 allocating location_matrix" << endl;
                        exit;
                }
                for (j=0; j<location_num; j++)
                        location_matrix[i][j] = false;
        }
    }

我觉得它是多余的,所以我将其改为如下:

location_matrix[location_num][location_num] = { {false} };

然而,运行时出现分段错误。 我的问题是:上述代码失败的原因是什么?如果看起来没问题,动态分配和静态分配有什么区别?只是因为维数可能不是常量,所以我们需要动态分配吗? 另外,仅仅出于好奇,我该如何malloc存储指针的2d数组?谢谢。


你为什么使用malloc(n * sizeof(T))而不是new T[n]? - moshbear
4个回答

4
改动可能需要约100MB(10,000 * 10,000 * 1)的堆栈空间,因此段错误很可能是由于堆栈溢出引起的。 编辑:我最初在答案中说了400MB,但@Mooing Duck指出bool很可能是1字节。 我想到的是Win32 BOOL(没有任何真正的原因),它被typedef为int。

我不了解C语言,但在C++中,当内存耗尽时,系统会打印“bad alloc”错误信息。那么你是说,在C语言中,段错误也可以表示堆栈溢出吗? - Shang Wang
这取决于编译器,但堆栈上的“分配”基本上是将堆栈指针加上一定值(或减去一定值……我现在忘记了它通常会向上还是向下)。如果未启用堆栈检查,则对超出有效堆栈的那个本地变量进行的任何读取/写入都将访问超出有效地址空间的内存,这可能会导致分段错误。 - Mark Wilkins
@MarkWilkins:我认为(在大多数实现中)bool只有1个字节。不过,StackOverflow似乎很可能。 - Mooing Duck
@Mooing Duck:那可能是真的。我会编辑它。我没有什么好的理由,只是基于Win32 BOOL,它是4个字节。 - Mark Wilkins

3

我认为这段代码没有任何问题。

以下代码无法正常工作,因为location_matrix未分配:

location_matrix[location_num][location_num] = { {false} };

GCC将允许以下内容(作为扩展):
bool location_matrix[location_num][location_num] = { {false} };

但是由于 10000 x 10000 太大了,所以它会让你的程序崩溃。
目前,你的代码使用了动态分配。这是正确的做法,因为矩阵太大了,不能用静态数组来完成(并且可能会溢出堆栈)。
至于你最后一个问题:“如何制作一个存储指针的2D数组”:它可以和你当前的代码几乎一样。只需将 bool 更改为 int* 即可。
因此,一个由 NULL int 指针组成的2D数组将如下所示:
int ***location_matrix;
if (node_locations)
{
    location_matrix = (int***)malloc(location_num*sizeof(int**));
    if (!location_matrix)
    {
            cout<<"error 1 allocating location_matrix" << endl;
            exit;
    }
    for (i=0; i<location_num; i++)
    {
            location_matrix[i] = (int**) malloc(location_num*sizeof(int*));
            if (!location_matrix[i])
            {
                    cout<<"error 2 allocating location_matrix" << endl;
                    exit;
            }
            for (j=0; j<location_num; j++)
                    location_matrix[i][j] = NULL;
    }
}

1
location_num是编译时初始化的本地const int,所以这段代码应该可以在C++中运行(即使没有编译器扩展),除非我眼前一花。 - Konrad Rudolph
@KonradRudolph:我指的是数组初始化器作为GCC扩展。 - Mysticial
初始化器看起来对我来说没问题。现在,你当然是对的,关于大小。 - Konrad Rudolph

3
标准库是你的好朋友。
#include <vector>

int
main()
{
  int location_num = 1000;
  std::vector<std::vector<bool> > location_matrix(location_num, std::vector<bool>(location_num, false));
}

2
请注意,vector<bool> 存在问题 - 它实际上不是一个 bool 数组。标准库专门为 vector<bool> 进行了特化,以尝试将位打包成动态位集。如果您真的需要一个 bool 数组,以便 .data() 给您一个指向 bool* 的指针,则可以使用 std::deque<bool>。 - emsr

2
其次,数组可能太大而无法放在堆栈上,因此您需要动态分配它--但只要二维数组和指针数组的区别不是问题(如果您需要将该数组传递给函数或对其使用指针算术,则会成为问题),则可以简化代码。
您可以使用以下类似代码:
bool (*location_matrix)[location_num];

location_matrix = (bool (*)[location_num])calloc( location_num, 
                                                  location_num * sizeof(bool) );

该函数为整个二维数组分配空间,并返回一个指向由bool数组构成的数组的指针,每个数组包含location_num个元素。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接