This is my code, which allocates space for a matrix of size specified by the parameters, and returns a pointer to said matrix:
int **allocateSpace(int row, int col){
int i;
int **a;
a = malloc(sizeof(int *) * row);
for(i = 0; i < row; i ++)
a[i] = malloc(sizeof(int) * col);
return a;
}
The above code works as intended.
However, when I change the code to the following form I get a segmentation fault:
void allocateSpace(int **a, int row, int col){
int i;
a = malloc(sizeof(int *) * row);
for(i = 0; i < row; i ++)
a[i] = malloc(sizeof(int) * col);
}
It seems like when returning from the allocateSpace() function, the memory allocated was released (since I got a segmentation fault). But why? All I am doing is allocating memory for a given pointer, and it's all done in the subfunction.
To summarize my question: Why am I getting a segmentation fault in the second piece of code?
Thank you very much!
Because you need to pass in a pointer to a pointer to a pointer in order to assign the allocated memory:
void allocateSpace(int ***a, int row, int col){
int i;
*a = malloc(sizeof(int *) * row);
for(i = 0; i < row; i ++)
( *a )[i] = malloc(sizeof(int) * col);
}
And to call it you would need to pass the address of an int**:
int** ppData;
allocateSpace( &ppData, 10, 10 );
The problem is that you are trying to change a pointer that is passed by value:
void allocateSpace(int **a, int row, int col){
// ...
}
int** a here is passed by value (i.e. the pointer value is copied to the stack in order to use it as function parameter).
When you then do
a = malloc(sizeof(int *) * row);
you change only the copy of the pointer and once the function returns, your change is discarded.
The solution is to pass the pointer by reference, i.e.
void allocateSpace(int ***a, int row, int col){
//...
}
and change the real value by following the reference:
*a = malloc(sizeof(int *) * row);
In the second case you are modifying the function's parameter a - that is a local copy passed by value. So, if you call the function like: allocateSpace(myptr,N,M), myptr will not be modifed - a copy local to the function will. Therefore, myptr contains whatever it contained before the call - possibly garbage. You would need to change the function param to: int ***a (oh the horror) and then put an additional * (dereference op) before each reference to a in the function body.
Compare this to the situation where you want to modify a simple int in a function - the param should be int * and assignments in function body should go to *a. Same applies here - one additional level of dereference is needed to achieve your goal.
In the second function int **a is passed by value (the pointer) so changes in the function dont affect the caller's function. You have to pass this value by reference.
Related
This question already has an answer here:
Dynamic memory access only works inside function
(1 answer)
Closed 4 years ago.
I wrote this simple code to test a bigger implementation I have and I get trash values plus a seg fault. One solution is to declare int* a and int* b as global and take out the arguments of fill. My question is, what is the consideration of memory handling in both cases, and why does it throw an error?
#include <stdio.h>
#include<stdlib.h>
#define LENGTH 4
void fill(int* a, int* b){
a = (int*) malloc(LENGTH * sizeof(int));
b = (int*) malloc(LENGTH * sizeof(int));
for(int i=0; i< LENGTH;i++){
a[i]=i;
b[i]=i+10;
}
}
void printArray(int* a, int* b){
for(int i = 0 ; i < LENGTH; i++)
printf("%d\n",a[i] );
for(int i = 0 ; i < LENGTH; i++)
printf("%d\n",b[i] );
}
int main(){
int* a;
int* b;
fill(a,b);
printArray(a,b);
}
You should pass pointers to pointers as arguments to the fill function so you can effectively modify the pointers a and b.
void fill(int** a, int** b){
*a = malloc(LENGTH * sizeof(int));
(*a)[i]=i;
fill(&a,&b);
Whenever you send args to a function in c they are always sent by value.
here, you send by value the addresses that a and b point to - they are uninitialized- so junk values.
When you use malloc- it returns a pointer to an address on the heap.
in your function the local values of a and b change. but in your main function they do not. if you want your function to change the address the pointers are pointing to in outside of the function you must send **a and **b. now when you change the address for a : * a= malloc() you change the value the pointer is holding. So now your a and b pointers will hold the new addresses allocated.
void fill(int** a, int** b)/*here you send by value the pointers addrsses */
{
int* aptr = NULL;
int* bptr = NULL;
*a = (int*) malloc(LENGTH * sizeof(int));/*update the value pointe a is pointing to */
*b = (int*) malloc(LENGTH * sizeof(int));
aptr = *a;
bptr = *b;
for(int i=0; i< LENGTH;i++){
aptr[i]=i;
bptr[i]=i+10;
}
}
I have created a double int pointer in main and called a function where I allocate place for this pointer.
void foo(int **array)
{
int i, j;
array = (int **)malloc(sizeof(int *)*(100)); //rows
for(i=0; i<100; i++)
array[i] = (int *)malloc(sizeof(int)*(50)); //cols
array[0][0] = 10;
}
and in main I have just these lines;
int** array;
foo(array);
printf("%d \n", array[0][0]);
As a result I get a segmentation fault. Since I am passing a pointer and it is allocated in foo method, does it mean that in main method it is not allocated? How can I solve it without making foo function to return a double pointer?
The way your function is defined:
void foo(int **array);
the two-dimensional array is a local variable that goes out of scope at the end of the function. You will lose the allocated memory and your main function won't know about the allocated memory, because the array in foo and main are different.
One solution is to create an int ** in main and then pass a pointer to that in foo:
void foo(int ***array);
You can then update the local variable in main via the pointer passed to foo, *array;
Another solution is to return the freshly allocated memory from the function:
int **foo(void);
This is a frequent question here and there should be plenty of code examples for array allocation.
finally, check this. update your foo function as below and it should work as per your expectations,
void foo(int (***array))
{
int i;
*array = (int **) malloc(100*sizeof(int *)); //rows
for(i=0; i<100; i++){
(*array)[i] = malloc(50*sizeof(int));} //cols
*array[0][0] =10;
}
In the main function, pass the address of array variable.
foo(&array);
hope this helps!
Here is my code:
typedef struct {
int** matrix;
int rows;
int cols;
}intMat;
intMat create_intMat(int rows,int cols,int matrix[rows][cols]){
intMat A;
A.rows = rows;
A.cols = cols;
int** mat;
mat = malloc(A.rows*sizeof(int*)); // Pointer for matrix rows
for(int i=0;i<A.rows;i++) mat[i] = malloc(A.cols*sizeof(int)); // Pointer of each matrix row to a matrix column
for (int i=0;i<A.rows;i++){
for (int j=0;j<A.cols;j++){
mat[i][j]=matrix[i][j];
}
}
A.matrix = mat;
return A;
}
int main() {
int mat[2][2] = {{1,2},{3,4}};
intMat A;
A = create_intMat(2,2,mat);
printf("%d\n",A.matrix[1][1]);
return 0;
}
I'm a beginner to pointers and got the pointer part of the code from another forum. I don't get it, though. int** mat is a pointer to a pointer to an int, so if I call it as is then it should give me back gibberish address, not the int being pointed to. However, the printf statement returns 4, which is the value of the int being pointed to! How come this is happening?
A.matrix is a pointer to a 2 pointers, which each point to 2 ints.
A.matrix[1] gets the second of those pointers - a pointer to 2 ints.
A.matrix[1][1] gets the second of those ints.
When you use:
int i;
int* p = &i;
or
int* p = malloc(sizeof(int));
p points to a single integer.
When you use:
int array[10];
int *p = array;
or
int *p = malloc(sizeof(int)*10);
p points to an array of 10 integers.
Similarly, a variable declared with:
int** mat;
can point to one int* or an array of int*s.
In your case, mat points to an array of 2 int*, each of which points to an array of 2 ints.
That makes use of mat[1][1] perfectly valid code.
I need to write a function that creates a double pointer using malloc.
This is how I declared my double pointer as I normally would:
double **G; //Create double pointer to hold 2d matrix
*G = malloc(numNodes * sizeof(double*));
for(i = 0; i < numNodes; i++)
{
G[i] = malloc(numNodes*sizeof(double));
for (j = 0; j < numNodes; j++)
{
G[i][j] = 0;
}
}
Now I tried replacing it with:
double **G;
mallocDoubleArr(G, numNodes);
With the function being:
void mallocDoubleArr(double **arr, int size)
{
int i, j;
*arr = malloc(size * sizeof(double*));
for(i = 0; i < size; i++)
{
arr[i]= malloc(size*sizeof(double));
for (j = 0; j < size; j++)
{
arr[i][j] = 0;
}
}
}
Why doesn't this work?
You need one more "indirection", in other words pass G by reference like a pointer to a pointer to a pointer to float:
void mallocDoubleArr(double ***arr, int size);
And then call it as
mallocDoubleArr(&G, numNodes);
Modify mallocDoubleArr accordingly, like for example
(*arr)[i] = malloc(size*sizeof(double));
For starters, you need to change the line
*G = malloc(numNodes * sizeof(double*));
to
G = malloc(numNodes * sizeof(double*));
(you can't dereference a pointer safely until you've assigned something to it.)
Secondly, your function modifies the pointer passed in, so you need a pointer to it. Your signature should instead by
void mallocDoubleArr(double ***arr, int size)
and you will need to add the relevant indirections in your code to access the pointer that the pointer is pointing to.
A lot of confusion for beginners working with pointers comes from, in my opinion, thinking that they are something different than regular old variables. Pointers, like ints, floats, etc. are just variables that live on the stack: they have addresses, and they are passed to functions the same way. If you want to change a variable (int, float, pointer, etc) in a function, you need to pass a pointer to it. There is no difference in this regard.
C is call-by-value. In
double **G;
mallocDoubleArr(G, numNodes);
you are passing an uninitialized variable to mallocDoubleArr. It may be zero, it may be something else, but it almost certainly isn't something that mallocDoubleArr can assign to.
We can change the code, and the function's definition, to pass in G's address, but then you're dealing with yet another level of pointer. That might make it harder to understand the code. If that really isn't a requirement, I'd propose instead to have mallocDoubleArr return a double**.
double **G;
G = mallocDoubleArr(numNodes);
double **mallocDoubleArr(int size)
{
int i, j;
double **arr;
arr = (double **) malloc(size * sizeof(double *));
/* continue with old code */
return arr;
}
[edit: bstamour's post was made while I was writing mine. Sorry for any overlap.]
I use for matrix operations code like following for allocating and freeing.
int **inputMatrix, i, j;
Grid myGrid = *grid;
inputMatrix = (int *) calloc (myGrid.num_nodes, sizeof(int*));
for(i=0; i < myGrid.num_nodes; i++){
inputMatrix[i] = calloc(myGrid.num_nodes, sizeof(int));
for(j=0;j<myGrid.num_nodes;j++){
inputMatrix[i][j] = 0;
}
};
for(i=0; i < myGrid.num_nodes; i++){
free(inputMatrix[i]);
}
free (inputMatrix);
I don't understand why this works:
void main() {
int * b;
b = (int *)malloc(sizeof(int));
*b = 1;
printf("*b = %d\n", *b);
}
while this does not (gets segmentation fault for the malloc()):
void main() {
int ** a;
int i;
for (i = 0; i<= 3; i++) {
a[i] = (int*)malloc(sizeof(int));
*(a[i]) = i;
printf("*a[%d] = %d\n", i, *(a[i]));
}
}
since I find a[i] is just like b in the first example.
BTW, a[i] is equal to *(a+i), right?
You need to allocate memory for a first, so that you can access its members as a[i].
So if you want to allocate for 4 int * do
a = malloc(sizeof(int *) * 4);
for (i = 0; i<= 3; i++) {
...
}
or define it as array of integer pointers as
int *a[4];
a is a 2 dimensional pointer, you have to allocate both dimension.
b is a 1 dimensional pointer, you have to allocate only one dimension and that's what you're doing with
b = (int *)malloc(sizeof(int));
So in order the second example to work you have to allocate the space for the pointer of pointer
void main() {
int ** a;
int i;
a = (int**)malloc(4*sizeof(int*));
for (i = 0; i<= 3; i++) {
a[i] = (int*)malloc(sizeof(int));
*(a[i]) = i;
printf("*a[%d] = %d\n", i, *(a[i]));
}
The allocated pointer is written to uninitialized memory (you never set a to anything), causing undefined behavior.
So no, it's not at all equivalent to the code in the first example.
You would need something like:
int **a;
a = malloc(3 * sizeof *a);
first, to make sure a holds something valid, then you can use indexing and assign to a[0].
Further, this:
a[i] = (int*)malloc(sizeof(int));
doesn't make any sense. It's assigning to a[i], an object of type int *, but allocating space for sizeof (int).
Finally, don't cast the return value of malloc() in C.
actually malloc it's not that trivial if you really want safe and portable, on linux for example malloc could return a positive response for a given request even if the actual memory it's not even really reserved for your program or the memory it's not writable.
For what I know both of your examples can potentially return a seg-fault or simply crash.
#ruppells-vulture I would argue that malloc is really portable and "safe" for this reasons.