I'm trying to allocate a 2d array in a C program. It works fine in the main function like this (as explained here ):
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv)
{
int ** grid;
int i, nrows=10, ncols=10;
grid = malloc( sizeof(int *) * nrows);
if (grid == NULL){
printf("ERROR: out of memory\n");
return 1;
}
for (i=0;i<nrows;i++){
grid[i] = malloc( sizeof(int) * ncols);
if (grid[i] == NULL){
printf("ERROR: out of memory\n");
return 1;
}
}
printf("Allocated!\n");
grid[5][6] = 15;
printf("%d\n", grid[5][6]);
return 0;
}
But since I have to do this several times with different arrays, I was trying to move the code into a separate function.
#include <stdio.h>
#include <stdlib.h>
int malloc2d(int ** grid, int nrows, int ncols){
int i;
grid = malloc( sizeof(int *) * nrows);
if (grid == NULL){
printf("ERROR: out of memory\n");
return 1;
}
for (i=0;i<nrows;i++){
grid[i] = malloc( sizeof(int) * ncols);
if (grid[i] == NULL){
printf("ERROR: out of memory\n");
return 1;
}
}
printf("Allocated!\n");
return 0;
}
int main(int argc, char ** argv)
{
int ** grid;
malloc2d(grid, 10, 10);
grid[5][6] = 15;
printf("%d\n", grid[5][6]);
return 0;
}
However, although it doesn't complain while allocating, I get segmentation fault when accessing the array. I read different posts on decayed arrays and similar topics, but I still can't figure out how to solve this problem. I imagine I'm not passing the 2d array correctly to the function.
Many thanks.
That is not a multidimensional array; it is a single dimensional array containing pointers to single dimensional arrays. Multidimensional arrays do not contain pointers; they are single memory blocks.
Your problem here is that you have a pointer to a pointer, and you're trying to return it from your function through a parameter. If you're going to do that, you're going to need a pointer to a pointer to a pointer as your parameter, and you're going to have to pass the address of a pointer to a pointer to the method. If you don't do this, you're not changing the value of the variable grid
in main
-- you're changing the one which was copied as the parameter to the malloc2d
function. Because the grid
in main
is left uninitialized, you get a undefined behavior.
Here's an example of what I mean as the fix:
#include <stdio.h>
#include <stdlib.h>
int malloc2d(int *** grid, int nrows, int ncols){
int i;
*grid = malloc( sizeof(int *) * nrows);
if (*grid == NULL){
printf("ERROR: out of memory\n");
return 1;
}
for (i=0;i<nrows;i++){
(*grid)[i] = malloc( sizeof(int) * ncols);
if ((*grid)[i] == NULL){
printf("ERROR: out of memory\n");
return 1;
}
}
printf("Allocated!\n");
return 0;
}
int main(int argc, char ** argv)
{
int ** grid;
malloc2d(&grid, 10, 10);
grid[5][6] = 15;
printf("%d\n", grid[5][6]);
return 0;
}
Additional notes:
free
on those before returning.int **
, and signal error by returning 0
.Here is your function, fixed:
int malloc2d(int *** grid, int nrows, int ncols){
int i;
*grid = (int**)malloc( sizeof(int *) * nrows);
if (*grid == NULL){
printf("ERROR: out of memory\n");
return 1;
}
for (i=0;i<nrows;i++){
(*grid)[i] = (int*)malloc( sizeof(int) * ncols);
if ((*grid)[i] == NULL){
printf("ERROR: out of memory\n");
return 1;
}
}
printf("Allocated!\n");
return 0;
}
int main(int argc, char ** argv)
{
int ** grid;
malloc2d(&grid, 10, 10);
grid[5][6] = 15;
printf("%d\n", grid[5][6]);
return 0;
}
Note the function now recieves an int***
and you pass the address of your int**
to the function. The function then dereferences the int***
to put the address of the allocated memory block in it.
C is pass by value. And to sum up the error you are doing, this example should be helpful -
void foo( int *temp )
{
temp = malloc(sizeof(int)) ;
// temp is assigned to point to new location but the actual variable
// passed from main do not point to the location temp is pointing to.
*temp = 10 ;
}
int main()
{
int *ptr ;
foo( ptr ) ;
// ptr is still unintialized
*ptr = 5 ; // Segmentation fault or Undefined behavior
return 0;
}
So, instead you should do -
void foo( int **temp )
{
*temp = malloc(sizeof (int) );
// ...
}
And now call the function as foo(&ptr);
in the main()
function.
If you still want malloc2d
to return a status code, the parameter needs to be of type int***
:
int malloc2d(int *** grid, int nrows, int ncols){
And you need to use *grid
to refer to the supplied buffer:
int i;
*grid = malloc( sizeof(int *) * nrows);
if (*grid == NULL){
printf("ERROR: out of memory\n");
return 1;
}
for (i=0;i<nrows;i++){
(*grid)[i] = malloc( sizeof(int) * ncols);
if ((*grid)[i] == NULL){
printf("ERROR: out of memory\n");
return 1;
}
}
printf("Allocated!\n");
return 0;
}
Then, when calling malloc2d
, pass it the address of an int**
to fill in:
int ** grid;
malloc2d(&grid, 10, 10);
C is actually always pass by value, so when you pass in 'grid' you are passing in a value and the function is modifying its own local copy. Try passing in '&grid' instead and modify malloc2d appropriately.
That's not your about your segmentation fault problem, but you should really consider to use a single malloc call to allocate all necessary memory space need by grid.
grid = malloc (nrows * ncols * sizeof(int *))
Look at Bill ONeary answer regarding pointer of pointer of pointer.
Shorter should be below, with free (:) and initialized values for each grid element:
#include <stdio.h>
#include <stdlib.h>
#define NROWS 10
#define NCOLS 10
int main()
{
int (* grid)[NCOLS] = calloc(NROWS,sizeof*grid);
/* no more needed here malloc2d(grid, 10, 10); */
grid[5][6] = 15;
printf("%d\n", grid[5][6]);
free(grid); /* every c/malloc need a free */
return 0;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.