Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

c - Storing and Accessing a 2D Array in a Struct

I am trying to code a program in C that generates a spiral based on user input and prints it to the console. I cannot figure out how to access the 2D array "data" that I defined in the struct "Spiral". How do I fix the "warning: assignment from incompatible pointer type" error?

#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("
");
    }
}

static int rotate() {
    static int val = 0;
    int tmp = val;
    val++;
    if (val > 3)
        val = 0;
    return tmp;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In the generateSpiral function you make the structures pointer point to the local variable data, but when the function returns data goes out of scope so the pointer now points to unallocated memory leading to undefined behavior.

But that's not your only problem: A second problem is that a pointer to a pointer is not the same as an array of arrays, the memory layout is different.


For the last part, lets check an example. Lets say we have the following declaration

int a[2][2];

In memory it will look something like this:

+---------+---------+---------+---------+
| a[0][0] | a[0][1] | a[1][0] | a[1][1] |
+---------+---------+---------+---------+

In other words, all data is contiguous.

If you, on the other hand have a declaration like

int **p;

and allocate data for it correctly, it will look something like

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

The memory is no longer contiguous. There is no longer any maximum size, a pointer points to a contiguous area of memory, but there is no way of knowing how big that area is. You have to keep track of it yourself.


The simple solution to both the problems is to use only pointer to pointer, and then allocate dynamically of the heap:

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));

Now the local variable data can be used directly to assign to spiral.data.

But there is a catch: In Java you don't have to free memory you allocate, it's handled automatically. In C it's not handled automatically, you have to manually free the memory you allocate or you will have a memory leak.

Freeing the memory can be done like

// 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);

Regarding pointers, a pointer can point to any memory address, and there is really no safety or checking that it points to a valid location. Also, C does not do deep copying of values and structures, if you have a pointer and make it point somewhere, then the compiler or runtime system doesn't make a copy.

And about scoping, Java has local variables as well, and just like in C when a function returns those go out of scope. The difference between Java and C, is that if you return a reference to a local object, then Java keeps track of that and keep the object in memory as long as there are references to the object. C doesn't have references, a pointer is just an integer whose value is an address in memory, and the data pointed to have no idea that there are pointers to it or how many.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...