17

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

int **m;

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

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

4

7 回答 7

35

m[line][column] = 12语法没问题(提供并且linecolumn范围内)。

但是,您没有编写用于分配它的代码,因此很难判断它是对还是错。它应该是类似的东西

m = (int**)malloc(nlines * sizeof(int*));

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

一些旁注:

  • 这样,您可以为每一行分配不同的长度(例如三角形数组)
  • 您可以稍后在使用数组时重新分配()或释放()单独的行
  • 当您释放()整个数组时,您必须释放()每一行
于 2009-01-18T21:53:24.850 回答
5

您的语法 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 的错误检查。真正的解决方案应该包括它们。

于 2009-01-18T21:53:54.257 回答
3

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

于 2009-01-18T21:57:55.263 回答
3

这是quinmars 解决方案的修改版本,它只分配一个内存块,并且可以通过以下方式与通用值一起使用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;
于 2009-01-19T00:41:54.370 回答
1

尽管我同意其他答案,但在大多数情况下,最好一次分配整个数组,因为 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);

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

于 2009-01-18T23:09:47.317 回答
1

嗯。旧时尚烟雾和镜子作为一种选择怎么样?

#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;
}
于 2009-01-19T00:15:59.073 回答
0

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

于 2009-01-18T21:53:22.480 回答