Initialization problem with malloc in C across functions - c

I'm having trouble understanding why the following code gives a garbage value.
EDIT: I need to use malloc, as it's part of the project requirements. I am well aware that it would be easier without using it, but I can't just not use it.
void int_init(int * x) {
x = malloc(sizeof(int));
*x = 7; //could be any number, 7 was chosen for fun
}
int main(void) {
int x;
int_init(&x);
printf("X: %d", x); //Should be "X: 7", is actually "X: 1595803432" or other garbage value
return 0;
}
I'm new to this, so apologies if this question is phrased poorly or is too trivial.
FINAL EDIT: Thanks to Vlad and Avi for helping me out. I may have misread the project description, since it seems like there is no way to use malloc to edit the original value of the variable. In my project, there is a struct that is associated with dynamically allocated memory (it contains an array of dynamically allocated structs), but I thought that it wanted us to dynamically allocate the entire struct. I apologize for the mistake, but am infinitely grateful for everyone's help.

In this function
void int_init(int * x) {
x = malloc(sizeof(int));
*x = 7; //could be any number, 7 was chosen for fun
}
the passed pointer was reassigned with the address of the dynamically allocated memory. So after that the pointer does not pointer to the original variable x declared in main.
As a result this statement
*x = 7; //could be any number, 7 was chosen for fun
assigns a value to the object in the dynamically allocated memory.
Moreover the function produces a memory leak because the allocated memory was not freed.
If you want to change the original variable x declared in main then define the function like
void int_init(int * x) {
*x = 7; //could be any number, 7 was chosen for fun
}
Taking into account your comment to my answer it seems you mean something like the following.
void int_init(int **x) {
*x = malloc(sizeof(int));
**x = 7; //could be any number, 7 was chosen for fun
}
int main(void) {
int *x;
int_init(&x);
printf("X: %d", *x);
free( x );
return 0;
}

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.)

Reason for Segmentation fault vs returning random values with the following C code

Please explain (reason for the output) what happens as a result of running the two segments of code. Please explain their difference too. There are two versions of setArr(int, int) as explained below...
#include <stdio.h>
void setArr(int, int);
int *arr[10]; // array of 10 int pointers
int main(int argc, char *argv[]) {
int i;
setArr(0, 0);
setArr(1, 100);
setArr(2, 200);
setArr(3, 300);
setArr(4, 400);
for (i = 0; i < 5; i++)
printf("arr[%d]: %d\n", i, *arr[i]); /* should be 0,100, 200,300,400 */
return 0;
}
Versions of setArr
Version A
void setArr(int index, int v) {
int i = v;
*arr[index] = i;
}
Output: Segmentation fault (core dumped)
Version B
void setArr(int index, int v) {
int i = v;
arr[index] = &i;
}
Output:
arr[0]: 400
arr[1]: 32748
arr[2]: 32748
arr[3]: 32748
arr[4]: 32748
I presume the values from running Version B are just random values.
I am fairly new to pointers I have knowledge in Java, so please explain it as beginner friendly as you can :)
You are hitting a lot of undefined behavior scenarios, but I will explain what is likely happening.
arr is an array of 10 pointers to integers.
int * arr[10]; // array of 10 int pointers
And when declared as a global variable, all of those pointers are going to be zero-initialized - so hence, it's an array of 10 NULL pointers.
So this line in version A, is dereferencing the address at arr[index]:
* arr[index] = i;
Is effectively saying this:
*(NULL) = i;
And that will certainly crash consistently.
In Version B, you have it as:
int i = v;
arr[index] = &i;
So now you are correctly assigning a pointer to a slot in the array. However that address getting assigned is to a local stack variable, i, which goes out of scope as soon as the function returns. So when you print the value at that address, it's most certainly been clobbered from other calls writing on top of the stack. (Or technically this "undefined behavior" of accessing a memory address of a stack variable that has gone out of scope.)
Better:
void setArr (int index, int v){
arr[index] = malloc(sizeof(int));
*arr[index] = v;
}
The above allocates memory for the address that you want to copy that value into. You're on your own for how to free that memory.
Alternatively:
Just declare arr as an array of integers instead of pointers:
int arr[10];
void setArr (int index, int v){
arr[index] = v;
}
And then print normally without the * deference thing on arr.
printf("arr[%d]: %d\n", i, arr[i]);
Version A says "the contents of an undefined pointer equals i" - undefined behavior = crash. Basically you are trying to write to some unknown location in memory.
Version B says "Some pointer = some address" - still undefined behavior as &i goes out of scope, but it is still an address and so it "kind of works". Here you are writing to "good" memory locations, but reading from bad ones.
in first case, you have defined the "array of pointers" to integer. They are not integer pointers. Either you will have to allocate memory (preferably using melloc/calloc functions) before storing any value to them OR you can define the array of integer like this:
int (*a)[10]
The following link may show you some idea about it: Difference between *ptr[10] and (*ptr)[10]
In second case, you are saving the address of integer into integer pointer, which is ok, but int i is local variable to function setArr(). This will therefore, the value of int i will be dereferenced every time the function setArr() exits. Therefore you are getting undefined behavior for 2nd case. Either you can use static int i OR use global variable (not preferred) OR use pointer to integer assignment.

