Tyler Treat
Tyler Treat

Reputation: 14988

Passing a 2D array to a function in C

I have, essentially, a matrix of data (lets say ints) that I would like to store in a 2D array in which the dimensions are not known until runtime (say x columns and y rows). I want to populate the array in a function, so I assume I need to do something like this:

int main(int argc, char **argv) {
    int y = atoi(argv[1]);
    int x = atoi(argv[2]);
    int **matrix = malloc(x * sizeof(int*));
    populateMatrix(matrix, y, x);
    return 0;
}

void populateMatrix(**matrix, int y, int x) {
    int i, j;
    for (i = 0; i < y; i++) {
        for (j = 0; j < x; j++) {
            matrix[i][j] = i * j; // populated with trivial data to keep it simple
        }
    }
}

Obviously this doesn't work, but I'm not sure how to do what I'm describing exactly.

Upvotes: 0

Views: 1263

Answers (4)

Jens Gustedt
Jens Gustedt

Reputation: 78903

C99 has a simple tool that is often frowned upon but serves exactly what you want, variable length arrays, VLA.

void populateMatrix(size_t y, size_t x, double matrix[x][y]);

The reason why they are frowned upon is that if you use them directly to allocate matrices on the stack you might observe stack overflow. You can avoid that by actually passing pointers to such beasts:

void populateMatrix2(size_t y, size_t x, double (*matrix)[x][y]) {
  for (... something ...) {
     (*matrix)[i][j] = 33.0;
  }
}

and in some function:

double (*myMatrix)[n][m] = malloc(sizeof(*myMatrix));
populateMatrix2(n, m, myMatrix);

For the syntax, you just have to have the size of the dimensions come before the matrix in the parameter list such that they are known at that point. Also use size_t for everything that is indices and sizes of objects, it makes usually no sense to have a signed type for them.

Upvotes: 0

Marko
Marko

Reputation: 138

matrix in main is a pointer to a pointer to int. Your program allocates space for x pointers to int. Considering the loop in populateMatrix, that should be space for y pointers to int. More importantly, you have not allocated space for the rows. You need another loop in main that will allocate y rows each large enough to hold x ints.

Upvotes: 0

Alnitak
Alnitak

Reputation: 339786

What you're missing is that each of the inner arrays needs to be malloc'ed too.

int **matrix = malloc(x * sizeof(int *));

should be something like:

int **matrix = (int **)malloc(y * sizeof(int *));
for (i = 0; i < y; ++i) {
    matrix[i] = (int *)malloc(x * sizeof(int));
}

That said, most matrix libraries I'm aware of would just use:

int *matrix = (int *)malloc(x * y * sizeof(int));

and then use:

int n = matrix[y * cols + x];

to read the individual elements. For (non-sparse) matrices this is more efficent than having a separately allocated block for each row. It also guarantees that the data is contiguous in memory which can make CPU caches more effective.

Upvotes: 4

Tristan
Tristan

Reputation: 916

Can you not just use a one-dimensional array and store by rows or columns? Then you would just access the array elements using array[row * numcols + col] instead of array[row][col] .

It really doesn't make any difference internally, as the memory doesn't care if you use two dimensions or one.

Upvotes: 0

Related Questions