【问题标题】:Pointer to contiguous 2D array指向连续二维数组的指针
【发布时间】:2013-05-17 15:40:18
【问题描述】:

我正在使用带有标志-Wall -std=gnu99 的 gcc 版本 4.8.0。

我需要在 C 中使用 malloc 为连续的二维数组动态分配内存;这个事实是不容谈判的。但是,为了便于使用,我仍然希望能够使用方便的x[r][c] 表示法访问数组。这是我创建指向连续二维数组的指针并通过执行*array[r][c] 为数组编制索引的勇敢尝试:

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    size_t rows = 3, cols = 5;

    printf("sizeof(int) = %li\n\n", sizeof(int));

    int (*array)[rows][cols] = malloc(sizeof(int) * rows * cols);
    printf("array starts at %p\n", array);
    printf("sizeof(array) = %li\n", sizeof(array));
    printf("sizeof(array[0][0]) = 0x%lx\n", sizeof(array[0][0]));
    puts("");

    unsigned short r, c;

    for (r = 0; r <= rows - 1; r++) {
        for (c = 0; c <= cols - 1; c++) {
            printf("array[%i][%i] is at %p\n", r, c, &(*array[r][c]));
        };
        puts("");
    };
}

虽然它编译时没有警告,但它有一些意想不到的输出:

sizeof(int) = 4

array starts at 0x16cc010
sizeof(array) = 8
sizeof(array[0][0]) = 0x14

array[0][0] is at 0x16cc010
array[0][1] is at 0x16cc024
array[0][2] is at 0x16cc038
array[0][3] is at 0x16cc04c
array[0][4] is at 0x16cc060

array[1][0] is at 0x16cc04c
array[1][1] is at 0x16cc060
array[1][2] is at 0x16cc074
array[1][3] is at 0x16cc088
array[1][4] is at 0x16cc09c

array[2][0] is at 0x16cc088
array[2][1] is at 0x16cc09c
array[2][2] is at 0x16cc0b0
array[2][3] is at 0x16cc0c4
array[2][4] is at 0x16cc0d8

我真的不明白这里发生了什么。元素是连续的,但它们对于整数来说太大了,而且数组太小而无法容纳所有元素。

我的数组声明是我最不确定的部分——我正在阅读int (*array)[rows][cols],因为“array 是一个指向整数数组(步长为cols)的指针”,但显然这是不正确的。

我到底做错了什么?

【问题讨论】:

  • 关闭:为什么几乎每个人都在不需要的地方使用后增量而不是预增量,可能会创建不必要的变量副本...
  • @Ze_:编译器很聪明,没有区别。 (在 C++ 中可以有重载的增量运算符,但这些是原始类型,甚至不是 C++。)
  • 这个我理解,但这不是Basic-like语言,它被设计得那么简单,程序员可以被认为更少……为什么要写一个原本希望优化的代码?
  • @Ze_ 这可能适用于旧的和/或狡猾的编译器,但现代编译器会优化它。
  • 您是说(使用较旧的编译器)我应该使用++r++c 而不是r++c++

标签: c pointers multidimensional-array


【解决方案1】:
int (*array)[cols] = malloc( sizeof *array * rows );

for (r = 0; r <= rows - 1; r++) {
    for (c = 0; c <= cols - 1; c++) {
        printf("array[%i][%i] is at %p\n", r, c, &array[r][c]);

这允许您将array 索引为array[i][j],因为array[i] 隐式取消引用指针。

要解除分配,你只需要调用

free( array );

【讨论】:

  • 我之前试过这个,但显然我在声明中混淆了行和列的大小。这完美地工作并简化了语法。
【解决方案2】:

代码应该是

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    size_t rows = 3, cols = 5;

    printf("sizeof(int) = %li\n\n", sizeof(int));

    int (*array)[rows][cols] = malloc(sizeof(int) * rows * cols);
    printf("array starts at %p\n", array);
    printf("sizeof(array) = %li\n", sizeof(*array));  // Note the *
    printf("sizeof(array[0][0]) = 0x%lx\n", sizeof((*array)[0][0]));
    puts("");

    unsigned short r, c;

    for (r = 0; r <= rows - 1; r++) {
        for (c = 0; c <= cols - 1; c++) {
            printf("array[%i][%i] is at %p\n", r, c, &((*array)[r][c]));
        };
        puts("");
    };
}

因为 array 是指向数组[x][y] 的指针,所以你必须先取消引用它

 (*array)

访问项目

 (*array)[x][y]

这样你就得到了

sizeof(int) = 4

array starts at 0x12de010
sizeof(array) = 60
sizeof(array[0][0]) = 0x4

array[0][0] is at 0x12de010
array[0][1] is at 0x12de014
array[0][2] is at 0x12de018
array[0][3] is at 0x12de01c
array[0][4] is at 0x12de020

array[1][0] is at 0x12de024
array[1][1] is at 0x12de028
array[1][2] is at 0x12de02c
array[1][3] is at 0x12de030
array[1][4] is at 0x12de034

array[2][0] is at 0x12de038
array[2][1] is at 0x12de03c
array[2][2] is at 0x12de040
array[2][3] is at 0x12de044
array[2][4] is at 0x12de048

在预期值范围内更多

【讨论】:

  • 我想我打印的是指针的大小而不是数组的大小。我觉得很傻。
  • 我仍然对一件事感到困惑:既然*array[r][c] 没有预期的优先级,为什么它仍然可以编译?
  • @DrKitty 因为还有 3 级间接性。
  • 如果可以,我会接受这两个答案,因为两者都可以,但我会选择 John Bode 的,因为它在访问数组时允许更简单的语法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-21
  • 2017-06-11
  • 2012-01-26
相关资源
最近更新 更多