【问题标题】:Storing and Accessing a 2D Array in a Struct在结构中存储和访问二维数组
【发布时间】:2014-12-14 17:58:40
【问题描述】:

我正在尝试用 C 编写一个基于用户输入生成螺旋并将其打印到控制台的程序。我无法弄清楚如何访问我在结构“Spiral”中定义的二维数组“数据”。如何修复“警告:来自不兼容的指针类型的赋值”错误?

#include <stdio.h>

typedef struct Spiral {
    int size;
    int **data;
} Spiral;

Spiral generateSpiral(int size);
void printSpiral(Spiral spiral);
static int rotate();

int main() {
    int size;
    scanf("%d", &size);
    Spiral spiral = generateSpiral(size);
    printSpiral(spiral);
    return 0;
}

Spiral generateSpiral(int size) {
    int data[size][size];
    int i;
    for (i = 0; i < size; i++) {
        int j;
        for (j = 0; j < size; j++) {
            data[i][j] = 0;
        }
    }

    for (i = 0; i < size; i++) {
        data[0][i] = 1;
    }

    int currX = 0;
    int currY = size - 1;

    for (i = size - 1; i > 0; i -= 2) {
        int j;
        for (j = 0; j < 2; j++) {
            int k;
            switch (rotate()) {
                case 0:
                    for (k = 0; k < i; k++) {
                        data[++currX][currY] = 1;
                    }
                    break;
                case 1:
                    for (k = i; k > 0; k--) {
                        data[currX][--currY] = 1;
                    }
                    break;
                case 2:
                    for (k = i; k > 0; k--) {
                        data[--currX][currY] = 1;
                    }
                    break;
                case 3:
                    for (k = 0; k < i; k++) {
                        data[currX][++currY] = 1;
                    }
                    break;
            }
        }
    }
    Spiral spiral;
    spiral.size = size;
    spiral.data = data;
    return spiral;
}

void printSpiral(Spiral spiral) {
    int i;
    for (i = 0; i < spiral.size; i++) {
        int j;
        for (j = 0; j < spiral.size; j++) {
            switch (spiral.data[i][j]) {
                case 0:
                    printf(" ");
                    break;
                case 1:
                    printf("#");
                    break;
            }
        }
        printf("\n");
    }
}

static int rotate() {
    static int val = 0;
    int tmp = val;
    val++;
    if (val > 3)
        val = 0;
    return tmp;
}

【问题讨论】:

  • data(int data[size][size];) 的类型不是int **。也不能在指向自动局部变量的函数指针之外使用。
  • 等等,当 size 不是 const 时编译 int data[size][size];?无论如何int data[][] 与int** data 是不同的类型
  • @luk32 int data[size][size] 是普通的variable-length array。
  • 如果spiral.data = data; 没有标记编译器警告,请提高您的警告级别,因为它是错误的。它们不是相同的类型,这并不重要,因为您正在保存一个本地自动地址,然后在函数返回并且 data 数组不再有效后期望它是有效的调用方。
  • @WhozCraig 我认为这正是发出警告/错误的行,因为那里显然存在类型不匹配。我认为如果解决了,接下来的事情就是分配一个超出范围的局部变量。它可能停在第一个错误的地方。

标签: c arrays struct multidimensional-array


【解决方案1】:

在generateSpiral 函数中,您使结构指针指向局部变量data,但是当函数返回时data 超出范围,因此指针现在指向指向undefined behavior 的未分配内存。

但这不是你唯一的问题:第二个问题是指向指针的指针不与数组数组相同,内存布局不同。


对于最后一部分,让我们看一个例子。假设我们有以下声明

int a[2][2];

在内存中它看起来像这样:

+---------+---------+---------+---------+ |一个[0][0] |一个[0][1] |一个[1][0] |一个[1][1] | +---------+---------+---------+---------+

换句话说,所有数据都是连续的。

另一方面,如果你有这样的声明

int **p;

并为它正确分配数据,它看起来像

+------+-----+------+ | p[0] | p[1] | ... | +------+-----+------+ | | | | | v | | ... | v | +---------+---------+------+ | | p[1][0] | p[1][1] | ... | | +---------+---------+------+ v +---------+---------+------+ | p[0][0] | p[0][1] | ... | +---------+---------+------+

内存不再连续。不再有任何最大大小,一个指针指向一个连续的内存区域,但无法知道该区域有多大。您必须自己跟踪它。


解决这两个问题的简单方法是只使用指向指针的指针,然后动态分配堆:

int **data;

// First allocate memory for `size` number of pointers
// I.e. we allocate an "array" of pointers
data = malloc(size * sizeof(int *));

// Then allocate each entry in the above allocated "array"
// I.e. make each pointer in the "array" point to an "array" of `int`
for (int i = 0; i < size; ++i)
    data[i] = malloc(size * sizeof(int));

现在可以直接使用局部变量data赋值给spiral.data。

但有一个问题:在 Java 中,您不必释放分配的内存,它会自动处理。在 C 中它不会自动处理,您必须手动释放您分配的内存,否则您将有 内存泄漏。

释放内存可以这样做

// First free all the "sub-arrays"
for (int i = 0; i < size; ++i)
    free(spiral.data[i]);

// Then free the top-level "array"
free(spiral.data);

关于指针,指针可以指向任何内存地址,实际上没有安全性或检查它是否指向有效位置。此外,C 不会对值和结构进行深度复制,如果您有一个指针并将其指向某个地方,那么编译器或运行时系统不会进行复制。

关于作用域,Java 也有局部变量,就像在 C 中函数返回那些超出作用域的变量一样。 Java 和 C 之间的区别在于,如果您返回对本地对象的引用,那么只要有对该对象的引用,Java 就会跟踪该对象并将该对象保留在内存中。 C没有引用,指针只是一个整数,它的值是内存中的地址,指向的数据不知道有指向它的指针,也不知道有多少。

【讨论】:

  • 我该如何解决?我来自 Java,正在尝试学习 C,但并不完全了解 C 中的范围和指针。
  • 一般情况下,你想在main中声明Spiral的实例,并传递一个指向generateSpiral的指针,例如: Spiral generateSpiral(Spiral *sp, int size),你可以直接对其进行操作或者将函数声明为Spiral *generateSpiral并返回一个指针。
  • @Daniel 更新了我的答案,原因是数组数组与指向指针的指针不同。还为这两个问题添加了可能的解决方案。
  • @Someprogrammerdude 伙计,我不确定您提供的实现是否确保连续分配...
  • @codemonkey 不,它不是,它是一个锯齿状数组,而不是连续的。
【解决方案2】:

您的问题是由于向量大小函数返回的 int 和 unsigned int 之间的不匹配。将您的 int i , j 更改为 size_t 类型,因此它们也是一个无符号整数,就像向量的大小一样。这就是您收到警告的原因

【讨论】:

    猜你喜欢
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    • 2017-04-13
    • 2011-07-04
    • 1970-01-01
    • 2017-10-11
    • 2017-11-07
    • 1970-01-01
    相关资源
    最近更新 更多