Copies of a pointer into a pointer doesn't work in C

I have a function with two pointers in parameters. The first pointers(Position *x) points on a struct which have values, the second on nothing(Position *y) (it has not been initialized yet). I try to copy my first pointer into the second and then to printf the values from the second pointer but it doesn't work. I don't understand. Does it mean that you can change the value of a pointer but not his adress since in reality C language always works by value(i mean in parameter transfer) ?
void waitDeplacement(Position *oldPosition, Position *newPosition, Sens *sens, Niveau *niveau)
{ ...
newPosition = oldPosition;
printf("NEW POSITION x:%d / y:%d\n", newPosition->x, newPosition->y);
...
}
Beside, When I use a deep copy:
*newPosition = *oldPosition;
it work. So why please ?
Pointer to pointer copy is available in c. But for constant pointers copying is not permitted.Line
newPosition = oldPosition; will work only if newPosition is not a constant pointer.
The moment you do newposition = oldPosition;, newPosition and oldPosition will point to the same location of memory.
Please show your code , this will help in understanding the issue better.
Be sure that everything work in the C language if you know this language. Pointers too but it is quite complicated topic for the beginners. You just need to learn the C a bit more. Use your favorite book.
void foo(int *ptr1, int *ptr2, int **ptr3)
{
ptr1 = ptr2; // ptr1 == ptr2 only in the scope of foo
*ptr3 = ptr2; // changes the ptr3
}
int main()
{
int i = 1, j = 2, k = 3;
int *x = &i, *y = &j, *z = &k;
foo(x, y, &z);
printf("After the call:\n *x = %d, *y = %d, *z = %d\n\n", *x, *y, *z);
}
https://ideone.com/GN8IMg
Thanks to Peter_01 and other people I have solved this matter.
In fact your completely right when you say that the copy of a pointer into a pointer is local.
That's why when I put oldPosition in newPosition it works in fact but just ones.
Because my matter was that I called several times the same waitDeplacement function with between each call aoldPosition = newPosition outside the function.
But since the copy of newPosition = oldPosition does not really work and that newPosition values is equals to {0, 0}. We find at the end that oldPosition take the values of newPosition which means 0.
Thanks a lot for your help.

Change value in main using void sub-function

