Question about pointer to array used in malloc/free - c

I saw the following code:
#include <stdlib.h>
void foo(char n)
{
int (*vals)[n] = malloc(sizeof(int[n]));
for (int i = 0; i < n; ++i)
(*vals)[i] = i;
free(vals);
}
int main(int argc, char **argv)
{
foo(*(argv[1]));
return 0;
}
This lines makes me very uncomfortable:
free(vals);
vals is a pointer pointing to an array. This looks right, but I just have a difficult time internalizing it, I do not know why.
I am more used to the following style:
int *p = (int*)malloc(n * sizeof(int));
......
free(p);
In this code, p is a pointer pointing to the start of a memory region for some integers, the malloc and free are symmetric in that they both work on a pointer type; yet the original code has malloc() working on a pointer to an array and free() a pointer.
Out of curiosity, I modified the original code:
free(vals); ==> free(*vals);
I was expecting this change will fail at compiler, the reason is *vals is an array now. But gcc is fine and valgrind does not complain memory leak.
I know C has a thing called array degenerates to pointer at function call. But I just cannot internalize this stuff. Sorry writing so long to describe a problem, wish you could see my struggle. Is there a definitive doc/stackoverflow/blog to clear this up - best C99 or later?
Thanks!

writing free(*vals); is same as writing free(vals);
edited your code to clear that a little bit
#include <stdlib.h>
#include <stdio.h>
void foo(char n)
{
int (*vals)[n] = malloc(sizeof(int[n]));
for (int i = 0; i < n; ++i)
(*vals)[i] = i;
printf("*val is %p\n", *vals);
printf("val is %p\n", vals);
printf("&val is %p\n", &vals);
free(vals);
}
int main()
{
foo(10);
return 0;
}
and this is the output:
*val is 0000018190365d50
val is 0000018190365d50
&val is 0000005d9dbff7b8
note that vals is Array pointer which means that its base type is an array of n integers where the pointer val is created in that stack and points to the whole array, not the first element only and that array is created in the heap, to illustrate, look at the following graph:
so for example if you write:
printf("val is %p\n", vals);
printf("val+1 is %p\n", vals+1);
the output will be :
val is 00000207ef0c5d50
val+1 is 00000207ef0c5d78
note the difference between the 2 is about 40 bytes as val points to the whole array not only one element as in case of int *p = (int*)malloc(n * sizeof(int));
note that when I say it points to the whole array, I also mean it points to the base address of the array.
in case of *Vals, look at the next graph:
*Vals is just an address of the first element of the array which is by the way is same as the base address of the array.
refer to free() manual, they said:
The free() function frees the memory space pointed to by ptr, which
must have been returned by a previous call to malloc(), calloc() or
realloc(). Otherwise, or if free(ptr) has already been called before,
undefined behavior occurs. If ptr is NULL, no operation is performed.
and what does malloc() function return ?
it returns the base address of your reserved space in heap, so writing free(vals); is same as writing free(vals);

This codes uses dynamic VLA.
I think that it may be easier to understand if the code is reformulated with a typedef.
void foo(char n)
{
typedef int T[n];
T *vals = malloc(sizeof(T));
...
free(vals);
}
Now it looks like a tivial use of a single dynamic object.
To access elements of an array first the pointer has to be dereferenced *vals forming an array, which decays to int* pointer suitable for [] operator.

Related

malloc() fails to allocate memory inside a function in C

