However, I'm having issues understanding:
- How you would access elements in this matrix inside the function. Can you still use the notation mat[i][j]?
- How you would declare and populate such a matrix. Do you begin with something like int **mat;? I'm thinking you'd have to use malloc(),
but I'm having a hard time figuring out the exact declaration
statement.
- Can matrices even be used like pointers to pointers like that? I have read that they work similarly but not exactly the same. How do
you solve the outlined problem in C89?
1. mat[i][j]
In C89, you are correct, you have no support for VLAs unless provided by a non-standard compiler extension (gcc does so). However, you can accomplish the same in two different arrays.
If you know the number of columns you will have at compile time and can define a constant for that value, then you can declare a pointer-to-array [COLS]. For example, if you know you will have 32 columns and an unknown number of rows, you can do:
#define COLS 32
...
int (*array)[COLS] = malloc (rows * sizeof *array);
That will allocate a block of memory in a single call providing storage for rows
number of int[32]
arrays allowing you access as array[i][j]
just as before. The beauty of using a pointer-to-array is you have a single-allocation and single-free. You can realloc
the number of rows as needed.
(note: as @PaulOgilvie points out, there is a difference in how you can pass the pointer to array to a function. You cannot pass as int array[][cols]
as with a VLA, you must pass as int (*array)[cols]
-- which you can also use with a VLA, but the reverse does not hold true)
Your other option is the declare a pointer-to-pointer-to type
(e.g. int **array;
). Note there is NO array involved here, it is simply a single pointer to pointer to type. Here allocation is a 2-step process. You first allocate memory for some number of pointers (rows number of pointers). For example:
int **array = malloc (rows * sizeof *array);
Above you allocate a block of memory capable of holding rows
number of pointers to which you can then separately allocate and assign blocks of memory to hold any number of integer values (there is no need that each row point to a block with the same number of integer values -- making a "jagged array" possible, for lack of better words) To then allocate storage for integers values (or whatever type you are using), you would do:
for (int i = 0; i < rows; i++)
array[i] = malloc (cols * sizeof *array[i]);
(note: you must validate every allocation which has been omitted for brevity. Also note in both cases above the dereferenced pointer has been used to set the typesize for allocation, e.g. malloc (rows * sizeof *array)
which could have been malloc (rows * sizeof(int*)))
. If you always use the dereferenced pointer to set typesize -- you will never get the type-size wrong)
At this point you have a pointer to a block of memory storing rows
number of pointers, and then you have assigned a block of memory capable of holding cols
number of integer values which you can access as array[i][j]
. Additionally, here you can realloc
the block of memory providing rows
pointers to add rows any time you need, but you have to allocate storage for integer values as well and assign those allocated blocks to your new row pointers before you attempt to store values there.
When you are done with your simulated 2D array based on a pointer-to-pointer you have a 2-step free as well. You must free the allocated blocks storing integers before you can free the block holding your rows pointers, e.g.
for (int i = 0; i < rows; i++)
free (array[i]); /* free storage for integers */
free (array); /* free pointers */
2. Populating Either Object
In either case since you can access your simulated 2D array with array[i][j]
notation, you can now fill and access the values in array
just as you did with a 2D VLA under C99+.
3. Can Matricies Be used with Pointers to Pointers
Yep, the simulated 2D array provides the exact same functionality as described above.
malloc()
. 3: Yes, when passed as an argument, a matrix decays into a pointer to pointer, just like an array decays into a pointer. – Rootfor(size_t i = 0; i < rows; i++) {
for(size_t j = 0; j < cols; j++) {
scanf("%d", &mat[i][j]); /*using scanf as an example, could be anything*/
}
}
I suppose that in this case I would have to allocate a new element for each spot in the matrix? – Glomerule