I want to declare a global 2d array in C, and allocate contiguous memory at runtime because the minor dimension is unknown at compile time. I would like to dereference the array with 2-indices notation A[i][j]. If the array wasn't global c99 notation "double A[m][n]" would be handy but in my case does not apply. What would be the right strategy?
#include <stdio.h>
#include <stdlib.h>
//TO DO
//DECLARE array here
void fun1() {
array[3][2] = 42.0;
}
int main(int argc,char *argv[])
{
int rows = atol(argv[1]);
int cols = atol(argv[2]);
//TO DO
//Allocate memory for array here
fun1();
printf("Array[3][2]=%f\n",array[3][2]);
return(0);
}
Unfortunately, it not quite possible in C to achieve what you are asking for.
There is a slightly ugly solution with a macro. Since the macro refers to both the global array itself and a global variable containing its second dimension, you have to be careful to not shadow the globals in any function which uses the macro. Here, I used clunky names ending with underscores to try to avoid name reuse.
Other than that, it should work:
void* global_array_void_;
size_t global_array_minor_dim_;
#define global_array ((double(*)[global_array_minor_dim_])global_array_void_)
Before you can use the macro, you need to allocate it and initialize the global variables:
void init_global_array(int rows, int cols) {
global_array_minor_dim_ = cols
global_array_void_ = malloc(rows * cols * sizeof global_array[0][0]);
}
From then on, you can use use global_array
as though it were a regular array:
void f(int r, int c, double v) {
global_array[r][c] = v;
}
The type in the cast ((double (*)[cols])(array_void_))
might not be obvious. It represents a pointer to an array of cols
double
s, which is what double[][cols]
would decay to as a pointer. Note that double[][cols]
does not decay to double**
, which is a completely different (and incompatible) type.
With that definition, sizeof global_array[r]
has the correct value: cols * sizeof(double)
. Contrast that with sizeof argv[i]
.
A more traditional way of doing this is to use a function to compute the precise index. That still depends on the minor dimension being available:
double* global_array;
size_t global_array_minor_dim_;
void init_global_array(int rows, int cols) {
global_array_minor_dim_ = cols
global_array_void_ = malloc(rows * cols * sizeof global_array[0][0]);
}
double* global_array_at(int r, int c) {
return &global_array[r * global_array_minor_dim_ + c];
}
Now you can use *global_array_at(r, c)
as a replacement for global_array[r][c]
. In C, it's impossible to eliminate the *
and still have assignment work (in C++, the function could have returned a double&
instead of a double*
), but this could be solved, once again, with a macro.