I want to allocate memory dynamically inside a function. The function is named func_1 and is declared as follows:
int func_1(int **destination);
Here destination is a pointer to a pointer. This pointer contains the address of the pointer to which I want to allocate memory dynamically inside the function.
The function func_1 has the following code:
void func_1(int **destination)
{
*destination = (int*)malloc(sizeof(int) * 10);
for(int i = 0 ; i < 10 ; i++)
{
*destination[i] = i; //segmentation fault comes HERE
}
}
Below is my main() function:
int main()
{
int *pointer;
func_1(&pointer);
return 0;
}
When I try to run this program, I get a segmentation fault (SIGSEGV) error. I used GDB to locate the source of this fault, and it turned out that the line inside the for loop is the culprit for this error.
Please note that I wish to retain the values I have assigned to the dynamically allocated memory inside the function, once the function exits, and that's the reason due to which I have passed the address of the pointer to which I want to allocate memory dynamically.
I want to know:
Why am I getting this error ?
How can this be fixed ?
Thanks for help !
[] (array subscripting) operator has precedence 2
* (dereference) operator has precedence 3
In your code *destination[i] means the same as *(destination[i]). This value is uninitialized and it leads to segmentation fault.
If you will use explicit priority of operation (*destination)[i] you will get the expected result.
void func_1(int **destination)
{
*destination = (int*)malloc(sizeof(int) * 10);
for(int i = 0 ; i < 10 ; i++)
{
(*destination)[i] = i; //no segmentation fault
}
}
you can read more about precedence here
Full code:
#include <stdio.h>
#include <stdlib.h>
void func_1(int **destination)
{
*destination = (int*)malloc(sizeof(int) * 10);
for(int i = 0 ; i < 10 ; i++)
{
(*destination)[i] = i;
}
}
int main()
{
int *pointer;
func_1(&pointer);
return 0;
}
Why am I getting this error ?
You are overwriting the destination pointer instead of assigning the value returned by malloc to the pointer pointed to by the destination pointer.
Instead of *destination = (int*)malloc(sizeof(int) * 10) you should type **destination = malloc(sizeof(int) * 10).
Instead of *destination[i] = i you should type (**destination)[i] = i.
In C, the array subscript operator [] has a higher precedence than the indirection operator *. In addition to that, the former is left-to-right associative, while the latter is right-to-left associative.
In your case this means that you need to type (**destination)[i] = i; instead of **destination[i] = i, because otherwise the [i] will be evaluated before the ** and you end up indirecting a wild pointer (which will cause a segmentation fault extremely likely in the general and absolutely certainly in this case, since you are referencing a null pointer when i == 0).
How can this be fixed ?
The "just make it work" fix is the one I presented above.
However, that does not address the fundamental issue with your code, which is that it is unnecessarily complicated. Using a pointer to a pointer is very error-prone and should be avoided. Indeed, there is no need to use one at all in this case.
The following does exactly what you want without all the unnecessary complexity:
int* func_1()
{
int* destination = malloc(sizeof(int) * 10);
for (int i = 0; i < 10; ++i)
{
destination[i] = i;
}
return destination;
}
int main()
{
int* pointer = func_1();
free(pointer);
return 0;
}
Please note that I wish to retain the values I have assigned to the dynamically allocated memory inside the function, once the function exits, and that's the reason due to which I have passed the address of the pointer to which I want to allocate memory dynamically.
As I demonstrated above, there is no reason to pass a pointer to the pointer to the function. Memory allocated with malloc is yours to use forever , you just need to keep track of it and release it with a call to free when you no longer need it. How you keep track of the memory doesn't matter - simply returning a pointer is enough in this case. Modifying pointer inside func_1 rather than catching the function's return value provides no additional benefit and only serves to make the code more complicated than it needs to be.
I get the impression that you are somewhat confused about pointers, so I recommend that you revise the subject. Here is a quite clear explanation regarding pointers that also covers pointers to pointeres (and pointers to pointers to pointers): How do pointers work in C?
Read more:
Operator Precedence and Associativity in C
What is a segmentation fault?

Assign array without element by element copy?

I have a function which creates an array, of say, size 5.
Is it possible for the function to accept a pointer (or maybe it needs a pointer to a pointer?) and then point said pointer at an array, so that when the callee then looks at the pointer, it can see all values of the array.
Something along the lines of this (except this will not work):
#define LENGTH 5
void assignArray(int *pointer)
{
int arr[LENGTH] = {0,1,2,3,4};
// Point the pointer at the array, without manually copying each element
pointer = arr;
}
void main()
{
int *pointer;
pointer = malloc(sizeof(int) * LENGTH);
assignArray(pointer);
int i;
for (i = 0 ; i < LENGTH ; i++) printf("%d\n", pointer[i]);
}
C assign array without element by element copy
In C, arrays (compile-time allocated) cannot be assigned. You need to copy the elements from one array to another.
To avoid element-by-element copy, you can copy the whole array all at a time using library function.
I'm not very sure what you want to ask here, but it seems, you need to do memcpy() to achieve your goal.
If you have a secondary array arr to copy from, you can write
memcpy( pointer, arr, ( (sizeof arr[0]) * LENGTH ));
The code to do what you are describing might look like:
#define LENGTH 5
void assignArray(int **pp)
{
static int arr[LENGTH] = {0,1,2,3,4};
// Point the pointer at the array, without manually copying each element
*pp = arr;
}
int main()
{
int *pointer;
assignArray(&pointer);
for (int i = 0 ; i < LENGTH ; i++)
printf("%d\n", pointer[i]);
}
Note that one does not simply point *pp at a non-static local variable arr. That is because int arr[] = .... would go out of scope when assignArray returns.
If you want each call to assignArray to "return" a different array then of course you will have to allocate space and use memcpy each time you want to make a copy of the original array.
int arr[LENGTH] = {0,1,2,3,4}; will be stack allocated, so attempting to return the pointer to any of its elements will give you undefined behaviour as the whole thing will be out of scope when the function returns.
If you want to change what a pointer is pointing to then use 2 levels of indirection ** (i.e. pass a pointer to a pointer). You'll need to allocate the array arr on the heap using malloc or something similar.
As you are trying to do it, it is not possible due to the fact that your local arr is saved to the stack and is cleaned up after the function assignArry finished. As already mentioned you need to memcpy.
This answer will have two parts:
As mentioned in other answers, this is now how you're supposed to do it. A common construct in similar code is:
void assignArray(int *dest, size_t size)
{
int i;
// initialize with some data
for (i=0; i<size; i++)
dest[i] = i;
}
This way you're not wasting space and time with an intermediate buffer.
Second part of this answer is about wrapping arrays in a struct. It's a silly trick, that in a way achieves exactly what you asked, and also something that you probably don't want because of extra data copying.
Example code:
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 5
struct foo { int arr[LENGTH]; };
struct foo assignArray()
{
struct foo bar = { .arr = {0,1,2,3,4} };
/* return the array wrapper in struct on stack */
return bar;
}
int main()
{
struct foo *pointer;
pointer = malloc(sizeof(*pointer));
*pointer = assignArray(); /* this will copy the data, not adjust pointer location */
int i;
for (i = 0 ; i < LENGTH ; i++) printf("%d\n", pointer->arr[i]);
return 0;
}

