Reputation: 33
I'm trying to create a 2-D array inside a function, and then use it elsewhere, but I'm stuck everywhere with incompatible pointer types. (I know, similar topics has been discussed, but still can't clearly figure it out from the existing boards.)
So here is the story:
I can pass an array to a function like this (with c99 allowed):
int func1(int N, int arr[][N]);
int main()
{
int N=<something>,M=<something>;
int array1[N][N];
func1(N, array1);
}
My understanding is, that array1 is effectively a pointer () though i'm unsure of it's type (is it same as int *p
or else?)
Now, the issue is that I'm trying to create this 2-D array by using a function (which scans the array dimensions to a certain variables, allocates memory for the array, fills it with data, and returns a pointer, to be used in the future), such as:
int *input_array(int *size_x,int *size_y)
{
scanf("%d",size_x); //recieve array dimensions
scanf("%d",size_y); //recieve array dimensions
int *arr=malloc((*size_x)*(*size_y)*sizeof(int));
if(!arr) return 0; //validate allocation success
for(int i=0; i<(*size_x); i++) {
for(int j=0; j<(*size_y); j++) {
scanf("%d",arr[i][j]); //fill input data in to array <- FAILS
}
}
return arr; //return pointer to the start of arr[][]
}
There is compilation failure on the scanf("%d",&arr[i][j]);
line, due to incompatible arr
type.
So, how can I convert int *p
to the same type as int arr[][]
(and what is exactly it's type), so I can reuse it elsewhere in the program? Or maybe I make create the allocation of a different type for this matter?
Thanks in advance!
Upvotes: 1
Views: 121
Reputation: 222526
To do this using variable-length arrays (which you already are using, and which were a part of C 1999 but are optional in C 2011), make two changes. Inside the function input_array
, change the malloc
statement from:
int *arr=malloc((*size_x)*(*size_y)*sizeof(int));
to:
int (*arr)[*size_y] = malloc(*size_x * sizeof *arr);
This defines arr
to be a pointer to an array of *size_y
int
, so it acts like an array of arrays, which is the two-dimensional array you wanted.
Second, since arr
is a pointer to an array of int
, you should not return it as an int *
, so the return type must be changed. Unfortunately, you cannot declare the return type in advance since you do not know the second dimension of the array at compile time. So you must return it in the same form malloc
gives it to you, a void *
:
void *input_array(int *size_x, int *size_y)
Then the caller of input_array
must cast it to a pointer of the appropriate type:
void *temporary = *input_array(&size_x, &size_y);
if (!temporary) HandleError;
int (*array)[size_y] = temporary;
There are two other ways to handle two-dimensional arrays.
One is to allocate the space as a one-dimensional array of int
(or other element) and use your own arithmetic to convert two-dimensional indices into one-dimension (mapping row i
and column j
to element i*NumberOfColumns + j
). You might write small functions or preprocessor macros to make the indexing look a little nicer. This is essentially the same thing the compiler does when you use variable-length arrays, but it is usable in compilers that do not support variable-length arrays.
Another method often suggested on Stack Overflow is to create an array of pointers and initialize them to point to rows of the array. So, if p
is a pointer to the array of pointers, then p[i]
is one of the pointers (so it points to a row of the array), and p[i][j]
is an element in that row. This is generally a bad solution, for several reasons. One, it consumes more space. Two, it requires an extra memory load (to get the second pointer). Three, it interferes with optimization by the compiler.
On the latter point, when you have a variable-length array or a one-dimensional array with manually calculated indices, the compiler can see that a[i][j]
and a[i+1][j]
refer to different elements, so it can optimize operations on these elements to execute in parallel. In the pointer method, a[i]
and a[i+1]
are pointers to rows, and the compiler generally cannot know whether they point to the same row or to overlapping rows, and this prevents it from optimization uses of a[i][j]
and a[i+1][j]
.
Upvotes: 1
Reputation: 714
I think you need an array of pointers each assigned an array of integers.
int** makeTable(int size_x, int size_y){
int z;
int** table;
/* get an array of pointers of length x */
table = malloc(sizeof(int*) * size_x);
for(z = 0; z < size_x; z++){
/* call calloc to zero out an array */
table[z] = calloc(sizeof(int), size_y);
}
return table;
}
then you can use table[i][j]
Upvotes: 0
Reputation: 5289
First the error you're getting: you have to explicitly convert the void* type from malloc to int*:
int *arr= (int*) malloc((*size_x)*(*size_y)*sizeof(int));
Second, if you allocate just a block of RAM, you would have to calculate the array index for yourself. For example:
arr[y*(*size_x)+x] = 123;
So you have to allocate an array for (*size_x) number of int*
pointers, and then you have to allocate (*size_x) number of separate int
arrays with size of (*size_y) each and store their pointers into the int*
array. Then you could use the arr[x][y]
notation.
Upvotes: 0
Reputation: 672
This might Help You
if (( c = ( int** )malloc( N*sizeof( int* ))) == NULL )
{ /* error */ }
for ( i = 0; i < N; i++ )
{
/* x_i here is the size of given row, need to
* multiply by sizeof( int )
*/
if (( c[i] = ( int* )malloc( x_i )) == NULL )
{ /* error */ }
/* probably init the row here */
}
Upvotes: 2