Given the rise of VLA since c99 it has become easier to pass a multidimensional array of unknown size to a function. But there is a decent amount of controversy around using VLAs. Some readily endorse it "It is often nicer
to use dynamic memory, alloca() or VLAs."1 others scorne them. The question I was asking myself is what the standard way was in the c90 days to passing a multidimensional array to a function. Here is a little code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int arr[2][4];
int i;
int j;
for(i = 0; i < 2; i++) {
for(j = 0; j < 4; j++) {
arr[i][j] = j;
}
}
exit(EXIT_SUCCESS);
}
I could think of one way: passing a pointer to a pointer:
void foo_a(int m, int n, int **ptr_arr)
{
int i, j;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
ptr_arr[i][j] += 1;
}
printf("\n");
}
}
But that would involve flattening the array first by inserting something like into main (which is not pretty).
int *unidim_arr[ROW];
for (i = 0; i < ROW; i++) {
unidim_arr[i] = &(arr[i][0]);
}
Another one would probably be using a single pointer and calculating the offset by hand which is error prone:
void foo_b(int m, int n, int *ptr_arr)
{
int i, j;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
*((ptr_arr + i * n) + j) += 1;
}
}
}
The solution that strikes me as nicest is using something like
void foo_c(int m, int n, int (*ptr_arr)[])
{
int i, j;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
ptr_arr[i][j] += 1;
}
}
}
but to my understanding this would only work with VLAs where I can simply specify (*ptr_arr)[n] in the functions parameter list? Is there another way to do it in c90 with special attention to foo_c()?
1. Please, no systemd-bashing.
One method is to pass a pointer to the first element of the array along with the array dimensions, then treat that pointer as a 1-d array in your function.
Example:
void foo( int *arr, size_t r, size_t c ) // process a 2D array defined as int arr[r][c]
{
for ( size_t i = 0; i < r; i++ )
for ( size_t j = 0; j < c; j++ )
arr[i * r + j] = some_value(); // calculate index manually
}
int main( void )
{
int arr[4][5];
foo( &arr[0][0], 4, 5 );
}
This scales up pretty easily to higher dimensioned arrays. Naturally this only works for true multi-dimensional arrays where the rows are all adjacent in memory. This won't work for arrays dynamically allocated a row at a time, such as
int **arr = malloc( sizeof *arr * rows );
for ( size_t i = 0; i < rows; i++ )
arr[i] = malloc( sizeof *arr[i] * cols );
since the rows aren't guaranteed to be adjacent, but in that case you'd just use the arr pointer as-is:
void bar( int **arr, size_t r, size_t c ) // process a 2D array defined as int **arr
{
for ( size_t i = 0; i < r; i++ )
for ( size_t j = 0; j < c; j++ )
arr[i][j] = some_value();
}
Related
This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 13 days ago.
I wrote this program that is supposed to sort NxN array. It gets compiled but doesn't work because the pointer type is incompatible.
I just need help with the pointers as argument. I get incompatible pointer type warning for both functions swap and dblArraySort. Any idea why is that ?
thanks in advance !
#include <stdio.h>
#include <stdlib.h>
void
swap(int **a, int **b)
{
int temp;
temp = **a;
**a = **b;
**b = temp;
}
void
dblArraySort(int **dblArray, int arrLen)
{
int chkIndex;
int i, j, k;
for (i = 0; i < arrLen; i++) {
if ((i + 1) % 2 == 0) {
for (j = 0; j < arrLen; j++) {
chkIndex = dblArray[i][j];
for (k = 1; k + j < arrLen; k++)
if (chkIndex < dblArray[i][k + j])
swap(&dblArray[i][j], &dblArray[i][k + j]);
else
continue;
}
} else {
for (j = 0; j < arrLen; j++) {
chkIndex = dblArray[i][j];
for (k = 1; k + j < arrLen; k++)
if (chkIndex >= dblArray[i][k + j])
swap(&dblArray[i][j], &dblArray[i][k + j]);
else
continue;
}
}
}
}
int
main()
{
unsigned int arrayLength;
printf("Provide array size: \n");
scanf("%d", &arrayLength);
int doubleArray[arrayLength][arrayLength];
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength; j++) {
scanf("%d", &doubleArray[i][j]);
}
}
dblArraySort(doubleArray, arrayLength);
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength; j++) {
printf("%d ", doubleArray[i][j]);
}
printf("\n");
}
return 0;
}
I tried the code mentioned above
Arrays in C can be confusing. The thing you need to worry about is element type.
The element type of int ** dblArray is int *. In other words, dblArray is an array of int *s.
However, the element type of int doubleArray[arrayLength][arrayLength] is int row_type[arrayLength]. That is not an int *, that is an array, which is a totally different thing.
Moreover, when you use an array⟶pointer conversion, as happens when you say:
dblArraySort(doubleArray, arrayLength); // doubleArray is converted to a pointer
You get a pointer to the array, which in this case is a pointer to the innermost element type, an int — which is also not an int *.
tl;dr: You are trying to pass an array of array of int to a function taking an array of pointer to int. That won’t work.
I would like to comment on your variable naming as well. When you say “double” or “dbl”, as in doubleArray and dblArray the very first thing people will think is that you are handling a linear array of type double, which is also not what the array is.
You have there a two-dimensional array. Not a “double” array. Common naming for such thing would be array2D or matrix.
To make it work you need either C11, which allows you to pass a VLA as:
void sort_array2D( size_t rows, size_t columns, int array[rows][columns] )
{
...
int value = array[i][j];
...
}
int main(void)
{
int array2D[Array_Length][Array_Length];
...
sort_array2D( Array_Length, Array_Length, array2D );
Or you need to simply assume you must compute the index manually. A little function will help:
size_t index2D( size_t rows, size_t columns, size_t r, size_t c )
{
(void)rows; // (quiet the compiler about not using this argument)
return r * columns + c;
}
Then you can write your function as:
void sort_array2D( int * array, size_t rows, size_t columns )
{
...
int value = array[index2D( rows, columns, i, j )];
...
}
int main(void)
{
int array2D[Array_Length][Array_Length];
...
sort_array2D( (int *)array2D, Array_Length, Array_Length );
I haven’t bothered to analyze your sort function. It doesn’t look right to me, but honestly, I’ve barely glanced at it. Calling a value from the array chkIndex looks fishy, since the values of the array are not indices per se, at least not in the context of sorting them.
Remember, when messing with arrays in C you need to keep strict care to not mix up the type of the elements. (Or the types of things in general, whether syntactic or conceptual.)
Related to dynamic allocation inside a function, most questions & answers are based on double pointers.
But I was recommended to avoid using double pointer unless I have to, so I want to allocate a 'array pointer' (not 'array of pointer') and hide it inside a function.
int (*arr1d) = calloc(dim1, sizeof(*arr1d));
int (*arr2d)[dim2] = calloc(dim1, sizeof(*arr2d));
Since the above lines are the typical dynamic-allocation of pointer of array, I tried the following.
#include <stdio.h>
#include <stdlib.h>
int allocateArray1D(int n, int **arr) {
*arr = calloc(n, sizeof(*arr));
for (int i = 0; i < n; i++) {
(*arr)[i] = i;
}
return 0;
}
int allocateArray2D(int nx, int ny, int *(*arr)[ny]) {
*arr[ny] = calloc(nx, sizeof(*arr));
for (int i = 0; i < nx; i++) {
for (int j = 0; j < ny; j++) {
(*arr)[i][j] = 10 * i + j;
}
}
return 0;
}
int main() {
int nx = 3;
int ny = 2;
int *arr1d = NULL; // (1)
allocateArray1D(nx, &arr1d);
int(*arr2d)[ny] = NULL; // (2)
allocateArray2D(nx, ny, &arr2d);
for (int i = 0; i < nx; i++) {
printf("arr1d[%d] = %d \n", i, arr1d[i]);
}
printf("\n");
printf("arr2d \n");
for (int i = 0; i < nx; i++) {
for (int j = 0; j < ny; j++) {
printf(" %d ", arr2d[i][j]);
}
printf("\n");
}
return 0;
}
And the error message already comes during the compilation.
03.c(32): warning #167: argument of type "int (**)[ny]" is incompatible with parameter of type "int *(*)[*]"
allocateArray2D(nx, ny, &arr2d);
^
It is evident from the error message that it has been messed up with the argument types (that I wrote as int *(*arr)[ny]) but what should I have to put there? I tried some variants like int *((*arr)[ny]), but didn't work).
And if I remove the 2D parts, then the code well compiles, and run as expected. But I wonder if this is the right practice, at least for 1D case since there are many examples where the code behaves as expected, but in fact there were wrong or un-standard lines.
Also, the above code is not satisfactory in the first place. I want to even remove the lines in main() that I marked as (1) and (2).
So in the end I want a code something like this, but all with the 'array pointers'.
int **arr2d;
allocateArray2D(nx, ny, arr2d);
How could this be done?
You need to pass the array pointer by reference (not pass an array pointer to an array of int*):
int *(*arr)[ny] -> int (**arr)[ny]
The function becomes:
int allocateArray2D(int nx, int ny, int (**arr)[ny]) {
*arr = calloc(nx, sizeof(int[ny])); // or sizeof(**arr)
for (int i = 0; i < nx; i++) {
for (int j = 0; j < ny; j++) {
(*arr)[i][j] = 10 * i + j;
}
}
return 0;
}
For details, check out Correctly allocating multi-dimensional arrays
Best practices with malloc family is to always check if allocation succeeded and always free() at the end of the program.
As a micro-optimization, I'd rather recommend to use *arr = malloc( sizeof(int[nx][ny]) );, since calloc just creates pointless overhead bloat in the form of zero initialization. There's no use of it here since every item is assigned explicitly anyway.
Wrong parameter type
Strange allocation
Wrong size type
I would return the array as void * too (at least to check if allocation did not fail).
void *allocateArray2D(size_t nx, size_t ny, int (**arr)[ny]) {
//*arr = calloc(nx, sizeof(**arr)); calloc is not needed here as you assign values to the array
*arr = malloc(nx * sizeof(**arr));
for (size_t i = 0; i < nx; i++) {
for (size_t j = 0; j < ny; j++) {
(*arr)[i][j] = 10 * i + j;
}
}
return *arr;
}
I'm new to c but I have been trying for ages to try and get this to work even though it seems so simple.
So below is what I am aiming to do which is working but I want to make 2 functions: fillseats() and printseatingplan()[for now I just want them all blank];
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main()
{
char seatingplan[15][15];
memset(seatingplan,'.',sizeof seatingplan);
for (int k = 0; k < 15; ++k)
{
for(int j = 0; j < 15; ++j)
{
printf("%c",seatingplan[k][j]);
}
printf("\n");
}
}
So whenever I try to run these functions without pointers it gives me these �`:�ij:�
i�d:�iH#=�i
�B��ik:�
how can i use pointers to fix this
can I pass this array into the functions where printseatingplan()
void printseatingplan(char array[15][15])
{
for (int k = 0; k < 15; ++k)
{
for(int j = 0; j < 15; ++j)
{
printf("%c",array[k][j]);
}
printf("\n");
}
}
and then fillseats() does:
void fillseats(char array[15][15])
{
memset(array,'.',sizeof array);
}
sizeof will give you only the size of the pointer, not the whole array.
You need to pass the sizes to the function. I would use pointer to array:
void fillseats(size_t rows, size_t cols, char (*array)[cols])
{
memset(array,'.',rows * sizeof(*array));
}
void printseatingplan(size_t rows, size_t cols, char (*array)[cols])
{
for (size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
printf("%c",array[row][col]);
}
printf("\n");
}
}
char array[15][15] when used as parameter to a function "decays" into a pointer to the first element, in this case equivalent to char (*array)[15]). If you do sizeof array instead the function, you get the size of a pointer (4 or 8 etc). If you do sizeof *array you just get the size of one dimension, 15.
A simple way to fix it:
#include <stdio.h>
#include <string.h>
void fillseats (size_t x, size_t y, char array[x][y])
{
memset(array, '.', sizeof(char[x][y]));
}
void printseatingplan (size_t x, size_t y, char array[x][y])
{
for (size_t i = 0; i < x; i++)
{
for(size_t j = 0; j < y; j++)
{
printf("%c",array[i][j]);
}
printf("\n");
}
}
int main (void)
{
char seatingplan[15][15];
fillseats(15, 15, seatingplan);
printseatingplan(15, 15, seatingplan);
}
The size of array is bound to its type. The problem is that the parameters of array type decay to pointers. To prevent it, you can pass a pointer to an array. The pointer don't decay thus the essential part of the array type prevails.
void printseatingplan(char (*array)[15][15])
{
for (int k = 0; k < 15; ++k)
{
for(int j = 0; j < 15; ++j)
{
printf("%c", (*array)[k][j]);
}
printf("\n");
}
}
void fillseats(char (*array)[15][15])
{
memset(*array,'.',sizeof *array);
}
int main (void)
{
char seatingplan[15][15];
fillseats(&seatingplan);
printseatingplan(&seatingplan);
}
I'm writing a C for which I need to create a 2D array. I've found a solution to my problem using double pointers (pointers to pointers) in the following way:
#include <stdio.h>
#include <stdlib.h>
int d = 3;
#define DIM_MAX 9
void changeArray(int d, int *array[d]);
int main()
{
//alocate array of 'd' colummns and 'd' row using malloc using array of pointers
int **array = malloc(d*sizeof(int *));
for(int count = 0; count < d; count++)
{
array[count] = malloc(d*sizeof(int *));
}
/* Call changeArray function */
changeArray(d, array);
for(int i = 0; i < d; i++)
{
for(int j = 0; j < d; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
for(int count = 0; count < d; count++)
{
free(array[count]);
}
return 0;
}
void changeArray(int n, int *array[d])
{
for(int i =0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
array[i][j] = i*j;
}
}
return;
}
The code above works pretty well (it seems), but I've read in the web that using pointer to pointer is not the correct way to create 2D arrays. So I've come up with the following code, which also works:
#include <stdio.h>
#include <stdlib.h>
#define DIM_MAX 9
int d = 3;
void changeArray(int d, int *array[d]);
int main()
{
//alocate array of 'd' colummns and 'd' row using malloc using array of pointers
int *array[DIM_MAX] = {0};
for(int count = 0; count < d; count++)
{
array[count] = (int *)malloc(d*sizeof(int *));
}
/* Call changeArray function */
changeArray(d, array);
for(int i = 0; i < d; i++)
{
for(int j = 0; j < d; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
for(int count = 0; count < d; count++)
{
free(array[count]);
}
return 0;
}
void changeArray(int n, int *array[d])
{
for(int i =0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
array[i][j] = i*j;
}
}
return;
}
What is the difference in using any of the two ways above to write this code?
[Not an answer, but an alternative approach to achieve the desired result, namely defining a user-defined 2D array.]
Assuming the compiler in use supports VLAs you could do this:
#include <stddef.h> /* for size_t */
void init_a(size_t x, size_t y, int a[x][y]); /* Order matters here!
1st give the dimensions, then the array. */
{
for (size_t i = 0; i < x; ++i)
{
for (size_t j = 0; j < y; ++j)
{
a[i][j] = (int) (i * j); /* or whatever values you need ... */
}
}
}
int main(void)
{
size_t x, y;
/* Read in x and y from where ever ... */
{
int a[x][y]; /* Define array of user specified size. */
init_a(x, y, a); /* "Initialise" the array's elements. */
...
}
}
It is actually pretty simple. All you have to do is this:
int i[][];
You are overthinking it. Same as a normal array, but has two indexes.
Let's say you want to create a "table" of 4 x 4. You will need to malloc space for 4 pointers, first. Each of those index points will contain a pointer which references the location in memory where your [sub] array begins (in this case, let's say the first pointer points to the location in memory where your first of four arrays is). Now this array needs to be malloc for 4 "spaces" (in this case, let's assume of type INT). (so array[0] = the first array) If you wanted to set the values 1, 2, 3, 4 within that array, you'd be specifying array[0][0], array[0][1], array[0][2], array[0][3]. This would then be repeated for the other 3 arrays that create this table.
Hope this helps!
I need to define function for allocation 2D array, but it should call malloc only once.
I know how to allocate it (-std=c99):
int (*p)[cols] = malloc (sizeof(*p) * rows);
But i can't figure out how to return it from function. Return isn't option, because the array will stop existing once the function ends (or at least part of it). So, only options to pass array to this function is as parametr, but the solution above needs to have defined number of cols at the declaration. Is it even possible?
Thanks.
Thanks to user kotlomoy i managed to solve this issue like this:
...
#define COLS 10
#define ROWS 5
int (*Alloc2D())[COLS]
{
int (*p)[COLS] = malloc(sizeof(*p) * ROWS);
return p;
}
//and this is example how to use it, its not elegant,
//but i was just learning what is possible with C
int main(int argc, char **argv)
{
int (*p)[COLS] = Alloc2D();
for (int i = 0; i < ROWS; i++)
for(int j = 0; j < COLS; j++)
p[i][j] = j;
for (int i = 0; i < ROWS; i++){
for(int j = 0; j < COLS; j++)
printf("%d", p[i][j]);
printf("\n");
}
return 0;
}
int * Alloc2D(int rows, int cols)
{
return malloc(sizeof(int) * rows * cols);
}
Usage.
To allocate:
int * array = Alloc2D( rows, cols );
To get element [i,j]:
array[ cols * i + j ]
And don't forget to clean memory:
free( array );