integer pointer is not working while assigning two dimensional array via another pointer?

I was trying to copy the contents of one 2d array to another using pointers. I wrote this simple test program but it shows me segmentation fault but i still cannot find a rock solid reason why?
#include <stdio.h>
void main(){
int m[2][3]={
{2,3,4},{5,6,7}
};
int *p=m;
int *n;
int i,j;
for(i=0;i<2;i++){
for(j=0;j<3;j++){
printf("%d \t", *(p+3*i+j));
printf("Debug here\n");
*(n+3*i+j)=*(p+3*i+j);
}
printf("\n");
}
}
// Output:
// 2 Debug here
// Segmentation fault (core dumped)
int *n is an unitialized pointer, you never allocated memory for it, therefore you are trying to write your copy onto unknown territory.
You can alloc space to n using this:
int *n = (int *)malloc(2 * 3 * sizeof(int));
You are not allocating space for your target array. At minimum, you should do:
int *n = malloc(2 * 3 * sizeof(int));
or
int n[2][3];
A pointer is a variable that points to a memory location. It stores the address of the memory location. You can access that location by dereferencing the pointer using *.
In your case,
int *n;
This only declares a pointer to an int. This can point to a single integer or an array integers. You have not yet assigned any value to it (It is still not assigned a memory location). We don't know where it is pointing right now (You might not be allowed to access the memory etc.). (That's why the seg fault)
You need to allocate memory as such,
int *n = malloc(2 * 3 * sizeof(int));
The advantage of a pointer to a dynamic array than a static array
int n[2][3];
is that the pointer can be re-used (Of course you need to take care of freeing the existing memory before resuing the pointer [If you dont have any other access paths to the memory])
reason why?
The destination area is not ensured
#include <stdlib.h>
int *p=&m[0][0];
int *n = (int*)malloc(sizeof(m));

Initializing array of integer pointer in C

