lukecampbell
lukecampbell

Reputation: 15256

C, passing 2 dimensional array

I haven't used pure C in a few years now, but I can't seem to make this really basic use case work. Here is the simple use-case in simple C, the actual situation is wrapped in the HDF library, but I need to start with this, first.

#include <stdio.h>

void print_data(float **data, int I, int J)
{
    for(int i=0;i<I;i++)
    {
        for(int j=0;j<J;j++)
            printf("%02.2f\t", data[i][j]);
        printf("\n");
    }
}
void initialize_data(float **data, int I, int J)
{
    for(int i=0;i<I;i++)
        for(int j=0;j<J;j++)
            data[i][j] = i * 6 + j + 1;
}
int main(int argc, char *argv[])
{
    float data[4][6];
    int I=4;
    int J=6;
    initialize_data((float **)data, 4,6);
    print_data((float **)data, 4, 6);
    return 0;
}

The above program will cause a failure and raise a EXC_BAD_ACCESS signal. GDB outputs:

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00007fff5fc0131a
0x0000000100000de6 in initialize_data (data=0x7fff5fbff348, I=4, J=6) at simple.c:16
16              data[i][j] = i * 6 + j + 1;

I know this is really stupid simple, but I'm at my wits' ends trying to figure out this simple thing. Could someone point me in the right direction for this?

Upvotes: 1

Views: 7606

Answers (2)

Daniel Fischer
Daniel Fischer

Reputation: 183968

void print_data(float **data, int I, int J)

expects an array of pointers to (the first element of arrays of) float.

But when you pass

float data[4][6];

you pass a pointer to float[6].

So in print_data, an access to

data[i]

reads sizeof(float*) bytes at an offset of i * sizeof(float*) bytes after what address data holds, and interprets these bytes as a float* that it then dereferences (after adding a suitable offset) in data[i][j].

So when you pass your 2D array, some float values are interpreted as pointers and then followed. That often leads to a segmentation fault.

You can either declare

void print_data(float (*data)[6], int I, int J)

and pass your 2D array, or you need to pass an array of pointers,

float *rows[4];
for(i = 0; i < 4; ++i) {
    rows[i] = &data[i][0];
}

and pass rows. Or, the third possibility is to pass and expect a flat array

void initialize_data(float* data, int I, int J) {
    for(i = 0; i < I; ++i) {
        for(j = 0; j < J; ++j) {
            data[i*J + j] = whatever;
        }
    }
}

and pass &data[0][0] from main.

Upvotes: 9

md5
md5

Reputation: 23707

A bi-dimensionnal array is not evaluated as a pointer to pointer, so you need to use an array of a pointer to array in your prototype:

void print_data(float data[4][6]);
void print_data(float (*data)[6]);

Upvotes: 1

Related Questions