I am having trouble with this problem:
#include <stdio.h>
void change_number(int *x);
int main()
{
int x;
printf("Enter the number x: ")
scanf("%d", &x);
printf("In the main program: x = %d\n", x);
change_number(&x);
printf("In the main program: x = %d\n", x);
return 0;
}
void change_number(int *x)
{
x = *x+3;
printf("In the subroutine: x = %d\n", x);
}
Expected output:
Enter the number x: 555
In the main program: x = 555
In the subroutine: x = 558
In the main program: x = 558
Two notes:
I cannot modify main, or anything that comes before it. I can only modify the void change_number function, and the code inside it is my own code.
I cannot get the required output – my code only outputs x+3 in the subroutine, but doesn't change it in the main program.
How would I go about changing the value in the main routine? Please keep in mind that I am very new to C, and don't know many things yet (in fact, I just covered pointers yesterday).
The code
void change_number(int *x)
{
x = *x+3;
printf("In the subroutine: x = %d\n", x);
}
should read
void change_number(int *x)
{
*x = *x+3;
printf("In the subroutine: *x = %d\n", *x);
}
This will use the pointers as intended (you need to dereference them on the LHS as well)
I think an answer to the OP question needs a little bit explanation as C syntax may be confusing at times:
The function is declared as
void change_number(int *x)
The * means that the input parameter x is a pointer to a variable of type int. In other words x represents a location in memory.
Inside the function:
x is the address in memory of the int value
*x is the "content" of the memory address pointed by x
So, as other correctly pointed out, the function should be written as
void change_number(int *x)
{
*x = *x+3;
printf("In the subroutine: x = %d\n", *x);
}
Because as you act on *x you're acting on the content pointed by x
What is happening into main() ?
x is an int variable.
And you call:
change_number(&x);
The amplersand & means that you're not passing the value of x.
Instead you're passing a pointer to x, in other words the address in memory where the content of x is stored.
In other-other words x is passed by reference.
A final note: when writing a program in c (well, in any language, but expecially in c) the compiler warnings/errors and the debugger are your best friends.
Furthermore a good IDE will show you warnings as you type the code.
Anyway... the compiler should have warned you that
x = *x+3;
involves an implicit conversion from a int to int * (pointer to int) and most likely is a mistake.
You should use
*x = *x+3;
instead of
x = *x + 3;
What a function does with its parameters is, it makes a copy to work on and once the function's scope is ended, the copy is released which cannot change a value of a parameter passed to a function from outside.This is where pointers come in.
when passing a pointer to a function, think of it as a copy of the real address where in your case x is stored.
Thus in order to use x or change x, you have to use or change respectively *x(and it gets later dereferenced in the main program by &.
so like many others mentioned x = *x+3; should be *x = *x+3; and you'll get the desired results
Instead of printing in the change function you can also print in the main function by doing
*x=*x+3

Assign values to a dereferenced void pointer

I'm doing a class in c++ that supports any kind of variable to help me in a future project. The thing is, when I try to assign a value to a void* variable, I get the error: void* is not a pointer-to-object type. Here is the code:
int main (void) {
void* a;
int x;
a = malloc(sizeof(int));
x = 120;
((int)(*a)) = x;
printf("%d",((int)*a));
free(a);
system("pause");
return 0;
}
I see it like I am trying to assign the value of x in the memory block reserved for a. I want that the value stored in x be stored in the memory block of a. Can any1 help me?
You probably want to do:
void* a;
int x;
a = malloc(sizeof(int));
x = 120;
*(int*)a = x;
printf("%d", * (int*)a);
free(a);
You're making it too complicated. Just cast a to be an int *, or better yet declare a as int * to start with.
int x = 120;
int * a ;
// now just cast the result from malloc as int*
if((a = (int *)malloc(sizeof(int))) == NULL){ //ALWAYS check
exit(-1);
}
*a = x;
There are slicker ways to do similar things in C++, but you appear to be primarily caught up in pointer syntax.
You need the cast as *(int*)(a) = x;.
Firstly, you must cast a to the appropriate pointer type and then de-reference it. Secondly, use a template- that's what they're for. Thirdly, malloc and free is baaaad, OK? Don't. If you think that this is good code, you need serious remedial C++. Fourthly, this is already done- boost::any serves this purpose.
There are other elegant ways to assign a variable of different types. For your current question you can follow the standard way as,
int* const a = new int;
//...
*a = 120;
//...
delete a;
Or just for this problem specifically,
int a = 120; // simple
[Note: In your current solution if you do,
*((int*)(a)) = x;
it might be breaking strict aliasing rule.]

Resources