3

I have a function which tries to loop through a 2D array in a struct:

typedef struct node
{
    int grid[3][3];
} Node;


void someFunction(Node *node) {
     int grid[3][3] = node->grid;
     //loop through
}

When I try to compile this however I get a

mp.c:42: error: invalid initializer

5
  • One thing, why not just pass an int[][3] instead of wrapping it in a node since it's only a 1 member struct? Commented Jul 21, 2011 at 1:58
  • @Jesus Ramos I plan to put other attributes in the struct. Commented Jul 21, 2011 at 2:06
  • 1
    @Jesus Ramos: Even though Jeune says it won't be like that, it's a common way to make an array a "first class" type. Simply for bringing advantages like allowing assignments (which automatically duplicates the array) or returning arrays from functions. Commented Jul 21, 2011 at 2:08
  • Ok just making sure you're not complicating things for yourself too much :) Commented Jul 21, 2011 at 2:12
  • You should try to understand the difference between an array and a pointer. Commented Jul 21, 2011 at 2:25

3 Answers 3

11

You cannot assign arrays in C. It is simply not allowed. When you wrote:

int grid[3][3] = node->grid;

you were attempting to initialize the local array, grid, from the passed in node. If that were permitted (which it isn't), then you'd not need a loop afterwards.

You can assign structures, though, even if they contain arrays, so if the local structure were a Node, you could have written:

Node local = *node;

You would not need to loop through the arrays afterwards to initialize local.

You can loop through the arrays, doing the copy one element at a time:

for (int i = 0; i < 3; i++)
    for (int j = 0; j < 3; j++)
        grid[i][j] = node->grid[i][j];

You can also use memmove() or memcpy():

int grid[3][3];

assert(sizeof(grid) == sizeof(node->grid));
memcpy(grid, node->grid, sizeof(grid));

At one time, another answer suggested:

Change the line:

int grid[3][3] = node->grid;

to:

int **grid = node->grid;

I noted that this will not work - and was legitimately challenged to explain why. That requires space and formatting.

First of all, the compiler notes:

warning: initialization from incompatible pointer type

That is saying 'you are playing with fire'.

Let's suppose we ignore that warning. The local grid now points at the top-left corner of the array (if you see arrays growing down and across from left-to-right). The value stored there is a plain number, not an initialized pointer, but when the compiler evaluates grid[0], it is forced to assume that will produce a pointer. If node->grid[0][0] contains a zero, you will probably get a segmentation fault and core dump for dereferencing a null pointer (on the assumption that pointers and int are the same size, which is generally true on 32-bit systems), or some other undefined behaviour. If node->grid[0][0] contains another value, then the behaviour is still undefined, but not quite as predictable.

Sign up to request clarification or add additional context in comments.

7 Comments

and then I can loop through grid like a normal 2d array?
@Jeune: yes, it is simply an initialized array with a copy of the contents of the other, which you can manipulate in any that you find necessary. That works regardless of which (compilable) mechanism you use to initialize the local array.
Just note that you will be making a copy of the array here, instead of just using the array that is in the structure already. That may be what you want, but if you just want a local variable that points to the same array that lives in the struct, see my answer below.
I get this though: incompatible implicit declaration of built-in function ‘memcpy’ Do I have to import anything?
You can, however, use int (*grid)[3] = node->grid, and this may actually be the most appropriate in this case.
|
1

If you don't want to do the copy, just want a pointer to the array in the struct (note: if you assign values to *pointer, the content of the array in the struct will be changed), you can achieve this aim in two ways:

#include <stdio.h>

typedef struct node
{
    int grid[3][3];
} Node;


void someFunction1(Node *node) {
     int i, j;
     int (*grid)[3] = node->grid;
     for(i=0; i<3; i++){
         for(j=0; j<3; j++){
             printf("%d ", grid[i][j]);
         }
         printf("\n");
     }
}

void someFunction2(Node *node) {
     int i, j;
     int *grid = (int*) node->grid;
     for(i=0; i<3; i++){
         for(j=0; j<3; j++){
             printf("%d ", grid[i*3+j]); // i * column_number + j
         }
         printf("\n");
     }
}

int main()
{
    Node t;
    int i, *p;

    //initialization: t.grid[0][0]=0,  ..., t.grid[2][2]=8
    for(i=0, p=(int*)t.grid; i<9; p++, i++){
        *p = i;
    }

    printf("Function1:\n");
    someFunction1(&t);

    printf("Function2:\n");
    someFunction2(&t);

    return 0;
}

The above code shows a simple function to use pointers. They are all safe and up to standard.

If you want to use pointer to pointer, int**, you will have to make it in a different way, because, arrays are linear storage in memory (so the above code can use an int* to point to the beginning of the array and operate it), but int** not.

EDIT

So here comes the someFunction3()

void someFunction3(Node *node)
{
    int i, j;
    int **p;

    // 3 is the row number. Ignore checking malloc failure
    p = malloc(sizeof(int)*3);
    for(i=0; i<3; i++) {
        p[i] = (int*) node->grid[i]; //assign address of each row of array to *p
    }

    for(i=0; i<3; i++) {
        for(j=0; j<3; j++) {
            printf("%d ", p[i][j]);
        }
        printf("\n");
    }

    free(p);
}

2 Comments

You can avoid the casts when initialising the int * values by using &node->grid[0][0] (or just node->grid[0]).
@caf: Thanks. You're right. It's my bad habit. I'm lazy to consider the type issue :-p
0

See this other thread for the same question and the answer that doesn't involve copying the memory:

Create a pointer to two-dimensional array

4 Comments

No; that won't work. To work, each of grid[0], grid[1] and grid[2] would have to be a pointer to array, and despite appearances, it is not. The address in node->grid is assigned to grid, but grid[1] is not properly initialized. It is hard to explain this in an answer; it is entirely non-trivial in a comment.
I get this warning though: mp.c:42: warning: initialization from incompatible pointer type what does that mean?
Check out this thread for more info: stackoverflow.com/questions/1052818/…
I'm going to change my answer to this other duplicate thread. @Jonathan: Thanks for the info.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.