The code works if i use the name of the struct array directly for the allocation, but not from the function argument. Otherwise it returns memory error.
typedef struct COORD
{
int xp;
int yp;
} coord;
coord** xy;
void allocate(coord** COORD)
{
int i;
//allocate COORD[500][460]
COORD = (coord**)malloc(sizeof(coord*)*500);
for(i=0; i<500; i++)
{
COORD[i] = (coord*)malloc(sizeof(coord)*460);
}
// freeing
for (i=0; i<500; i++) free(COORD[i]);
free(COORD);
}
//function call: allocate(xy);
//That is the code that leeds to the error
Using just xy instead of COORD works. And i am all wondering why is that not working.
You are mixing up various coding styles here. It's not clear what exactly you want to achieve. Pick one according to your task.
Temporary buffer
You need a large temporary buffer that should be allocated on the heap and that does not need to be seen from outside. Just create a local variable:
void do_stuff(int w, int h)
{
coord **p;
int i;
p = malloc(h * sizeof(*p));
for (i = 0; i < h; i++) p[i] = malloc(w * sizeof(**p));;
// do stuff
for (i = 0; i < h; i++) free(p[i]);
free(p);
}
Allocate memory for further use
You want to allocate storage that your client code can use. Then provide two functions, one that allocates and one that frees the memory:
coord **create(int w, int h)
{
coord **p;
int i;
p = malloc(h * sizeof(*p));
for (i = 0; i < h; i++) p[i] = malloc(w * sizeof(**p));
return p;
}
void destroy(coord **p, int h)
{
int i;
for (i = 0; i < h; i++) free(p[i]);
free(p);
}
Your client code can then use the memory between these calls:
coord **p = create(500, 460);
// do stuff
drestroy(p, 500);
(Note that you have to pass the height to destroy, which is a bit unfortunate. It might be cleaner to create a wrapper struct that hold information about width and height and the pointer.)
Allocate memory for a global variable
You have a single instance of a global pointer. Then your functions always operate on that pointer and you don't need any further information on it (except the dimensions):
coord **global = NULL;
void destroy_global(int h)
{
int i;
for (i = 0; i < h; i++) free(global[i]);
free(global);
global = NULL;
}
void create_global(int w, int h)
{
int i;
if (global != NULL) free_global();
global = alloc(h * sizeof(*global));
for (i = 0; i < h; i++) global[i] = malloc(w * sizeof(**global));
}
Note that you should include <stdlib.h> for all memory functions and the NULL macro.
Addendum According to your comment, you want to allocate memory for a bitmap. That's option 2 above.
I recommend to create an object structure. You can pass a pointerv to that structure as handle to a bunch of functions. You can create the object with a function that returns that handle.
The following sketches a rough design for a bitmap object.
typedef struct Pixel Pixel;
typedef struct Bitmap Bitmap;
struct Pixel {
uint8_t r, g, b;
};
struct Bitmap {
int height;
int width;
Pixel **pixel;
};
Bitmap *bitmap_new(int w, int h)
{
Bitmap *bmp = malloc(sizeof(*bmp));
int i;
bmp->height = h;
bmp->width = w;
bmp->pixel = malloc(h * sizeof(*bmp->pixel));
for (i = 0; i < h; i++) {
bmp->pixel[i] = malloc(w * sizeof(**bmp->pixel));
}
return p;
}
void bitmap_delete(Bitmap *bmp)
{
int i;
for (i = 0; i < h; i++) free(bmp->pixel[i]);
free(bmp->pixel);
free(bmp);
}
Bitmap *bitmap_read(const char *fn)
{
Bitmap *bmp;
FILE *f = fopen(fn, "rb");
// read and allocate
return bmp;
}
void bitmap_blank(Bitmap *bmp, int r, int g, int b)
{
for (i = 0; i < bitmap->height; i++) {
for (j = 0; j < bitmap->width; j++) {
bmp->pixel[i][j].r = r;
bmp->pixel[i][j].g = g;
bmp->pixel[i][j].b = b;
}
}
}
void bitmap_mirror_x(Bitmap *bmp)
{
// do stuff
}
int bitmap_write(Bitmap *bmp, const char *fn)
{
FILE *f = fopen(fn, "rb");
// write bitmap to file
return 0;
}
The design is similar to the interface to FILE *: fopen gives you a handle (or NULL; error checking is omitted in the code above) and fread, fprintf, fseek and family take a pointer to the file as argument. Finally call fclose to close the file on disk and to free any ressources fopen has claimed.
Have you tried to compile this code? There are a number of errors.
First, the type of main should always be 'int main(int argc, char *argv[])'
Second, you need to '#include <stdlib.h>' at the top of your file to get the return type of malloc/free and friends.
Third, you are not declaring 'i'.
Fourth, you are using the same name 'COORD' as both a struct name and as a variable. Don't do this, it will cause you problems.
Sending incorrect code makes it very difficult to figure out what the root of your problem is, but I suspect it's the overloading of 'COORD'.
typedef struct COORD
{
int xp;
int yp;
} coord;
coord** xy;
void allocate(coord** COORD)
{
int i;
//allocate COORD[500][460]
COORD = (coord**)malloc(sizeof(coord*)*500);
for(i=0; i<500; i++)
{
COORD[i] = (coord*)malloc(sizeof(coord)*460);
}
// freeing
for (i=0; i<500; i++) free(COORD[i]);
free(COORD);
}
//function call: allocate();
//That is the code that works
The problem is that the function allocate() cannot change the value of xy outside itself. This is because C is call by value, the called function only gets the values of its arguments, not any kind of references to the expressions in the caller's context.
It needs to be:
void allocate(coord ***c)
{
}
and:
coord **xy;
allocate(&xy);
which of course is silly: the proper design would be for allocate() to return the new address:
coord ** allocate(void)
{
}
with use like:
coord **xy = allocate();
Probably it would be even better to have the dimensions as parameters to the function, since magic numbers are generally not a good thing:
coord ** allocate(size_t width, size_t height);
typedef struct
{
int xp;
int yp;
} Coord;
Coord **xy;
Coord** allocate(size_t height, size_t width)
{
int i;
Coord **arr;
arr = malloc(sizeof(Coord*)*height);
for(i=0; i<height; i++) {
arr[i] = malloc(sizeof(coord)*width);
}
return arr;
}
void allocate2(Coord ***p_arr, size_t height, size_t width)
{
int i;
Coord **arr;
arr = *p_arr;
arr = malloc(sizeof(Coord*)*height);
for(i=0; i<height; i++) {
arr[i] = malloc(sizeof(coord)*width);
}
}
void deallocate(Coord **arr, size_t height)
{
for (i=0; i<500; i++) {
free(arr[i]);
}
free(arr);
}
int main()
{
Coord **arr_2;
Coord ***p_arr_3;
allocate2(&xy, 500, 460);
/* do something with global array, xy, e.g. */
xy[1][2].xp = 100;
xy[1][2].yp = 200;
deallocate(xy, 500);
arr_2 = allocate(500, 460);
/* do something with local array, arr_2 */
deallocate(arr_2, 500);
allocate2(p_arr_3, 500, 460);
/* do something with ptr to local array, p_arr_3 */
deallocate(*p_arr_3, 500);
return 0;
}
Related
I have an exam and the teacher want to do a problem. It sound like this.
a)Reading information about an array (the function returns a structure associated with an array)
b)Reading the elements of an array (the function receives as parameters two integers and a pointer to FILE and returns a pointer to pointer to integer)
the point a) is Matrix* infoM.
the point b) is int** readM
And I get an error with the returning type
enter code here
#include <stdio.h>
#include <stdlib.h>
typedef struct Matrix{
int rows;
int cols;
int** data;
}Matrix;
Matrix* infoM( int n_rows, int n_cols)
{Matrix Matrix;
int i;
Matrix.rows = n_rows;
Matrix.cols = n_cols;
Matrix.data = (int**)malloc(sizeof(int*) * n_rows);
if(Matrix.data == 0)
{
fprintf(stderr, "err");
exit(EXIT_FAILURE);
}
for(i=0;i<n_rows;i++)
{
*(Matrix.data+i) = (int*)malloc(sizeof(int)*n_cols);
if(*(Matrix.data+i) == 0)
{
fprintf(stderr,"err");
exit(EXIT_FAILURE);
}
}
struct Matrix *m;
m = &Matrix;
return m;
}
int** readM(int n_rows, int n_cols, FILE *in)
{
Matrix* matrix = infoM(n_rows,n_cols);
int i,j;
for(i=0; i<n_rows; i++)
{
for(j=0; j<n_cols; j++)
{
fscanf(in, "%d",*(matrix->data+i)+j);
}
}
return matrix;
}
I would use a flexible array member to remove double-pointer - and additional overhead (it removes one level of indirection). Additionally, it simplifies malloc/free (only one needed).
To access data use an array pointer.
typedef struct Matrix{
size_t rows;
size_t cols;
int data[];
}Matrix;
Matrix *createM(size_t rows, size_t cols)
{
Matrix *m = malloc(sizeof(*m) + cols * rows * sizeof(m -> data[0]));
return m;
}
Matrix *initM(Matrix *m)
{
int (*data)[m -> cols] = (int (*)[m -> cols])m -> data;
for(size_t row = 0; row < m -> rows; row++)
{
for(size_t col = 0; col < m -> cols; col++)
{
data[row][col] = rand();
}
}
return m;
}
Use correct types for sizes.
C has a notion of lifetime for variables. Automatic variables (declared in a block of function) reach their end of life at the end of the block (or function...) where they are declared in. And using an object passed its end of life explicetely invokes Undefined Behaviour (close to hell for C programmers).
For that reason you cannot return the address of a local variable. It is called a dangling pointer (Google that word for additional details...).
But C allows to return a whole structure. So a minimal modification of your code could be:
...
Matrix infoM( int n_rows, int n_cols)
{Matrix Matrix;
int i;
Matrix.rows = n_rows;
...
return Matrix;
}
Matrix readM(int n_rows, int n_cols, FILE* in)
{
Matrix matrix = infoM(n_rows, n_cols);
int i, j;
for (i = 0; i < n_rows; i++)
{
for (j = 0; j < n_cols; j++)
{
fscanf(in, "%d", matrix.data[i] + j); // more C idiomatic...
}
}
return matrix;
}
For the same reason, readM is not allowed to return a pointer inside a local object, because it would be a dangling pointer, but you can again return the struct itself.
I'm trying to create a function that creates a variable sized 2D funct array. I'm using the following code, which seems to work just fine on its own:
typedef struct
{
//Starter Properties
int TypeB;
int TypeF;
int TypeW;
//Randomized Properties
int RandB;
int RandF;
int RandW;
//Derived Properties
int Speed;
} MapTileData;
MapTileData **Map;
int i, x=5, y=5;
//Allocate Initial Space
Map = (MapTileData**)calloc(x, sizeof(MapTileData));
for(i = 0; i < x; i++)
{
Map[i] = (MapTileData*)calloc(y, sizeof(MapTileData));
}
So the above code creates a 2D struct array. My attempts to move the code to a function have been less successful, giving segmentation faults when trying to print the array:
void CreateMap(MapTileData **Map, int xSize, int ySize)
{
//Variables
int i;
//Allocate Initial Space
Map = (MapTileData**)calloc(xSize, sizeof(MapTileData));
for(i = 0; i < xSize; i++)
{
Map[i] = (MapTileData*)calloc(ySize, sizeof(MapTileData));
}
}
Used in the code:
MapTileData **MapTile;
CreateMap(MapTile,5,5);
Any and all help is greatly appreciated!
Function arguments are passed by value in C and modifying arguments in callee won't affect caller's local variables.
Use pointers to modify caller's local variables.
void CreateMap(MapTileData ***Map, int xSize, int ySize)
{
//Variables
int i;
//Allocate Initial Space
*Map = calloc(xSize, sizeof(MapTileData));
for(i = 0; i < xSize; i++)
{
(*Map)[i] = calloc(ySize, sizeof(MapTileData));
}
}
Usage in the code:
MapTileData **MapTile;
CreateMap(&MapTile,5,5);
Alternate way: Pass the allocated array via the return value.
MapTileData **CreateMap(int xSize, int ySize)
{
//Variables
MapTileData **Map;
int i;
//Allocate Initial Space
Map = calloc(xSize, sizeof(MapTileData));
for(i = 0; i < xSize; i++)
{
Map[i] = calloc(ySize, sizeof(MapTileData));
}
//Return the value
return Map;
}
Usage in the code:
MapTileData **MapTile;
Maptile = CreateMap(5,5);
Also note that they say you shouldn't cast the result of malloc() and its family in C.
I'm trying to create a function that creates a variable sized 2D funct array. I'm using the following code, which seems to work just fine on its own:
typedef struct
{
//Starter Properties
int TypeB;
int TypeF;
int TypeW;
//Randomized Properties
int RandB;
int RandF;
int RandW;
//Derived Properties
int Speed;
} MapTileData;
MapTileData **Map;
int i, x=5, y=5;
//Allocate Initial Space
Map = (MapTileData**)calloc(x, sizeof(MapTileData));
for(i = 0; i < x; i++)
{
Map[i] = (MapTileData*)calloc(y, sizeof(MapTileData));
}
So the above code creates a 2D struct array. My attempts to move the code to a function have been less successful, giving segmentation faults when trying to print the array:
void CreateMap(MapTileData **Map, int xSize, int ySize)
{
//Variables
int i;
//Allocate Initial Space
Map = (MapTileData**)calloc(xSize, sizeof(MapTileData));
for(i = 0; i < xSize; i++)
{
Map[i] = (MapTileData*)calloc(ySize, sizeof(MapTileData));
}
}
Used in the code:
MapTileData **MapTile;
CreateMap(MapTile,5,5);
Any and all help is greatly appreciated!
Function arguments are passed by value in C and modifying arguments in callee won't affect caller's local variables.
Use pointers to modify caller's local variables.
void CreateMap(MapTileData ***Map, int xSize, int ySize)
{
//Variables
int i;
//Allocate Initial Space
*Map = calloc(xSize, sizeof(MapTileData));
for(i = 0; i < xSize; i++)
{
(*Map)[i] = calloc(ySize, sizeof(MapTileData));
}
}
Usage in the code:
MapTileData **MapTile;
CreateMap(&MapTile,5,5);
Alternate way: Pass the allocated array via the return value.
MapTileData **CreateMap(int xSize, int ySize)
{
//Variables
MapTileData **Map;
int i;
//Allocate Initial Space
Map = calloc(xSize, sizeof(MapTileData));
for(i = 0; i < xSize; i++)
{
Map[i] = calloc(ySize, sizeof(MapTileData));
}
//Return the value
return Map;
}
Usage in the code:
MapTileData **MapTile;
Maptile = CreateMap(5,5);
Also note that they say you shouldn't cast the result of malloc() and its family in C.
I am trying to dynamically create an array of rectangles with random values. However when trying to access the space I malloc I get a seg fault.
My Code:
typedef struct Point
{
double x;
double y;
} PointT;
typedef struct Rect
{
PointT location;
char color;
double w; //width
double h; //height
} RectT;
main()
{
RectT *recs;
randRect(&recs);
}
void randRect(RectT **rects)
{
int i;
rects =malloc(numRec*sizeof(RectT*));
for(i = 0; i < numRec-1; i++)
{
rects[i]->w=rand()%20;
rects[i]->h=rand()%20;
rects[i]->location.x=rand()%20;
rects[i]->location.y=rand()%20;
}
}
numRec is defined as 50
Rects in a function is a pointer to a pointer. So you need to allocate array of RectT items before using it. It should be like this:
void randRect(RectT **rects)
{
int i;
*rects =malloc(numRec*sizeof(RectT));
for(i = 0; i < numRec; i++)
{
(*rects)[i].w=rand()%20;
(*rects)[i].h=rand()%20;
(*rects)[i].location.x=rand()%20;
(*rects)[i].location.y=rand()%20;
}
}
Or even better way:
Rect* randRect()
{
int i;
Rect* rects =malloc(numRec*sizeof(RectT));
for(i = 0; i < numRec; i++)
{
rects[i].w=rand()%20;
rects[i].h=rand()%20;
rects[i].location.x=rand()%20;
rects[i].location.y=rand()%20;
}
return rects;
}
You allocate space for an array of RectT pointers, but you never allocate space for the RectTs that they point to.
You need to allocate space for rectangles, not for pointers to rectangles:
void randRect(RectT **rects) }
*rects = malloc(numRec * sizeof(RectT));
for (size_t i = 0; i != numRec; ++i) {
(*rects)[i]->w = 0; // etc
}
}
I have structure to hold pointer to array of input numbers. When I create matrix I also create default data array. As I suppose the m.data = data; means that m.data pointer points at first element of the array. When I print data right after alocation everything seems ok. But when I print them after in the main function the result is different.
Why does output differs(commented sections)?
#include <stdio.h>
#include <stdlib.h>
typedef struct matrix {
int *data;
int rows;
} Matrix;
//Create Matrix
extern Matrix create_matrix(int size)
{
int data[size * size];
int i = 0;
for(i = 0; i < size * size; i++)
{
data[i] = 0;
}
Matrix m;
m.data = data;
for(i = 0; i < size * size; i++)
{
printf("%d\n",*(m.data + i)); //<--- m.data {0,0 ..... ,0,0,0}
}
m.rows = size;
return m;
};
extern void supply_row_data(Matrix m, int row, int* data)
{
int i = 0;
for(i = 0; i < m.rows; i++)
{
m.data[i] = data[i];
}
};
int main(){
int size = 4;
Matrix m = create_matrix(size);
int i = 0;
int *j = m.data;
for(i = 0; i < size * size; i++)
{
//*(j + i) = i;
printf("%d\n", *(j + i));
}
getch();
}
int data[size * size];
This is a local variable (array) to the function create_matrix It goes out of scope when the function terminates.
m.data = data;
This does not copy the data in the variable data to the data in the variable m.data but rather sets the pointer m.data to the beginning of the array data. When the function returns, the Matrix returned contains what is called a dangling pointer: a pointer to data that no longer exists.
Use the advice from #RSahu to fix this.
That's not how you can copy the data from an array in C.
You need to:
Allocate memory for the data.
m.data = malloc(sizeof(int)*size*size);
Copy the data one element at a time or using memcpy.
memcpy(m.data, data, sizeof(int)*size*size);
Make sure you deallocate the memory allocated to hold the matrix data.
free(m.data);
You should avoid using pointer to local data once function return address of array is no loger valid try to allocate array in following way
int* allocate_vector(size_t elem, int value){
int* vec = (int *) calloc(elem, sizeof(int));
int i = 0;
for( ; i < elem; i++){
*(vec + i) = value;
}
return vec;
}