C语言:使用一维数组实现多维数组

3

我正在尝试申请一个巨大的4D数组(有192G可用空间),但输入的内容与输出的不匹配(请参见下面代码中的assert())。 (我将定义的尺寸缩小了,但实际数字为:20、9000、195、120)

#define SIZE_A 1
#define SIZE_B 3
#define SIZE_C 4
#define SIZE_D 2

#define offSet(a,b,c,d) ( ((size_t) SIZE_A * SIZE_B * SIZE_C * a) + ((size_t) SIZE_B * SIZE_C * b) + ((size_t) SIZE_C * c) + d)

void xall(void)
{
int *aray = (int *) malloc( (size_t) SIZE_A * SIZE_B * SIZE_C *  SIZE_D  * sizeof(int));


int counter = 0;

    for (int a = 0; a < SIZE_A; ++a){
        for (int b = 0; b < SIZE_B; ++b){
            for (int c = 0; c < SIZE_C; ++c) {
                for (int d = 0; d < SIZE_D; ++d){
                    aray[ offSet(a,b,c,d) ] = counter++;

                }}}}


counter = 0;    
    for (int a = 0; a < SIZE_A; ++a){
        for (int b = 0; b < SIZE_B; ++b){
            for (int c = 0; c < SIZE_C; ++c) {
                for (int d = 0; d < SIZE_D; ++d){       
                    int value = aray[ offSet(a,b,c,d) ] ;
                    assert(value == counter++);

                }}}}
}
4个回答

5

正如其他人所提到的那样,您的宏是错误的。修复这个问题当然可以,但我建议您直接分配一个多维数组,而不是手动编写偏移量宏。请参考以下示例:

#include <assert.h>
#include <stdlib.h>

#define SIZE_A 1
#define SIZE_B 3
#define SIZE_C 4
#define SIZE_D 2

int main(void)
{
  int counter = 0;
  int (*array)[SIZE_A][SIZE_B][SIZE_C][SIZE_D] = 
          malloc(sizeof(int) * SIZE_A * SIZE_B * SIZE_C *  SIZE_D);

  for (int a = 0; a < SIZE_A; ++a)
    for (int b = 0; b < SIZE_B; ++b)
      for (int c = 0; c < SIZE_C; ++c) 
        for (int d = 0; d < SIZE_D; ++d)
          (*array)[a][b][c][d] = counter++;

  counter = 0;    
  for (int a = 0; a < SIZE_A; ++a)
    for (int b = 0; b < SIZE_B; ++b)
      for (int c = 0; c < SIZE_C; ++c)
        for (int d = 0; d < SIZE_D; ++d)
        {
          int value = (*array)[a][b][c][d];
          assert(value == counter++);
        }

  return 0;
}

此示例中分配的数组的内存布局与您的问题中完全相同,但为什么不让编译器为您做这件事呢?
编辑说明:在 C 程序中不要将 malloc() 调用的返回值强制转换。从 void * 的转换是隐式的,而显式强制转换可能会隐藏您本来应该获得的隐式函数声明警告,例如如果您忘记包含 stdlib.h 文件时。

好的观点,但问题是维度对于Visual C来说太大了:数组的总大小超过4GB,我得到了关于数组大小太大的C2148错误。 - PaeneInsula
但是你可以分配那么多的内存并将其分配给一个简单的指针吗?我不明白。 - Carl Norum
C2148错误表示一个数组的总大小不能超过2^31-1字节。但是你仍然可以使用malloc分配超过这个大小的内存。因此,这只是编译器的限制。 - Mysticial
@mikithskegg:我使用的是64位操作系统,我的工作站最大支持192GB内存(没错,是Gigabytes而不是Megabytes)。还有其他建议吗? - PaeneInsula
是的,您可以使用malloc分配比c2148警告所说更多的内存,这就是我正在做的。据我所知,如果数组维度为(例如)[500] [300] [9000] 195],则没有办法执行Carl Norum建议的操作。 - PaeneInsula
显示剩余3条评论

1

你的宏并不完全正确。请将其更改为以下内容:

#define offSet(a,b,c,d) ( ((size_t) SIZE_B * SIZE_C * SIZE_D * a) + ((size_t) SIZE_C * SIZE_D * b) + ((size_t) SIZE_D * c) + d)

你基本上把你的SIZE_X向右移了一个字母。

我还建议在宏参数周围加上()

#define offSet(a,b,c,d) ( ((size_t) SIZE_B * SIZE_C * SIZE_D * (a)) + ((size_t) SIZE_C * SIZE_D * (b)) + ((size_t) SIZE_D * (c)) + (d) )

0

我觉得宏应该这样定义:

#define offSet(a,b,c,d) ( ((size_t)  SIZE_B * SIZE_C *SIZE_D * a) + ((size_t)  SIZE_C *SIZE_D * b) + ((size_t) SSIZE_D * c) + d)

0
在某些操作系统中,每个进程的内存分配有限制。通常默认值可以更改。
其他一些操作系统在调用malloc时甚至不会分配实际内存,例如Linux,当您尝试写入时可能会失败,但我猜这不是您的情况。
尝试检查您的系统是否可以控制每个进程的最大分配内存。
希望您能找到答案,这确实很有趣。
一些阅读材料:

http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory http://www.linux-mag.com/id/827/


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