C pass pointer to function, how to? - c

Having the following code, how can I have "get" receive a map, and return the value at the specified position?
I am attempting to write a cellular automaton in C to try to wrap my head around pointers and memory allocation. Everything was fine until I decided to make "get" to obtain data instead of a direct map[x+world.w*y] as I used to.
I require this because in the future, I plan to have two maps of the same size, and use the same function to get data from them (so it'd be "get(&map2, x, y)" instead of "get(&map, x, y)".
I do this because I was advised against using globals, so I will keep the two maps in main and send their addresses to functions to process.
This is C language, so no C++ solutions are valid.
I tried to search for this in google but all documentation is extremely technical and convoluted, and I am not sure of how this procedure is actually named... So, can anyone help me with this? How can I pass a malloc'ed array to a function and retrieve or alter data from it?
typedef struct Map {
int HP;
int type;
unsigned int flags;
} Map;
typedef struct World {
int w;
int h;
} World;
struct World world;
int tile (int x, int y) { return x + world.w * y; }
int get (/*unknown*/map , int x, int y){
int val = x + world.w * y;
return /*unknown ->?*/ type;
}
int main (){
Map* map;
world.w = 8;
world.h = 8;
int tiles = world.w * world.h;
map = (Map*)malloc(sizeof(Map) * tiles);
int i;
for(i = 0; i < tiles; i++){
map[i].type = rand()%2;
}
int x,y;
while(1){
put(0,0);
for(y = 0; y < world.h; y++){
printf("\n");
for(x = 0; x < world.w; x++){
printf("%i ", get(&map, x, y));
}
}
};
printf("\n");
return 0;
}

Instead of:
get(&map, x, y)
in which you pass the address of the address of the map pointer that malloc() returned, just pass the address itself:
get(map, x, y)
AFAICT from your code, malloc( ) returns exactly the thing that get( ) is looking for, i.e., a pointer to someplace in memory that has room for 64 tiles. So get( ) could look something like:
int
get( Map *map, int x, inty ) {
int val = x + map->w * y; // map is a pointer to struct, not the struct itself
return val; // get( ) returns an int, and it's in val
}
That might be closer to what you want.
-- pete
There are a few other errors in your code, too, but this might let the compiler get off the ground.

Your map variable in main() is already a Map * so don't create a double-indirect pointer out of it by appling & to it at the call site.
Also, int get(Map *m, int x, int y) { ... return map[...]; }
Don't cast the return value from malloc(3).

I may be wrong but from reading your question, it doesn't sound like you are really looking for a function pointer, rather a pointer to a Map structure to pass to a function. Perhaps you want to return a pointer to a particular Map element as well. If this is the case it would look something like the following:
typedef struct Map {
int HP;
int type;
unsigned int flags;
} Map;
typedef struct World {
int w;
int h;
} World;
struct World world;
int tile (int x, int y) { return x + world.w * y; }
Map * get (Map *map , int x, int y){
return map[x + world.w * y];
}
int main (){
Map *map;
Map *m;
world.w = 8;
world.h = 8;
int tiles = world.w * world.h;
map = (Map*)malloc(sizeof(Map) * tiles);
int i;
for(i = 0; i < tiles; i++){
map[i].type = rand()%2;
}
int x,y;
while(1){
put(0,0);
for(y = 0; y < world.h; y++){
printf("\n");
for(x = 0; x < world.w; x++){
m = get(map, x, y); // map was already declared as a pointer
printf("%d\n", m->HP);
printf("%d\n", m->type);
printf("%X\n", m->flags);
}
}
};
printf("\n");
return 0;

Passing a pointer to a struct (or union) in C is easy:
typedef struct Foo
{
int a ;
char b[32] ;
} FOO ;
void do_something_with_a_foo( FOO* p )
{
// using the arror operation '->' to deference a structure pointer
int m = p->a ;
char n = p->b[3] ;
// using the * operator to deference a structure pointer
int x = (*p).a ;
char y = (*p).b[3] ;
return ;
}
void pass_a_foo_pointer_to_function()
{
FOO stack_instance = { 3 , "hello, world" , } ;
FOO* heap_instance = malloc( sizeof(FOO) ) ;
heap_instance->a = 12 ;
strcpy( heap_instance->b , "this, that and the other" ) ;
do_something_with_a_foo( &stack_instance ) ;
do_something_with_a_foo( heap_instance ) ;
free( heap_instance) ;
return ;
}
Cheers!

Related

multiple dynamic arrays inside a struct

i am trying do dynamicly allocate a matrix which is inside a struct, also if anyone can also tell me how to send it to the function so i don't have to declare my struct variable globally i would really apreciate it, cuz i can't seem to figure it out
#include <stdio.h>
#include<stdlib.h>
#include <stdbool.h>
struct matrice_dinamica{
int linii, coloane;
int **matrice;
};
struct matrice_dinamica* v = NULL;
void comanda_L_citire_matrice(int i)
{
scanf("%d %d", &v[i].linii, &v[i].coloane);
int v[i].(*matrice)[v[i].coloane] = malloc (sizeof(int[v[i].linii][v[i].coloane]));
for(int x = 0; x < v[i].linii; x++){
for(int y = 0; y < v[i].coloane; y++){
scanf("%d", &v[i].matrice[x][y]);
}
}
}
int main(int argc, char const *argv[])
{
v = (struct matrice_dinamica*)malloc(sizeof(struct matrice_dinamica));
there are more things in the main function so i only gave what i thought usefull cuz the error i get is in the function
the error i get is error: expected expression before '.' token
To avoid double pointers, int **matrice cannot be used because that is a double pointer. The storage for the matrix can be "flattened" into a single dimension and the positions of the elements for each (row,column) coordinate can calculated arithmetically as row * num_columns + column. For example:
struct matrice_dinamica{
int linii, coloane;
int *matrice; // flattened
};
// Get pointer to start of a row
int *matrice_row(struct matrice_dinamica *m, int x)
{
return m->matrice + x * m->coloane;
}
// Get pointer to an element
int *matrice_elp(struct matrice_dinamica *m, int x, int y)
{
return matrice_row(m, x) + y;
}
// Get value of an element
int matrice_el(struct matrice_dinamica *m, int x, int y)
{
return *matrice_elp(m, x, y);
}
// Store value in an element
void matrice_el_store(struct matrice_dinamica *m, int x, int y, int val)
{
*matrice_elp(m, x, y) = val;
}
void comanda_L_citire_matrice(struct matrice_dinamica *m)
{
int *md;
scanf("%d %d", &m->linii, &m->coloane);
m->matrice = malloc(m->linii * m->coloane * sizeof(int));
md = m->matrice;
for(int x = 0; x < m->linii; x++){
for(int y = 0; y < m->coloane; y++){
scanf("%d", md++);
}
}
}

C - Initializing structs inside a 2D array before returning double pointer from function

I'm new to C Programming and want to focus on learning dynamic allocation. As a learning opportunity for me, I'm trying to create a function that returns a double-pointer for a 2D array of structs. I've been referencing tutorials that generally refer to what is mentioned here in approach #3.
I can see that the tutorial assigns integer values no problem, but I'm not sure how that translates with structs.
Here's my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
const int HEIGHT = 64;
const int WIDTH = 96;
struct Tile
{
char type;
bool armed;
struct Tile* up;
struct Tile* right;
struct Tile* down;
struct Tile* left;
};
struct Tile** createTileMap(unsigned int w, unsigned int h)
{
struct Tile** map = (struct Tile **)malloc(w * sizeof(struct Tile *));
for (int x = 0; x < w; x++)
{
map[x] = (struct Tile *)malloc(h * sizeof(struct Tile));
for (int y = 0; y < h; y++)
{
map[x][y] = (struct Tile){.type = '_', .armed = false, .up = NULL,
.right = NULL, .down = NULL, .left = NULL};
}
}
}
int main(int argc, char* argv[])
{
struct Tile** map = createTileMap(WIDTH, HEIGHT);
for (int x = 0; x < WIDTH; x++)
{
for (int y = 0; y < HEIGHT; y++)
{
printf(" (%d, %d): ", x, y);
printf("%c", map[x][y].type);
}
printf("\n");
}
return 0;
}
This code segfaults, and I'm not too sure why. Any help is appreciated.
As indicated by EOF, I simply forgot to actually return the address. Fortunately my other code was fine, though!

Three Dimensional array of structs in C

Hello I am struggling to find a solution Ive defined the following 3D array of structures.
typedef struct{
float x;
float y;
float z;
} Point;
Point ***Qw;
Qw = malloc(num_bezier * sizeof(Point **));
for(i=0; i<num_bezier; i++){
Qw[i] = malloc((m+1) * sizeof(Point *));
for(j=0; j<=m;j++)
Qw[i][j] = malloc((p+1) * sizeof(Point));
}
I can loop through the array to print its contents but at some point of the program after modifying some of the elements, Im no longer able to access some of the structs in the array and i get a segfault. Any help appreciated, thanks.
PD: Ive just noticed i had defined incorrectly my struct...
typedef struct{
double x;
double y;
float z;
} Point;
As soon as i exchanged the double for float type it fixed the segfault... still trying to figure out why it was segfaulting
Consider allocating a single buffer (with pow( num_bezier, 3) elements) instead of allocating rows, columns and cells separately. That way you can avoid excess allocation but also memory fragmentation.
struct Point { float x, y, z; }
size_t bufferLength;
size_t bufferSquareLength;
struct Point* buffer; // pointer to a dynamically-allocated cubic buffer of Point values, stored in row x, column y, and depth z order.
void allocateBuffer(size_t squareLength) {
bufferSquareLength = squareLength;
bufferLength = squareLength * squareLength * squareLength;
buffer = calloc( bufferLength, sizeof(struct Point) );
}
struct Point* getElement(size_t x, size_t y, size_t z) {
Point* p = buffer + ( x * bufferSquareLength * bufferSquareLength ) + ( y * bufferSquareLength ) + z;
return p;
}
Much simpler and easier to follow.
To iterate over each value:
void forEachPoint( void(*callback(size_t x, size_t y, size_t z, struct Point* value) ) {
for(size_t x = 0; x < bufferSquareLength; x++) {
for(size_t y = 0; y < bufferSquareLength; y++) {
for(size_t z = 0; z < bufferSquareLength; z++) {
callback( x, y, z, getElement( x, y, z ) );
}
}
}
}
Simply call forEachPoint with a custom callbakc function to iterate over each struct Point value.

Getting the address of function return arguement in C

Having read the chapter about sttructures from "The C programming Language book" I tried the following code. The goal is to have an array of pointer initialized with some specific value for all its points.
#include <stdio.h>
#define MAXPOINTS 1000
struct point {
int x;
int y;
};
struct point makepoint(int x, int y);
int main(int argc, const char *argv[])
{
int i;
int number1 = 5, number2 = 10;
struct point *points[1000];
for (i=0; i< MAXPOINTS; i++) {
points[i] = &(makepoint(number1, number2));
}
}
struct point makepoint(int x, int y) {
struct point my_point;
my_point.x = x;
my_point.y = y;
return my_point;
}
The error generated after running the above code is the following:
test_something.c:18:22: error: cannot take the address of an rvalue of type 'struct point'
Why does this happen since the makepoint function does return a valid point object?
Thanks in advance,
You are returning a temporary copy of a point and take his address is not a good idea.
Try this:
struct point* makepoint(int x, int y);
int main(int argc, const char *argv[]) {
int i;
int number1 = 5, number2 = 10;
struct point* points[MAXPOINTS];
for (i=0; i< MAXPOINTS; i++)
points[i] = makepoint(number1, number2);
for (i=0; i< MAXPOINTS; i++)
free(points[i]);
return 0;
}
struct point* makepoint(int x, int y) {
struct point* my_point = malloc(sizeof(struct point));
my_point->x = x;
my_point->y = y;
return my_point;
}
Anyway, in your code:
struct point *points[10];
for (i=0; i< MAXPOINTS; i++) {
points[i] = &(makepoint(number1, number2));
}
...you have an array of 10 pointers and you're trying to assign 1000 pointers (MAXPOINTS).
You cannot take the address of a value, only of a variable. This is because values don't necessarily need to live in (addressable) memory. For example: the return value of a function is (usually) passed via a register, and you cannot take the address of a register(-variable).
You could instead change your makepoint function to take a pointer to a struct point and fill it in:
struct point makepoint(struct point * in, int x, int y){
in->x = x;
in->y = y;
return *in;
}
Note that the return value isn't strictly necessary, but kept for 'backward compatability'.

Passing struct array of pointers as a function argument?

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;
}

Resources