3

I would like to create a C function that takes a 2D array of doubles as a parameter and operates on that array via indexing, e.g. printf("%f ", array[i][j]).

What I've been able to piece together from various examples and SO questions is something like this:

void printArray(double **array, int m, int n)
{
    int i, j;
    for (i = 0; i < m; i++) 
    {
        for (j = 0; j < n; j++) 
        {
             printf("%f ", array[i][j]);
        }
    printf("\n");
    }
}

In main, I'm able to successfully print the array like so:

int i, j, k = 0, m = 5, n = 6;
double **a = malloc(m * sizeof(*a));

//Initialize the arrays
for (i = 0; i < m; i++) 
{
    a[i] = malloc(n * sizeof(*(a[i])));
}
for (i = 0; i < m; i++) 
{
    for (j = 0; j<n; j++) 
    {
        k++;
        a[i][j] = k;
    }
}

printArray(a, m, n);

However, when I try to initialize an array to some given values and then call:

double a[5][6] = { { 1, 2, 3, 4, 5 ,6},
                   { 1, 2, 3, 4, 5, 6},
                   { 1, 2, 3, 4, 5, 6},
                   { 1, 2, 3, 4, 5, 6},
                   { 1, 2, 3, 4, 5, 6} };

printArray(a, 5, 6);

I am met with the following error:

Unhandled exception at 0x011514D3 in Example.exe: 0xC0000005:
Access violation reading location 0xA1F8E3AC.

Can someone explain what my mistake is and how to fix it? edited

Please note that, for the purposes of the function definition, I will know the size of the array at run time but not compile time. Also, I'm compiling on Windows with VisualStudio 2013.

Trekkie
  • 964
  • 1
  • 9
  • 32
  • Your function seems to take a double pointer, aren't you passing the array by value? Try "&a" – Jay Jul 19 '15 at 03:24
  • If you want the most straight forward example from another user on SO use: http://stackoverflow.com/questions/3911400/passing-2d-arrays. – KillaBytes Jul 19 '15 at 03:26
  • @JohnColeman In printarray(a, 5, 6): 5,6 is the size of the array not the element. Unless I didn't understand what you meant? – ilent2 Jul 19 '15 at 03:27
  • @Kozmik Unfortunately, that solution (stackoverflow.com/questions/3911400/passing-2d-arrays) requires knowledge of the array size at compile time, i.e. defining the rows and column in the code. – Trekkie Jul 19 '15 at 03:51
  • @TrekkieByDay So you want to create these arrays dynamically - with the information you already have now you can just combine what many here have given you with dynamic allocation. This might help as well: http://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/ – KillaBytes Jul 19 '15 at 03:53
  • possible duplicate of [Passing a 2D array in a function in C program](http://stackoverflow.com/questions/6321670/passing-a-2d-array-in-a-function-in-c-program) – n. m. could be an AI Jul 19 '15 at 04:25
  • @n.m. I had in fact seen that post and several others like it... these answers, though, have put me on track where the others had not. – Trekkie Jul 19 '15 at 04:29
  • This post answers your question precisely. "An array decays to a pointer only once". Is there something unclear in this wording? – n. m. could be an AI Jul 19 '15 at 04:35
  • @n.m Yes, that is a fact, and yes it added to my understanding of the general issue, but no, it did not answer my question precisely. Borealid and Kozmik both helped tremendously though. I was in fact able to reach a solution based on their responses. – Trekkie Jul 19 '15 at 04:42
  • 1
    @Kozmik That is a great link, think you. – Trekkie Jul 19 '15 at 04:44
  • Your question was "what is my error". Your error was that you expected `double[5][6]` to decay to `double**`. The post and the answer explain that this is not the case. Perhaps your actual problem was different from the question you asked. – n. m. could be an AI Jul 19 '15 at 04:48
  • Ahh, I see @n.m.! Thank u for clarifying. You are correct, it does answer the question "what is my error." The question I should have asked and the one that has been answered here is, "how can i fix it"? – Trekkie Jul 19 '15 at 04:51
  • I am considering just working with 1d arrays and mapping the 2d indexing accordingly... that may be better anyway performance wise. – Trekkie Jul 19 '15 at 04:54
  • But you already know that nested malloc calls work, you have working code in the question. That's exactly how you fix it. What's your question again? – n. m. could be an AI Jul 19 '15 at 04:56
  • My post showed my ignorance as to the difference between array** and array[5][6]. Between yours and everyone else responses, I now understand. Im afraid i dont understan your issue... it seems everything is good now. – Trekkie Jul 19 '15 at 05:02
  • @n.m. or others, what do u think of the flat indexing idea? – Trekkie Jul 19 '15 at 05:02
  • No issues, all is OK. Flat indexing should work. – n. m. could be an AI Jul 19 '15 at 05:09

1 Answers1

5

double a[5][6] has type double[][6], which is not the same as double**. double** is a pointer to a pointer to a double. double[][6] is a compiler-managed data type that represents a two-dimensional array.

What's going on here is that the double[][6] you created is being silently cast to a double** in your invocation of printArray.

If your function is going to take a double**, you need to pass it a double**. You can initialize the array contents by filling each member array individually:

double row1[3] = {3, 4, 5};
a[1] = row1;

This works around the problem; because the double[] is stored by the compiler as a contiguous array of double values, casting it to double* implicitly as above is safe.

Another solution is to change the function to take a "real" double[][6], instead of a pointer-pointer. How you would do this with non-fixed-size arrays is up to your particular off-brand of C; it's not part of the C standard so far as I know.

A third solution is to build the array row by row with malloc and fill it cell by cell with a[0][0] = 1 and so forth. You already have this in your question, and it works correctly.

A final thing to be aware of is that you are allocating a on the stack: when your main function exits, accessing it will result in undefined behavior.

Borealid
  • 95,191
  • 9
  • 106
  • 122
  • "type `double[][]`" There is no such type in the C language. Given `double a[5][6]`,`a` has type `double[5][6]`. This decays to `double (*)[6]` which is equivalent to `double [][6]` in function prototypes. – n. m. could be an AI Jul 19 '15 at 04:23
  • @n.m. Technically correct, the best type of correct. In my answer I didn't want to say `double[][6]` because that fixes the six, and I was worried that "`double[][x]` for arbitrary x" would confuse things. I've bitten the bullet and deleted the irrelevant sections of my answer. – Borealid Jul 19 '15 at 08:37
  • @Borealid This was still a good answer. The driving force behind my question is the need to speed up Scipy's 2D interp function. So I am writing a minimal equivalent in C to be called using Python ctypes. The numerical method is straightforward.. how C deals with multidim arrays was not. Since array multidimensionality is a human construct anyway.. I think I am going to modify the algorithm to use a 2d mapped to 1d flattened indexing system and just avoid this issue. As it stands now, it looks like I would have to do a loop to get the np array data into a proper 2d format – Trekkie Jul 19 '15 at 11:58
  • Continuing from my previous comment, extra loops are B-A-D at this point. :D – Trekkie Jul 19 '15 at 12:08
  • @TrekkieByDay That is a good idea, not necessarily because of "this issue", but because a 1D array is going to be much faster than an array of pointers. This is thanks to cache locality, the single biggest factor in modern application performance: if you can make access be to sequential memory locations, your application will have fewer cache misses and perform much better. – Borealid Jul 19 '15 at 17:58