This question already has answers here:
malloc-ating multidimensional array in function
(7 answers)
Closed 7 years ago.
At first, it may sound normal if I free the allocation within the function, but it's not the case. As I'm writting these lines, I've found a work around, but I would like to keep a certain homogeneity in my code and would prefer to keep it the way it ways but you know working properly, so is there another solutions or my workaround is the only option?
The main function:
void main(void)
{
SHead head; // Custom struct
unsigned char **array = NULL; // pointer to 2D array
allocArray2D(&head, array) // the function signature: (SHead*, unsigned char**)
// here, the array pointer is still NULL (0x0)
//...
return EXIT_SUCCESS;
}
The allocation function malloc a very small amount of memory around 21 unsigned char* and for each simple pointer 21 unsigned char.
Within the function, the pointer is fine and points to a proper address.
So my work around was modify the function from:
void allocArray(SHead* h, unsigned char** arr)
{
int x, y, i;
getsize(head, *x, *y);
arr = (unsigned char**)malloc(sizeof(unsigned char*)*y);
if(arr)
printf(">> Erro allocating memory\n"), return;
for(i =0; i<y; i++)
{
arr[i] = (unsigned char)malloc(sizeof(unsigned char)*x);
}
}
to the following:
unsigned char** allocArray(SHead*)
{
int x, y, i;
unsigned char **arr;
getsize(head, *x, *y);
arr = (unsigned char**)malloc(sizeof(unsigned char*)*y);
if(arr)
printf(">> Erro allocating memory\n"), return;
for(i =0; i<y; i++)
{
arr[i] = (unsigned char)malloc(sizeof(unsigned char)*x);
}
return arr; // returning the address
}
As I said earlier, I'd like to keep homogeneity within my code and would prefer to keep a function signature similar to other function I have. My workaround work properly. And I'm wondering if it is the only solution, or perhaps I am missing something.
EDIT: Following the comments I added more code.
Thank you,
Alex.
You have to pass a pointer to the 2dimensional array to your function, to write in the function to the value behind the pointer:
SHead head; // Custom struct
unsigned char **array = NULL; // pointer to 2D array
allocArray2D(*head, &array)
// ^ address of array
-
void allocArray(SHead* head, unsigned char*** pArray)
// ^ pointer to char** because its an output parameter
{
int x, y, i;
getsize( head, &x, &y );
*pArray = malloc( y * sizeof( unsigned char * );
// ^ assigne somtething to the variable array refered by the pointer pArray
if( *pArray == NULL )
{
printf(">> Erro allocating memory\n")
return;
}
for ( i = 0; i < y; i ++ )
(*pArray)[i] = malloc( x * sizeof( unsigned char ) );
}
Note, what you did was to pass a NULL-pointe to the function allocArray.
An other solution would be to return the allocated memory by the return value of function allocArray:
SHead head; // Custom struct
unsigned char **array = NULL;
array = allocArray( &head );
-
unsigned char** allocArray( SHead* head )
{
int x, y, i;
getsize( head, &x, &y );
unsigned char** arr = malloc( y * sizeof( unsigned char * );
if( arr == NULL )
{
printf(">> Erro allocating memory\n")
return;
}
for ( int i = 0; i < y; i ++ )
arr[i] = malloc( x * sizeof( unsigned char ) );
return arr;
}
If I have understood you correctly what you need is something like the following
For simplicity I excluded the parameter that refers to the structure.
void allocArray2D( unsigned char ***a, size_t n )
{
*a = malloc( n * sizeof( unsigned char * ) );
for ( size_t i = 0; i < n; i++ ) ( *a )[i] = malloc( n * sizeof( unsigned char ) );
}
//...
unsigned char **array = NULL; // pointer to 2D array
allocArray2D( &array, 21 );
If you want that the original object would be changed after passing it to a function then you have to pass it by reference.
Your call looks very strange.
First, you are passing *head. head seems to be an uninitialised variable, so passing *head seems badly wrong.
Second, the function called has no way of seeing array. Your call is equivalent to allocArray2D (*head, NULL) and not having the array variable at all. This also seems very wrong.
Related
i am trying to write a code in C but i am having some problems with realloc. I had to write a code that will create a stack, and will add to it (dodaj_do_stosu), reamove from it (usun_ze_stosu) and will look at the top thing that is on this stack. I have problem with compiling(it does work for first two words but then it returns (0xC0000374)).
I think i am usining the realloc wrong and the sizeof my structure. If someone could look at my code (especially at the function (dodaj_do_stosu) and tell me what am i doing wrong thx. My code look like this:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct {
int n;
char *nazwa;
}element_t;
typedef struct {
int rozmiar;
element_t **tablica;
}stos_t;
void top_of_stack(stos_t *s){
printf("ostatni element stosu:rozmiar = %d nazwa=%s, n=%d\n", s->rozmiar, s->tablica[s->rozmiar]->nazwa, s->tablica[s->rozmiar]->n);
}
void init(stos_t *s)
{
s->rozmiar=0;
s->tablica=malloc(0);
}
void dodaj_do_stosu(stos_t *s, int n, char *name)
{
s->tablica = realloc(s->tablica, (s->rozmiar + 1) * sizeof(s->tablica));
s->tablica[s->rozmiar]->nazwa = name;
s->tablica[s->rozmiar]->n = n;
printf("rozmiar=%d, n=%d , nazwa=%s\n",s->rozmiar, s->tablica[s->rozmiar]->n, s->tablica[s->rozmiar]->nazwa);
s->rozmiar++;
}
void usun_ze_stosu(stos_t *s)
{
s->tablica = realloc(s->tablica, (s->rozmiar - 1) * sizeof(s->tablica[0]));
s->rozmiar--;
}
void rm(stos_t s)
{
free(s.tablica);
}
int main(int argc, char **argv)
{
stos_t s;
init(&s);
int i;
srand(time(0));
if (argc>1)
for(i=1;i<argc;i++){
printf("%s\n", argv[i]);
dodaj_do_stosu(&s, rand() % 10, argv[i]);
}
for(i=0;i<argc-1;i++){
//printf("i=%d, n=%d, nazwa=%s\n",i, s.tablica[i].n, s.tablica[i].nazwa);
}
//top_of_stack(&s);
//usun_ze_stosu(&s);
//top_of_stack(&s);
rm(s);
return 0;
}
A big part of your problem is that tablica is an array of pointers, but you never initialize the pointers themselves.
The dodaj_do_stosu function reallocates the array, but doesn't create the element_t objects. Therefore any dereference of e.g. s->tablica[s->rozmiar] will lead to undefined behavior.
There are two possible solutions:
Allocate a new element_t structure:
s->tablica[s->rozmiar] = malloc(sizeof(element_t));
before you initialize the element_t structure members.
Make tablica an array of structure objects instead of pointers:
element_t *tablica; // tablica is an array of objects, not an array of pointers
I recommend solution 2.
At least the function dodaj_do_stosu is wrong. The data member tablica is declared like
element_t **tablica;
So the expression s->tablica[s->rozmiar] has the type element_t * and an indeterminate value. Thus dereferencing the pointer expression for example like
s->tablica[s->rozmiar]->nazwa
invokes undefined behavior.
You have to allocate memory for objects of the structure type element_t not for pointers of the type element_t *.
So you need to declare the data member like
element_t *tablica;
and within the function to write
s->tablica = realloc(s->tablica, (s->rozmiar + 1) * sizeof( *s->tablica));
Also it is safer to use an intermediate pointer for calls of realloc.
The function can look the following way
int dodaj_do_stosu( stos_t *s, int n, char *name )
{
element_t *tmp = realloc( s->tablica, ( s->rozmiar + 1 ) * sizeof( *s->tablica ) );
int success = tmp != NULL;
if ( success )
{
s->tablica = tmp;
s->tablica[s->rozmiar]->nazwa = name;
s->tablica[s->rozmiar]->n = n;
printf("rozmiar=%d, n=%d , nazwa=%s\n", s->rozmiar, s->tablica[s->rozmiar]->n, s->tablica[s->rozmiar]->nazwa );
++s->rozmiar;
}
return success;
}
Consequently the function should be redefined at least the following way. As is it can for example invoke undefined behavior when s->rozmiar is equal to 0.
int usun_ze_stosu( stos_t *s )
{
int success = s->rozmiar != 0;
if ( success )
{
element_t *tmp = realloc( s->tablica, ( s->rozmiar - 1 ) * sizeof( *s->tablica ) );
success = tmp != NULL;
if ( success )
{
s->tablica = tmp;
--s->rozmiar;
}
}
return success;
}
Also within the function init it will be much better ro write
void init(stos_t *s)
{
s->rozmiar=0;
s->tablica = NULL;
}
Another problem is the function rm
void rm(stos_t s)
{
free(s.tablica);
}
You should pass the original object through a pointer to it and within the function to write
void rm(stos_t *s)
{
free( s->tablica );
s->tablica = NULL;
s->rozmiar = 0;
}
I need to do a simple thing, which I used to do many times in Java, but I'm stuck in C (pure C, not C++). The situation looks like this:
int *a;
void initArray( int *arr )
{
arr = malloc( sizeof( int ) * SIZE );
}
int main()
{
initArray( a );
// a is NULL here! what to do?!
return 0;
}
I have some "initializing" function, which SHOULD assign a given pointer to some allocated data (doesn't matter). How should I give a pointer to a function in order to this pointer will be modified, and then can be used further in the code (after that function call returns)?
You need to adjust the *a pointer, this means you need to pass a pointer to the *a. You do that like this:
int *a;
void initArray( int **arr )
{
*arr = malloc( sizeof( int ) * SIZE );
}
int main()
{
initArray( &a );
return 0;
}
You are assigning arr by-value inside initArray, so any change to the value of arr will be invisible to the outside world. You need to pass arr by pointer:
void initArray(int** arr) {
// perform null-check, etc.
*arr = malloc(SIZE*sizeof(int));
}
...
initArray(&a);
I need to do a simple thing, which I used to do many times in Java, but I'm stuck in C (pure C, not C++). The situation looks like this:
int *a;
void initArray( int *arr )
{
arr = malloc( sizeof( int ) * SIZE );
}
int main()
{
initArray( a );
// a is NULL here! what to do?!
return 0;
}
I have some "initializing" function, which SHOULD assign a given pointer to some allocated data (doesn't matter). How should I give a pointer to a function in order to this pointer will be modified, and then can be used further in the code (after that function call returns)?
You need to adjust the *a pointer, this means you need to pass a pointer to the *a. You do that like this:
int *a;
void initArray( int **arr )
{
*arr = malloc( sizeof( int ) * SIZE );
}
int main()
{
initArray( &a );
return 0;
}
You are assigning arr by-value inside initArray, so any change to the value of arr will be invisible to the outside world. You need to pass arr by pointer:
void initArray(int** arr) {
// perform null-check, etc.
*arr = malloc(SIZE*sizeof(int));
}
...
initArray(&a);
I need to do a simple thing, which I used to do many times in Java, but I'm stuck in C (pure C, not C++). The situation looks like this:
int *a;
void initArray( int *arr )
{
arr = malloc( sizeof( int ) * SIZE );
}
int main()
{
initArray( a );
// a is NULL here! what to do?!
return 0;
}
I have some "initializing" function, which SHOULD assign a given pointer to some allocated data (doesn't matter). How should I give a pointer to a function in order to this pointer will be modified, and then can be used further in the code (after that function call returns)?
You need to adjust the *a pointer, this means you need to pass a pointer to the *a. You do that like this:
int *a;
void initArray( int **arr )
{
*arr = malloc( sizeof( int ) * SIZE );
}
int main()
{
initArray( &a );
return 0;
}
You are assigning arr by-value inside initArray, so any change to the value of arr will be invisible to the outside world. You need to pass arr by pointer:
void initArray(int** arr) {
// perform null-check, etc.
*arr = malloc(SIZE*sizeof(int));
}
...
initArray(&a);
How can I pass an array of structs by reference in C?
As an example:
struct Coordinate {
int X;
int Y;
};
SomeMethod(Coordinate *Coordinates[]){
//Do Something with the array
}
int main(){
Coordinate Coordinates[10];
SomeMethod(&Coordinates);
}
In C arrays are passed as a pointer to the first element. They are the only element that is not really passed by value (the pointer is passed by value, but the array is not copied). That allows the called function to modify the contents.
void reset( int *array, int size) {
memset(array,0,size * sizeof(*array));
}
int main()
{
int array[10];
reset( array, 10 ); // sets all elements to 0
}
Now, if what you want is changing the array itself (number of elements...) you cannot do it with stack or global arrays, only with dynamically allocated memory in the heap. In that case, if you want to change the pointer you must pass a pointer to it:
void resize( int **p, int size ) {
free( *p );
*p = malloc( size * sizeof(int) );
}
int main() {
int *p = malloc( 10 * sizeof(int) );
resize( &p, 20 );
}
In the question edit you ask specifically about passing an array of structs. You have two solutions there: declare a typedef, or make explicit that you are passing an struct:
struct Coordinate {
int x;
int y;
};
void f( struct Coordinate coordinates[], int size );
typedef struct Coordinate Coordinate; // generate a type alias 'Coordinate' that is equivalent to struct Coordinate
void g( Coordinate coordinates[], int size ); // uses typedef'ed Coordinate
You can typedef the type as you declare it (and it is a common idiom in C):
typedef struct Coordinate {
int x;
int y;
} Coordinate;
To expand a little bit on some of the answers here...
In C, when an array identifier appears in a context other than as an operand to either & or sizeof, the type of the identifier is implicitly converted from "N-element array of T" to "pointer to T", and its value is implicitly set to the address of the first element in the array (which is the same as the address of the array itself). That's why when you just pass the array identifier as an argument to a function, the function receives a pointer to the base type, rather than an array. Since you can't tell how big an array is just by looking at the pointer to the first element, you have to pass the size in as a separate parameter.
struct Coordinate { int x; int y; };
void SomeMethod(struct Coordinate *coordinates, size_t numCoordinates)
{
...
coordinates[i].x = ...;
coordinates[i].y = ...;
...
}
int main (void)
{
struct Coordinate coordinates[10];
...
SomeMethod (coordinates, sizeof coordinates / sizeof *coordinates);
...
}
There are a couple of alternate ways of passing arrays to functions.
There is such a thing as a pointer to an array of T, as opposed to a pointer to T. You would declare such a pointer as
T (*p)[N];
In this case, p is a pointer to an N-element array of T (as opposed to T *p[N], where p is an N-element array of pointer to T). So you could pass a pointer to the array as opposed to a pointer to the first element:
struct Coordinate { int x; int y };
void SomeMethod(struct Coordinate (*coordinates)[10])
{
...
(*coordinates)[i].x = ...;
(*coordinates)[i].y = ...;
...
}
int main(void)
{
struct Coordinate coordinates[10];
...
SomeMethod(&coordinates);
...
}
The disadvantage of this method is that the array size is fixed, since a pointer to a 10-element array of T is a different type from a pointer to a 20-element array of T.
A third method is to wrap the array in a struct:
struct Coordinate { int x; int y; };
struct CoordinateWrapper { struct Coordinate coordinates[10]; };
void SomeMethod(struct CoordinateWrapper wrapper)
{
...
wrapper.coordinates[i].x = ...;
wrapper.coordinates[i].y = ...;
...
}
int main(void)
{
struct CoordinateWrapper wrapper;
...
SomeMethod(wrapper);
...
}
The advantage of this method is that you aren't mucking around with pointers. The disadvantage is that the array size is fixed (again, a 10-element array of T is a different type from a 20-element array of T).
The C language does not support pass by reference of any type. The closest equivalent is to pass a pointer to the type.
Here is a contrived example in both languages
C++ style API
void UpdateValue(int& i) {
i = 42;
}
Closest C equivalent
void UpdateValue(int *i) {
*i = 42;
}
also be aware that if you are creating a array within a method, you cannot return it. If you return a pointer to it, it would have been removed from the stack when the function returns.
you must allocate memory onto the heap and return a pointer to that.
eg.
//this is bad
char* getname()
{
char name[100];
return name;
}
//this is better
char* getname()
{
char *name = malloc(100);
return name;
//remember to free(name)
}
Arrays are effectively passed by reference by default. Actually the value of the pointer to the first element is passed. Therefore the function or method receiving this can modify the values in the array.
void SomeMethod(Coordinate Coordinates[]){Coordinates[0].x++;};
int main(){
Coordinate tenCoordinates[10];
tenCoordinates[0].x=0;
SomeMethod(tenCoordinates[]);
SomeMethod(&tenCoordinates[0]);
if(0==tenCoordinates[0].x - 2;){
exit(0);
}
exit(-1);
}
The two calls are equivalent, and the exit value should be 0;
In plain C you can use a pointer/size combination in your API.
void doSomething(MyStruct* mystruct, size_t numElements)
{
for (size_t i = 0; i < numElements; ++i)
{
MyStruct current = mystruct[i];
handleElement(current);
}
}
Using pointers is the closest to call-by-reference available in C.
Hey guys here is a simple test program that shows how to allocate and pass an array using new or malloc. Just cut, paste and run it. Have fun!
struct Coordinate
{
int x,y;
};
void resize( int **p, int size )
{
free( *p );
*p = (int*) malloc( size * sizeof(int) );
}
void resizeCoord( struct Coordinate **p, int size )
{
free( *p );
*p = (Coordinate*) malloc( size * sizeof(Coordinate) );
}
void resizeCoordWithNew( struct Coordinate **p, int size )
{
delete [] *p;
*p = (struct Coordinate*) new struct Coordinate[size];
}
void SomeMethod(Coordinate Coordinates[])
{
Coordinates[0].x++;
Coordinates[0].y = 6;
}
void SomeOtherMethod(Coordinate Coordinates[], int size)
{
for (int i=0; i<size; i++)
{
Coordinates[i].x = i;
Coordinates[i].y = i*2;
}
}
int main()
{
//static array
Coordinate tenCoordinates[10];
tenCoordinates[0].x=0;
SomeMethod(tenCoordinates);
SomeMethod(&(tenCoordinates[0]));
if(tenCoordinates[0].x - 2 == 0)
{
printf("test1 coord change successful\n");
}
else
{
printf("test1 coord change unsuccessful\n");
}
//dynamic int
int *p = (int*) malloc( 10 * sizeof(int) );
resize( &p, 20 );
//dynamic struct with malloc
int myresize = 20;
int initSize = 10;
struct Coordinate *pcoord = (struct Coordinate*) malloc (initSize * sizeof(struct Coordinate));
resizeCoord(&pcoord, myresize);
SomeOtherMethod(pcoord, myresize);
bool pass = true;
for (int i=0; i<myresize; i++)
{
if (! ((pcoord[i].x == i) && (pcoord[i].y == i*2)))
{
printf("Error dynamic Coord struct [%d] failed with (%d,%d)\n",i,pcoord[i].x,pcoord[i].y);
pass = false;
}
}
if (pass)
{
printf("test2 coords for dynamic struct allocated with malloc worked correctly\n");
}
//dynamic struct with new
myresize = 20;
initSize = 10;
struct Coordinate *pcoord2 = (struct Coordinate*) new struct Coordinate[initSize];
resizeCoordWithNew(&pcoord2, myresize);
SomeOtherMethod(pcoord2, myresize);
pass = true;
for (int i=0; i<myresize; i++)
{
if (! ((pcoord2[i].x == i) && (pcoord2[i].y == i*2)))
{
printf("Error dynamic Coord struct [%d] failed with (%d,%d)\n",i,pcoord2[i].x,pcoord2[i].y);
pass = false;
}
}
if (pass)
{
printf("test3 coords for dynamic struct with new worked correctly\n");
}
return 0;
}