1

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?

lukecampbell
  • 14,728
  • 4
  • 34
  • 32
  • This code has no two-dimensional array, this is a pointer-to-pointer. remove the (float**) cast in main and enable all compiler warnings. [Related question](http://stackoverflow.com/questions/12462615/how-do-i-correctly-set-up-access-and-free-a-multidimensional-array-in-c). – Lundin Dec 06 '12 at 18:40
  • 1
    A two dimensional array is not the same thing as a pointer-to-a-pointer (**). The name of the array, `data`, would still just be a pointer (the base address). That's probably the root source of the EXC_BAD_ACCESS. – hall.stephenk Dec 06 '12 at 18:40
  • -1. There are numerous questions on the same topic, and even the first one should not have been asked (because any good C tutorial clears this up.) –  Dec 06 '12 at 18:42

2 Answers2

9
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.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
  • Is there a correct way to handle a matrix of floats like this? – lukecampbell Dec 06 '12 at 18:43
  • 1
    Either have the function take a pointer to arrays, but that requires the dimension to be fixed when defining the function, or pass an array of pointers into the 2D array, and follow those pointers then (meanwhile there is an example in the answer). – Daniel Fischer Dec 06 '12 at 18:46
  • Sorry about that, my brain is fried right now, I remember this stuff now. I'm converting my functions to use flat matrix referencing, iow: `float *` followed by the `size_t` for the necessary dimensions. Thanks again! – lukecampbell Dec 06 '12 at 19:11
1

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]);
md5
  • 23,373
  • 3
  • 44
  • 93
  • What if the dimensions are unbounded, where the function is not aware of the sizes of the dimensions. – lukecampbell Dec 06 '12 at 18:42
  • @lukecampbell `print_data(float* data)` in that case. The dimensions, when posted as a parameter, are just syntactic sugar. – Lundin Dec 06 '12 at 18:45
  • @lukecampbell: You'll need to pass the size as well, i.e., `print_data(float* data, size_t size)` – Ed S. Dec 06 '12 at 18:52