I have some confusions/problems about the usage of pointers in C. I've put the example code below to understand it easily. Please notice differences of these codes. If you have some problem understanding it, please have a feedback.
This doesn't work.
#include <stdio.h>
#include <stdlib.h>
void process() {
int *arr;
arr=(int*)malloc(5*sizeof(int));
arr=(int*){3,1,4,5,2};
for(int z=0;z<5;z++) {
printf("%d ",arr[z]);
}
printf("\n");
}
int main() {
process();
return 0;
}
But this works.
#include <stdio.h>
#include <stdlib.h>
void process() {
int *arr;
arr=(int*)malloc(5*sizeof(int));
arr=(int[]){3,1,4,5,2};
for(int z=0;z<5;z++) {
printf("%d ",arr[z]);
}
printf("\n");
}
int main() {
process();
return 0;
}
This also works too. Why? I didn't allocate memory here.
#include <stdio.h>
#include <stdlib.h>
void process() {
int *arr;
arr=(int[]){3,1,4,5,2};
for(int z=0;z<5;z++) {
printf("%d ",arr[z]);
}
printf("\n");
}
int main() {
process();
return 0;
}
Why aren't they same?
arr=(int*){3,1,4,5,2};
arr=(int[]){3,1,4,5,2};
Is there any other way to initializing array of integer pointer, not using in this individual assigning way?
arr[0]=3;
arr[1]=1;
arr[2]=4;
arr[3]=5;
arr[4]=2;
How can i get the size/number of allocation in memory of pointer so that i can use something like for(int z=0;z<NUM;z++) { instead of for(int z=0;z<5;z++) { statically?
Any answer is highly appreciated.
Thanks in advance.
The malloc calls in the first few examples allocate a block of memory and assign a pointer to that memory to arr. As soon as you assign to arr again, the pointer value is overwritten, and you've lost track of that allocated memory -- i.e., you've leaked it. That's a bug right there.
In other words, if you allocate a block of memory using using malloc(), then you can write data into it using array syntax (for example):
int* arr = (int *) malloc(sizeof(int) * 5);
for (int i=0; i<5; ++i)
arr[i] = i;
But you can't assign anything else directly to arr, or you lose the pointer to that block of memory. And when you allocate a block using malloc(), don't forget to delete it using free() when you don't need it anymore.
An array is not a pointer-to-integer; it's an array. An array name is said to "decay to a pointer" when you pass it as an argument to a function accepting a pointer as an argument, but they're not the same thing.
Regarding your last question: that's actually the difference between an array and a pointer-to-type: the compiler knows the size of an array, but it does not know the size of a block pointed to by an arbitrary pointer-to-type. The answer, unfortunately, is no.
But since you're writing C++, not C, you shouldn't use arrays anyway: use `std::vector'! They know their own length, plus they're expandable.
When you say: ptr = {1,2,3,4,5}, you make ptr point to a memory in the data segment, where constant array {1,2,3,4,5} resides and thus you are leaking memory. If you want to initialize your memory, just after allocation, write: ptr[0]=1; ptr[1]=2; and so on. If you want to copy data, use memcpy.
The comma-separated list of values is a construct for initializing arrays. It's not suitable for initializing pointers to arrays. That's why you need that (int[]) - it tells gcc to create an unnamed array of integers that is initialized with the provided values.
gcc won't let you losing the information that arr is an array unless you really want to. That's why you need a cast. It's better that you declare arr as an array, not as a pointer. You can still pass it to the functions that accept a pointer. Yet gcc would not let you leak memory with malloc:
error: incompatible types when assigning to type ‘int[5]’ from type ‘void *’
If you want a variable that can be either an array or an pointer to allocated memory, create another variable for that. Better yet, create a function that accepts a pointer and pass it either an array or a pointer.

ansi c struct {with dynamic array} assigned to array which is realloc

why the below code gives me error of "double free or corruption"... when i compile and run with gcc [(Debian 4.4.4-8) 4.4.5 20100728 (prerelease)]. Thanks in advance!
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int *index1;
} data;
void doo(int *);
int main(int argc, char *argv[])
{
int *a = (int *) malloc(10*sizeof(int));
int i;
for(i=0; i<10; i++)
{
a[i] = 2*i;
}
doo(a);
data one;
one.index1 = a;
printf("%d\n", one.index1[4]);
free(a);
printf("%d\n", one.index1[4]);
free(one.index1);
return 0;
}
void doo(int *b)
{
b = (int *) realloc(b, 5*sizeof(int));
return;
}
one.index1=a;
...
free(a);
...
free(one.index1);
...
Ergo, the double free.
void doo(int *b)
{
b = (int *) realloc(b, 5*sizeof(int));
return;
}
When you pass the a pointer to this function, its value(which is infact an address), gets copied into b, another local int pointer.
Now, when you realloc space for 5 ints, it changes the space allocation for a infact. So your space gets reduced from 10 to 5 ints.
As requested by OP, to get the same data & separate memory pointers, space must be allocated afresh for the new pointer, as a pointer is after all, just a variable, holding an address. If you allocate two separate blocks, you would get two separate addresses, which can be freed individually.
Because the storage pointed to by 'a' and 'one.index1' are the same (assignment before the first printf). Thus you have a double free.
You are passing to doo a pointer. You modify the pointer itself, but your main function does not get the new address.
That happens because you make one.index1 and a point to the same memory location.
To test this add the following to your code:
one.index1 = a; // from now on, both variables point to the same address
printf("-> 0x%x\n", one.index1);
printf("-> 0x%x\n", a);
printf("%d\n", one.index1[4]);
free(a); // release the resource pointed by a
// You should not try to print the data of one.index1[4] since
// that piece of memory doesn't exist no more.
printf("%d\n", one.index1[4]);
free(one.index1); // Problem: trying to free the same memory resource TWICE.
You'll notice that both pointers will print the same memory addresses. So after free(a); is executed, performing free(one.index1); is redundant, and trying to free a resource that is not allocated anymore is what is causes the problem.

Resources