C language Array modification with Malloc - c

void helperWithoutMalloc(int *arr) {
arr[0] = 18;
arr[1] = 21;
arr[2] = 23;
}
int main() {
int *data;
helperWithoutMalloc(data);
printf("%d\n", data[0]);
return 0;
}
The above method successfully modify the value of data through the method helperWithoutMalloc(); however, when malloc method is applied; similar way doesn't work. Three value in the data array still zero
void helperNotWorking(int *arr) {
arr = malloc(sizeof(int)*3);
arr[0] = 18;
arr[1] = 21;
arr[2] = 23;
}
int main() {
int *data;
helperNotWorking(data);
printf("%d\n", data[0]);
return 0;
}
I'm just wondering what happen when the line arr = malloc(sizeof(int)*3) is implemented; and makes two code so different?
The main confusion is that : first code regardless of its incorrectness, can still modify the array element while second code, can't modify the array elements; since both functions pass the address of array; and we manipulate the array element through address

Any data structure in C as in any other language must be provided with a memory region where it data could be kept. In your first example you failed to do so. The 'data' pointer does not point to any memory and is initialized. It worked by a chance and you just caused your program to write data somewhere, which happened to be writable. you needed something like the following:
int main() {
int data[3]; // allocate an array for data
helperWithoutMalloc(data);
In the above example the memory was provided by the C array of 3 elements.
In a similar fashion you can use malloc:
int main() {
int *data = malloc(sizeof(int) * 3);
helperWithoutMalloc(data);
Note that the space for data was allocated before calling to the function and passed to it. The function can use pointer (memory address) to access the array elements.
In your second example you did a different mistake. You allocated the space, but you assigned the pointer to the parameter of the function. The pointer in your case was passed to your function by value, therefore it is uni-directional. you can pass it to the function but not backwards. It worked perfectly well inside the function but it did not update 'data', so you cannot access the values after returning from the function. There are few ways to work around it. I.e. you can return your pointer from the function:
int *helper() {
int *arr = malloc(sizeof(int)*3);
...
return arr;
}
int main() {
int *data = helper();
...
or you can use a pointer to pointer to pass to the function:
void helper(int **arr) {
*arr = malloc(...)
(*arr)[0] = 0;
...
}
int main () {
int *data;
helper(&data);

In my opinion, the correct way should be
void NoMalloc(int *arr) {
arr[0] = 18;
arr[1] = 21;
arr[2] = 23;
}
int main() {
int *data = (int *)malloc(sizeof(int) * 3);;
NoMalloc(data);
printf("%d\n", data[0]);
free(data);
return 0;
}
The malloc function allocates some memory and returns a pointer to that allocated memory.
Pointer stores addresses in the memory, and when you define a uninitialized pointer (such as the your first piece of code, int * data;) you don't know where the pointer (data) is pointing and therefore accessing the values stored at the location would often cause Access Violations and should never be used.
As with any other type of C variables, pointers are passed by values when serving as an argument of a function. So data itself would not be modified after calling helperWithoutMalloc or helperNotWorking. The second piece of code does not work because after calling helperNotWorking, the data pointer is still an uninitialized pointer. The numbers you though you have stored in data is actually stored in the modified value of arr in the helperNotWorking function, which does not affect does not point to the same address as data anymore.

Related

How does malloc work within wrapper function? [duplicate]

This question already has answers here:
How do I modify a pointer that has been passed into a function in C?
(7 answers)
Closed 2 years ago.
I have a question dedicated to:
void* malloc (size_t size);
In the regular example that can be found on millions of sites over the internet it's shown that the right way to use malloc is the following:
int main()
{
int* num;
num = malloc(sizeof(int));
*num = 10;
printf("Value = %d\n", *num);
free(num);
return 0;
}
But If I want to allocate memory within a function and use it in main like below, then the only option is to implement the function the following way:
void func_alloc(int** elem, int num_value)
{
*elem = malloc(sizeof(int));
**elem = num_value;
}
int main()
{
int* num;
func_alloc(&num, 10);
free(num);
return 0;
}
I assumed by mistake, that such code as below would work:
void func_alloc(int* elem, int num_value)
{
elem = malloc(sizeof(int));
*elem = num_value;
}
int main()
{
int* num;
func_alloc(num, 10);
free(num);
return 0;
}
Could you please explain or maybe give a link to resource with explanation why does it work only this way?
I really cannot understand why do I need double pointer as an input parameter and why in the other case it comes to "segmentation fault"...
Thank in advance ;)
I assumed by mistake, that such code as below will work.
In C, the arguments are passed by value, when you pass a pointer as an argument of a function, you are passing the value of the pointer, basically a copy of it, not the pointer itself, malloc will change the value of that pointer, but since what you passed was a copy, that is what's changed, not the original pointer, that one remains unchanged.
In the second code snippet, the working code, *elem = malloc(sizeof(int)); broadly means make this pointer elem point to this valid memory address given to me by malloc(assuming it succeeds), the value of the pointer to the pointer elem which you passed as an argument remains unchanged, it being a copy doesn't matter because it's not changed, it's still the same address that was passed as argument, the address of the pointer num which is now pointing to the memory location given by malloc.
**elem = num_value means store num_value in the address stored in the pointer where elem is pointing to, which is where num is pointing to, which is the new memory block previously given by malloc.
That being said, it's not the only option, you can use a local pointer, return it and assign it to another local pointer in the caller side, this is still a copy, but it's a copy of the changed pointer:
int *func_alloc(int num_value)
{
int *elem = malloc(sizeof *elem); //more idiomatic
if(elem == NULL){ // check for allocation errors
perror("malloc" );
exit(EXIT_FAILURE);
}
*elem = num_value;
return elem;
}
int main()
{
int* num = func_alloc(10);
free(num);
return EXIT_SUCCESS;
}
Footnote:
In the third code snippet, freeing num, given that it is uninitialized is a bad idea, I assume you know as much, nonetheless I thought I'd mention it. This may be the reason for the segfault you experienced, whatever garbage value num has will be assumed to be valid memory address, and free will try to deallocate it, doing this will invoke undefined behavior. If it was NULL, it's a different story, it's well defined behavior (execept in some very old standars). Initializing variables when they are declared is, in most cases, a good idea.
A commented explanation :
void func_alloc(int* elem, int num_value)
{
/* elem points to address gave by malloc, let's say 0x12345678 */
elem = malloc(sizeof(int));
/* at address 0x12345678 you have now your num_value */
*elem = num_value;
/* end of the function. Changes made to parameters passed by value are lost */
}
int main()
{
int* num;
/* num is a pointer to an address you could not have write access to, you actually don't know */
func_alloc(num, 10);
/* As C arguments are passed by value, changes made into the function are lost */
/* You try to free num which is still a pointer to an address you potentially have no access to => SEGFAULT */
free(num);
return 0;
}
EDIT:
Not shown in this example, but it is good practice to always check that pointer returned by malloc is not NULL, otherwise you should exit without trying to assign a value to the pointer.
If you have:
#include <stdio.h>
void foo(int x)
{
x = 9;
}
int main(void)
{
int a = 1;
foo(a);
printf("%d\n", a);
}
you probably don't expect the value of a in main() to change just because foo() assigned to x, right? It doesn't change, because parameters are assigned by value. The variables x in foo(), and a in main() are two different variables.
The same applies in your code. elem in func_alloc() is a different variable from num in main(), and assigning to the former doesn't change the value of the latter. The fact that these two are of type int *, and not e.g. just int, makes no difference in this.
That said, you can also return the pointer you got from malloc(), e.g.
int *alloc_int(int value)
{
int *p = malloc(sizeof(int));
*p = value;
return p;
}
(not that it seems to make much sense for a mere int.)

Passing double pointer as function argument

I simply want to assign a pointer to another pointer via the function (same memory address). My code is below:
#include <stdio.h>
void d(int** a)
{
int* val_ptr = malloc(1);
*val_ptr = 5;
printf("%d\n", *val_ptr);
a = &val_ptr;
}
int main()
{
int* a = NULL;
d(&a);
printf("%d\n", *a);
return 0;
}
Output from Link
5
Segmentation fault
Your code has three problems:
Here int* val_ptr = malloc(1);, you allocate 1 byte rather than allocating space for an int. Use the following to fix it:
int* val_ptr = malloc(1 * sizeof(int));
This a = &val_ptr; is not what you want. It changes the local pointer and makes it point to the address of val_ptr. This will not affect the pointer that you've defined in main.
Fix it using
*a = val_ptr;
This way, the pointer in main will also reflect the change and will point to the malloced memory
You should free the allocated memory after its use. Add
free(a);
after the printf in main to free it.

C Returning an array from a function

And having some trouble grasping arrays in C and how to return them via a function. If I do something like this
int main()
{
int num_set[10]={0,1}; //initialize first two elements as 0,1 and rest as 0
int* p=num_set; //assign array to int pointer called p
printf("\n%i",&num_set); //outputs 2686660 on my machine
printf("\n%i",&num_set[0]); //also outputs 2686660
printf("\n%i",p); //also outputs 2686660
printf("\n%i",p[1]);* //outputs 0; the same as num_set[1]
}
It works as expected, but when I try to return an array through another function like the following
int multiply_by_2(int given_number)
{
int num_set[10];
for(int fun_counter=0; fun_counter<10; fun_counter++)
{
num_set[fun_counter] = (given_number*2) ;
}
return num_set; //return int array num_set to caller
}
int main()
{
int* p = multiply_by_2(300) //assign array returned by function to p
for(int main_counter=0; main_counter>10; main_counter++)
{
printf("\np[%i] = %i"
, i, p[i]);
}
}
I get an error saying "invalid conversion from 'int' to 'int*'"
They was no error when I assigned the array to an int pointer in the first code, but I get this error when I try to return it through a function.
Please help.
In C you cannot return array by value. You would have to return the pointer of the array you want to return.
Pass a pointer and a size for a buffer to store your results.
There are a number of errors here.
The return type of the function multiply_by_2 needs to be int* - i.e a pointer to an integer. What is actually returned is a pointer to the first element of the array.
You are attempting to return a variable initialized on the stack (num_set). This will
disappear as soon as the multiply_by_two function exits, because it is an automatic variable. Instead, you should use the malloc function to allocate heap memory. Here's a link explaining the difference between stack and heap memory
You have a > where you should have a < in the for loop in main. As written the loop will immediately exit.
Minor point - the number 10 is repeated several times throughout the code. It is better practice to use a variable or a #define to give the number a meaningful name
Here's an amended version of the code:
#include <stdio.h>
#include <stdlib.h> //This is required to use malloc
#define ARRAY_SIZE 10
int* multiply_by_2(int given_number)
{
int *num_set =malloc(sizeof(int)*ARRAY_SIZE);
for(int fun_counter=0; fun_counter<ARRAY_SIZE; fun_counter++)
{
num_set[fun_counter] = (given_number*2) ;
}
return num_set; //return int array num_set to caller
}
int main()
{
int* p = multiply_by_2(300); //assign array returned by function to p
for(int i=0; i<ARRAY_SIZE; i++)
{
printf("\np[%i] = %i", i, p[i]);
}
free(p);
}
This is wrong on so many levels, but the compiler error comes from your declaration of "multiply_by_2". You declare it to return an integer, but then you try to return a pointer.
Let's try something like this:
int* multiply_by_2(int size, int given_number)
{
int *ip = (int*)malloc(size*sizeof(int)); // dynamically create int x[size]
for(int fun_counter=0; fun_counter < size; fun_counter++)
{
ip[fun_counter] = (given_number*2) ;
}
return ip; //return int array num_set to caller
}
Caller must free() returned memory.
int main(int argc, char **argv) {
int *ip = multiply_by_2(3, 2);
// ip points to array {4, 4, 4}
free(ip);
return 0;
}
We say that the function caller becomes owner of returned memory, that's why you are responsible to call free() later.
int multiply_by_2(int given_number) // not returning an array, but just an int
The return type of your function is int therefore you will get an error when trying to assign it to int *. Change it to the following:
int* multiply_by_2(int given_number)
This change is acceptable because in C, an array of ints is interchangeable with a pointer to an int.
Your header is wrong. Should be
int* multiply_by_2(int given_number)
You need to return pointer of int, not just int.
Another thing, in the function multiply_by_2 you have created local array. That means that the array will be deleted after the function will end.
You must use dynamic allocation (malloc and free).
Three major problems in your program:
The return type of function is int but you are returning an int * type.
You are returning the pointer to an automatic local variable.
Second expression in for loop in main would not let the body of loop to execute.
Change return type of the function to int * and use dynamic allocation.
int* multiply_by_2(int given_number)
{
int* num_set = malloc(sizeof(int)*10);
// rest of you code
}
And finally change second expression in your for loop in main to main_counter < 10. Use free in main to free the allocated memory.

What is the type of my array? [duplicate]

This question already has answers here:
Return a 2d array from a function
(10 answers)
How to return matrix (2D array) from function? (C)
(3 answers)
Closed 8 years ago.
I have the following function :
int** myfunc() {
int array[2][2];
// operation on the array
return array;
}
And the following error from the compiler :
cannot convert 'int (*)[2]' to 'int**' in return
So my question is : how can I return my array ?
So my question is : how can I return my array ?
You cannot. The array named array has function scope and goes out of scope when the function myfunc returns. This means the array no longer exists and trying to access it will invoke undefined behaviour. Also, the return type of myfunc is int **. In the return statement
return array;
the array named array is implicitly converted to a pointer to its element. int array[2][2]; defines array to be an array of 2 elements of type int[2], i.e., an array of 2 integers. Therefore, array in the return statement is implicitly converted to type int (*)[2], i.e., a pointer to an array of 2 integers. This explains the error message.
If you want to return an array from a function, you should allocate it dynamically using malloc which should later be freed in the caller after its use.
// you should change function signature to take the array size.
// and change return type to (int *) to return a pointer to the
// first element of the dynamically allocated array
int *myfunc(int len) {
int *array = malloc(len * sizeof *array);
if(array == NULL) {
printf("error in memory allocation\n");
return NULL;
// handle it
}
// operation on the array
return array;
}
Please note that an array type object is a contiguously allocated nonempty set of objects with a particular member object type, called the element type. Therefore, a 2-D array is not a new type. It's just an array type where the elements of the array are themselves arrays. This mean we have the following equivalence -
// an automatic array of 200 elements allocated on the stack
int auto_array[10][20];
// a dynamic array of 200 elements allocated on the heap
int *dynamic_array = malloc((10 * 20) * sizeof *array);
printf("%d\n", auto_array[4][8];) // prints element in the 5th row, 9th column
printf("%d\n", dynamic_array[4*10 + 8]); // prints element in the 5th row, 9th column
This only fixes the compiler error
The compiler is already giving you the correct type to return, you just need to give the type a name to return it easily:
typedef int (*myArrayPtr)[2];
myArrayPtr myFunc() {
int foo[2][2];
return foo; //Compiles, BUT DON'T USE IT (see below)
}
Alternatively, you can write the function declaration like this (but please don't, this should only be done in code that tries to win the International Obfuscated C Code Contest):
int (*myFunc())[2] {
int foo[2][2];
return foo; //Compiles, BUT DON'T USE IT (see below)
}
This approach actually works
The code above returns a pointer to a local variable, which is automatically deallocated when myFunc() returns. If the calling function uses the returned pointer in any way, anything might happen. To return a 2D array correctly, you need to malloc() it:
typedef int myArray[2];
myArray* myFunc() {
myArray* foo = malloc(2*sizeof(*foo));
foo[1][1] = 7;
return foo;
}
Note, that one of the two dimensions is encoded in the array type, while the other one is implicit in the pointer. That is why the sizeof of *foo must be multiplied by the size of the first dimension. Of course, you can also encode both dimensions in the array type, but that requires you to write an additional dereference when you access its elements:
typedef int myArray[2][2];
myArray* myFunc() {
myArray* foo = malloc(sizeof(*foo));
(*foo)[1][1] = 7;
return foo;
}
Arrays and pointers, while deceptively similar, are not the same thing in C.
You're trying to return a local variable, memory for which is allocated on the stack. The local variable will be popped off the stack as soon as your function exits, which is why most compilers give you a warning when you try to return the address of a local variable. The returned address points to a value that is gone.
What you need to do, is declare an int** & return it. You can allocate memory dynamically using malloc() present in the malloc.h header. Something like the following should work.
#include <stdio.h>
#include <malloc.h>
int** myfunc()
{
// Allocate memory so array can hold two int *
int** array = malloc(sizeof(int *) * 2);
// Allocate memory for each of the pointers that the array holds
// We want to reserve space for two integers in each slot.
array[0] = malloc(sizeof(int) * 2);
array[1] = malloc(sizeof(int) * 2);
array[0][0] = 0;
array[0][1] = 1;
array[1][0] = 2;
array[1][1] = 3;
return array;
}
int main(void)
{
int i, j;
int **x;
x = myfunc();
for (i = 0; i < 2; ++i) {
for (j = 0; j < 2; ++j) {
printf("%d", x[i][j]);
}
}
return 0;
}
Don't forget to free() the contents of the array when you're done with it.
Arrays are not first-class data types in C, you cannot return an array by copy, and returning a reference to a local variable will have undefined behaviour (and is never good).
There are three ways (at least) to do what you are attempting. The most usual (not to mention safe and efficient) is to have the caller own the array, then pass the array into the function by reference and have the function operate on the provided array:
void myFunc( int array[2][2] )
{
// operate directly on caller's array
}
The second method is to wrap the array in a struct, which is a first-class data type and can be exchanged by copy or reference. Note for large structures, exchange by copy can become expensive computationally.
typedef struct
{
int array[2][2] ;
} array_container ;
array_container myFunc()
{
array_container contained_array ;
return contained_array ;
}
Dynamically allocating the array within the function is a possibility, but leaves the question of who is responsible for freeing the memory and how and when it is safe to do so. However although I would not recommend it:
#define ARRAY_DIM1 2
#define ARRAY_DIM2 2
int** myfunc()
{
int** array = malloc( sizeof(int*) * ARRAY_DIM1 ) ;
int* array_memory = malloc( sizeof(int) * ARRAY_DIM1 * ARRAY_DIM2 ) ;
int i = 0 ;
for( i = 0; i < ARRAY_DIM1; i++ )
{
array[i] = array_memory[i * ARRAY_DIM2]
}
return array;
}

assign dynamic array in a function and send it back to the caller in C

I have been using java for long time but for some reason I need to use C (ANSI C not C++) to write a simple code. I need to pass the pointer from outside to a function, allocate some memory to the pointer and assign some values also before the function return. I have my code like
#include <stdio.h>
#include <stdlib.h>
void test(int *a)
{
int n=3;
// I have to call another function t determine the size of the array
n = estimatesize(); // n >=3
// I tried fix size n=10 also
a = (int*)malloc(n*sizeof(int));
a[0] = 1;
a[1] = 2;
a[2] = 3;
}
void main(void)
{
int *s=NULL;
test(s);
printf("%d %d %d", s[0], s[1], s[2]);
}
I don't know why the code crashes. I thought at the beginning it is estimatesize() return wrong number but even I fix n to 10, the error still there. So I cannot pass a pointer to a function for memory allocation? If so, how can I dynamically create memory inside a function and pass it out? I know it may be a safe problem in this way but I just want to know if it is possible and how to do that. Thanks.
There are two solutions to this: Either return the pointer from the function, or pass the argument by reference.
For the first one, you simply don't take any arguments, instead you return the pointer:
int *test(void)
{
int *a = malloc(...);
...
return a;
}
int main(void)
{
int *s = test();
...
}
For the second one, you need to pass the address of the pointer, in other words a pointer to the pointer, using the address-of operator &:
void test(int **a)
{
*a = malloc(sizeof(int) * 3);
for (int i = 0; i < 3; ++i)
(*a)[i] = i;
}
int main(void)
{
int *s;
test(&s);
...
}
The reason it doesn't work now, is because the pointer (s in main) is passed by copying it. So the function test have a local copy, whose scope is only in the test function. Any changes to a in the test function will be lost once the function returns. And as s is copied for the argument, that means that s in main never actually changes value, it's still NULL after the function call.

Resources