【问题标题】:dynamic allocating array of arrays in CC中动态分配数组的数组
【发布时间】:2010-10-02 03:23:24
【问题描述】:

我并不真正了解 C 中的一些基本内容,例如动态分配数组。 我知道你可以做到:

int **m;

为了声明一个二维数组(随后将使用一些 *alloc 函数分配)。也可以通过*(*(m + line) + column)“轻松”访问它。但是我应该如何为该数组中的元素赋值呢?使用 gcc 以下语句 m[line][column] = 12; 失败并出现分段错误。

任何文章/文档将不胜感激。 :-)

【问题讨论】:

  • 这不是“数组数组”。

标签: c arrays memory dynamic-memory-allocation allocation


【解决方案1】:

使用malloc(3) 分配第一个数组并将malloc(3) 创建的指针放入其中应该与array[r][c] 一起使用,因为它应该等效于*(*(array + r) + c),它符合C 标准。

【讨论】:

    【解决方案2】:

    m[line][column] = 12 语法没问题(前提是linecolumn 在范围内)。

    但是,你没有编写你用来分配它的代码,所以很难判断它是对还是错。应该是这样的

    m = (int**)malloc(nlines * sizeof(int*));
    
    for(i = 0; i < nlines; i++)
      m[i] = (int*)malloc(ncolumns * sizeof(int));
    

    一些旁注:

    • 这样,您可以为每一行分配不同的长度(例如三角形数组)
    • 您可以稍后在使用数组时重新分配()或释放()单独的行
    • 当你释放()整个数组时,你必须释放()每一行

    【讨论】:

    • @jpalecek:我为此分配内存的方式是:m = malloc(lines * columns * sizeof(int *));
    • @hyperboreean:这将分配一个一维指针数组。你想要的是一个指针数组,每个指针都指向另一个数组。您需要首先分配指针数组,然后为每个指向的数组分配内存。
    • 哇,两个可悲无用的编辑。 @chakrit:强制转换 malloc 在 C 中通常被认为是不好的做法,因为它没有必要并且可以掩盖错误。为原始答案 +1。
    • @Robert,不幸的是它取决于编译器的实现。一些较旧的编译器具有需要强制转换的非标准 malloc。直到最近,VisualStudio 都是这样(不记得确切的版本)
    • 强制转换 malloc 在 C++ 中是一种很好的做法,因为如果 LHS 上的变量不是 void 指针,则它是必需的。在 C 语言中这是不好的做法,因为它消除的警告几乎总是需要正确解决的错误,而消除警告只是治疗症状。
    【解决方案3】:

    您的语法 m[line][colummn] 是正确的。但是为了在 C 中使用二维数组,您必须为其分配内存。例如,此代码将为给定行和列的表分配内存。

    int** AllocateArray(int line, int column) {
      int** pArray = (int**)malloc(line*sizeof(int*));
      for ( int i = 0; i < line; i++ ) {
        pArray[i] = (int*)malloc(column*sizeof(int));
      }
      return pArray;
    }
    

    注意,为简洁起见,我省略了 malloc 的错误检查。真正的解决方案应该包括它们。

    【讨论】:

    【解决方案4】:

    它不是一个二维数组——它是一个数组数组——因此它需要多次分配。

    【讨论】:

    • 可能这是我的问题,我遇到了段错误。
    【解决方案5】:

    虽然我同意其他答案,但在大多数情况下最好一次分配整个数组,因为 malloc 非常慢。

    
    int **
    array_new(size_t rows, size_t cols)
    {
        int **array2d, **end, **cur;
        int *array;
    
        cur = array2d = malloc(rows * sizeof(int *));
        if (!array2d)
            return NULL;
    
        array = malloc(rows * cols * sizeof(int));
        if (!array)
        {
            free(array2d);
            return NULL;
        }
    
        end = array2d + rows;
        while (cur != end)
        {
            *cur = array;
            array += cols;
            cur++;
        }
    
        return array2d;
    }
    

    要释放数组,只需执行以下操作: free(*array); free(array);

    注意:此解决方案仅在您不想更改行的顺序时才有效,因为您可能会丢失第一个元素的地址,您需要稍后释放数组。

    【讨论】:

    • 这是一个机智的解决方案 :) 虽然如果我想立即分配它,我可能会求助于“array[i*cols+j]”寻址并放弃“array2d”数组。
    【解决方案6】:

    嗯。作为一种选择,老式的烟雾和镜子怎么样?

    #define ROWS  5
    #define COLS 13
    #define X(R, C) *(p + ((R) * ROWS) + (C))
    
    int main(void)
    {
        int *p = (int *) malloc (ROWS * COLS * sizeof(int));
        if (p != NULL)
        {
            size_t r;
            size_t c;
            for (r = 0; r < ROWS; r++)
            {
                for (c = 0; c < COLS; c++)
                {
                     X(r,c) = r * c;  /* put some silly value in that position */ 
                }
            }
    
            /* Then show the contents of the array */ 
            for (r = 0; r < ROWS; r++)
            {
                printf("%d ", r);   /* Show the row number */ 
    
                for (c = 0; c < COLS; c++)
                {
                     printf("%d", X(r,c));
                }
    
                printf("\n");
            }
    
            free(p);
        }
        else
        {
            /* issue some silly error message */ 
        }
    
        return 0;
    }
    

    【讨论】:

      【解决方案7】:

      这是quinmars' solution 的修改版本,它只分配一个内存块,并且可以通过void * 与通用值一起使用:

      #include <stdlib.h>
      #include <string.h>
      #include <assert.h>
      
      void ** array2d(size_t rows, size_t cols, size_t value_size)
      {
          size_t index_size = sizeof(void *) * rows;
          size_t store_size = value_size * rows * cols;
      
          char * a = malloc(index_size + store_size);
          if(!a) return NULL;
      
          memset(a + index_size, 0, store_size);
          for(size_t i = 0; i < rows; ++i)
              ((void **)a)[i] = a + index_size + i * cols * value_size;
      
          return (void **)a;
      }
      
      int printf(const char *, ...);
      
      int main()
      {
          int ** a = (int **)array2d(5, 5, sizeof(int));
          assert(a);
          a[4][3] = 42;
          printf("%i\n", a[4][3]);
          free(a);
          return 0;
      }
      

      我不确定将void ** 转换为int ** 是否真的安全(我认为该标准允许在转换为void * 时进行转换?),但它适用于gcc。为了安全起见,您应该将每次出现的void * 替换为int * ...


      以下宏实现了先前算法的类型安全版本:

      #define alloc_array2d(TYPE, ROWS, COLS) \
          calloc(sizeof(TYPE *) * ROWS + sizeof(TYPE) * ROWS * COLS, 1)
      
      #define init_array2d(ARRAY, TYPE, ROWS, COLS) \
          do { for(int i = 0; i < ROWS; ++i) \
              ARRAY[i] = (TYPE *)(((char *)ARRAY) + sizeof(TYPE *) * ROWS + \
              i * COLS * sizeof(TYPE)); } while(0)
      

      像这样使用它们:

      int ** a = alloc_array2d(int, 5, 5);
      init_array2d(a, int, 5, 5);
      a[4][3] = 42;
      

      【讨论】:

      • calloc 分配并清零数组。 init_array2d 可能是多余的,除非有一个版本可以将每个单元格设置为不是(TYPE)0 的给定值
      猜你喜欢
      • 1970-01-01
      • 2014-08-19
      • 2010-11-27
      • 2021-11-24
      • 2022-11-25
      • 2012-11-23
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      相关资源
      最近更新 更多