Passing a pointer to a function doesn't work as expected - c

I have this tiny code :
#include <stdio.h>
#include <stdlib.h>
typedef struct Ship Ship;
struct Ship
{
int x, y;
};
int main()
{
Ship* ship;
assignShip(ship);
printf("%d", ship->x);
return 0;
}
void assignShip(Ship* ship)
{
Ship anotherShip;
anotherShip.x = 10;
ship = &anotherShip;
}
And it doesnt' work.
I create a pointer of type Ship named ship, and then I pass the pointer to my function, I set the pointer to anotherShip and then tries to see if it worked but the console goes in "isn't responding" and crash.
What am I doing wrong ?

There are ... some issues with your code and approach:
Parameters are passed by value
In C parameters are passed by value. This means that assignShip receives a copy of the pointer you have in main. So this assignment ship = &anotherShip; has no effect on the Ship* ship; variable from main, because you modify the local copy the function has.
The fix to this is to have a pointer to the main variable. I.e.:
int main()
{
Ship* ship;
assignShip(&ship); // we pass a pointer to the variable `ship`
printf("%d", ship->x);
return 0;
}
void assignShip(Ship** ship) // receive pointer to pointer
{
Ship anotherShip;
anotherShip.x = 10;
*ship = &anotherShip; // ... still wrong
}
This however brings us to the next big issue you have:
Local function variables have automatic storage duration
anotherShip is local to the function assignShip which means that as soon as the function call ends that variable is destroyed, so in main you will be left with a dangling pointer
The fix to this is to use dynamic allocation:
int main()
{
Ship* ship;
assignShip(&ship);
printf("%d", ship->x);
return 0;
}
void assignShip(Ship** ship) // receive pointer to pointer
{
Ship* anotherShip = malloc(sizeof(Ship));
anotherShip->x = 10;
*ship = anotherShip;
}
Now we have an object will will survive the call to assignShip.
And this brings us to the next problem:
Object with dynamic storage duration must have the lifetime managed by the programmer
Unlike automatic storage duration where the compiler is responsible to manage the lifetime of objects, with dynamic storage duration that is the responsibility of the programmer. So every memory allocated with malloc must be released with free:
int main()
{
Ship* ship;
assignShip(&ship);
printf("%d", ship->x);
free(ship); // free the memory
return 0;
}
And this brings us to the next issue:
Ownership of manually managed resources must be clear
Although the above version of our program is technically correct, there is a problem with they way we handle memory management.
Consider this snippet:
Ship* ship;
assignShip(&ship); // we pass a pointer to the variable `ship`
Does assignShip allocate memory for the parameter. Do we have to call free after it or does it expect to receive a pointer to a valid memory location?
To answer this we must consult the documentation of assignShip (if that exists) and/or the source code of assignShip
One approach is to make that clear from the function name. e.g. allocateAndAssignShip.
The other one is to move the allocation out of the function:
int main()
{
Ship* ship = malloc(sizeof(Ship));
assignShip(ship);
printf("%d", ship->x);
free(ship);
return 0;
}
void assignShip(Ship* ship)
{
ship->x = 10;
}

"What am I doing wrong ?"
A bunch of things.
First, inside function assignShip, the local variable anotherShip goes out of scope at the end of the function, leaving ship pointing to a variable that no longer exists.
Secondly, since you are passing variable ship by value, not reference, you cannot make permanent changes to it from within the function.
Instead:
#include <stdio.h>
#include <stdlib.h>
typedef struct Ship Ship;
struct Ship
{
int x, y;
};
int main()
{
Ship* ship = NULL;
assignShip(&ship);
// Check ship here, it is now non-NULL.
printf("%d", ship->x);
return 0;
}
void assignShip(Ship** ship)
{
static Ship anotherShip;
anotherShip.x = 10;
*ship = &anotherShip;
}

Ship anotherShip; is declared on the stack , once you leave the function the pointer is undeclared which means you assigned undeclared pointer .
either alloc it or make it locally static or globally and it should work

Related

Dynamic array in structs

I have a problem using dynamic memory in C.
I am creating a struct whose data is a number and a pointer to another struct (in short, an array of struct). The goal is for the parent struct to store an array of another struct using dynamic memory.
The problem I have is to access the cells of the created array, because I don't know if it's due to syntax issues (I'm new to C), or that I'm creating the array wrong, I can't modify the information contained in each cell of the contained array inside the parent struct. I can only modify by default the first cell.
This is my code, any idea or suggestion will be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char string[64];
void* date;
void* colour;
} DataState;
typedef struct {
int number;
DataState* array;
} Book;
Book* makeBook (int number){
int a=5;
void* auxiliary=&a;
Book* book_A=(Book*)(malloc(sizeof(Book)));
book_A->number=number;
book_A->array=(DataState*)(malloc(number*sizeof(DataState))); //creating array of structs inside main struct.
//And what I want to do is something like this, modify the information contained in cells of the array of structs of the main struct.
book_A->array[3]->date=auxiliary;
return book_A;
}
From already thank you very much.
Here:
book_A->array[3]->date=auxiliary;
you assign a value of auxiliary to the 3rd element of an array, but auxiliary is defined as
void* auxiliary=&a;
while a is an automatic variable in your function.
Automatic variables disappear at the return from the function, hence the pointer assigned to book_A->array[3]->date becomes invalid as soon as the return is executed.
If you want the data saved in a to remain valid after makeBook returns, then you must allocate it in more persistent storage than automatic. You've essentially done this:
int* foo()
{
int a = 5;
// WRONG, cannot return the address of a local variable
return &a;
}
int main(void)
{
int* a_addr = foo();
// WRONG, invokes undefined behavior
printf("a = %d\n", *a_addr);
}
If you want a to persist outside of foo, a possible option is:
int* foo()
{
int* a = malloc(sizeof *a);
// always check the return value of malloc
if (a != NULL)
{
*a = 5;
}
// this is ok. `a` is still in automatic storage, but this _returns_ its
// value, which is a pointer to data _not_ in automatic storage.
return a;
}
int main(void)
{
int* a_addr = foo();
// still must check here, malloc in `foo` could have failed. Probably
// better to design an architecture where you only check validity once
if (a_addr != NULL)
{
printf("a = %d\n", *a_addr); // prints a = 5
// don't forget to `free(a_addr)` when you're done with it, or you can
// let the OS clean up the memory when the process exits.
}
else
{
// handle error how you want
fprintf(stderr, "Out of mem!\n");
}
return 0;
}

how to return a pointer value from function to array of strings in c? [duplicate]

Is the following code (func1()) correct if it has to return i? I remember reading somewhere that there is a problem when returning a reference to a local variable. How is it different from func2()?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
This code snippet:
int& func1()
{
int i;
i = 1;
return i;
}
will not work because you're returning an alias (a reference) to an object with a lifetime limited to the scope of the function call. That means once func1() returns, int i dies, making the reference returned from the function worthless because it now refers to an object that doesn't exist.
int main()
{
int& p = func1();
/* p is garbage */
}
The second version does work because the variable is allocated on the free store, which is not bound to the lifetime of the function call. However, you are responsible for deleteing the allocated int.
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
int main()
{
int* p = func2();
/* pointee still exists */
delete p; // get rid of it
}
Typically you would wrap the pointer in some RAII class and/or a factory function so you don't have to delete it yourself.
In either case, you can just return the value itself (although I realize the example you provided was probably contrived):
int func3()
{
return 1;
}
int main()
{
int v = func3();
// do whatever you want with the returned value
}
Note that it's perfectly fine to return big objects the same way func3() returns primitive values because just about every compiler nowadays implements some form of return value optimization:
class big_object
{
public:
big_object(/* constructor arguments */);
~big_object();
big_object(const big_object& rhs);
big_object& operator=(const big_object& rhs);
/* public methods */
private:
/* data members */
};
big_object func4()
{
return big_object(/* constructor arguments */);
}
int main()
{
// no copy is actually made, if your compiler supports RVO
big_object o = func4();
}
Interestingly, binding a temporary to a const reference is perfectly legal C++.
int main()
{
// This works! The returned temporary will last as long as the reference exists
const big_object& o = func4();
// This does *not* work! It's not legal C++ because reference is not const.
// big_object& o = func4();
}
A local variable is memory on the stack, and that memory is not automatically invalidated when you go out of scope. From a function deeper nested (higher on the stack in memory), it’s perfectly safe to access this memory.
Once the function returns and ends though, things get dangerous.
Usually the memory is not deleted or overwritten when you return, meaning the memory at that address is still containing your data - the pointer seems valid.
Until another function builds up the stack and overwrites it.
This is why this can work for a while - and then suddenly cease to function after one particularly deeply nested set of functions, or a function with really huge sized or many local objects, reaches that stack-memory again.
It even can happen that you reach the same program part again, and overwrite your old local function variable with the new function variable. All this is very dangerous and should be heavily discouraged.
Do not use pointers to local objects!
A good thing to remember are these simple rules, and they apply to both parameters and return types...
Value - makes a copy of the item in question.
Pointer - refers to the address of the item in question.
Reference - is literally the item in question.
There is a time and place for each, so make sure you get to know them. Local variables, as you've shown here, are just that, limited to the time they are locally alive in the function scope. In your example having a return type of int* and returning &i would have been equally incorrect. You would be better off in that case doing this...
void func1(int& oValue)
{
oValue = 1;
}
Doing so would directly change the value of your passed in parameter. Whereas this code...
void func1(int oValue)
{
oValue = 1;
}
would not. It would just change the value of oValue local to the function call. The reason for this is because you'd actually be changing just a "local" copy of oValue, and not oValue itself.

Why can we initialize inside a function and still use that value outside the function?

For example:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct {
int n;
double d;
} some_thing;
void alloc_and_init_some_thing(some_thing** s, int n, double d) {
some_thing si = { .n=n, .d=d };
*s = malloc(sizeof(**s));
memcpy(*s, &si, sizeof(**s));
}
void alloc_and_init_int(int **i) {
int j = 21;
*i = malloc(sizeof(**i));
memcpy(*i, &j, sizeof(**i));
}
int main() {
some_thing *s;
alloc_and_init_some_thing(&s, 41, 31);
printf("s->n=%d s->d=%f\n", s->n, s->d);
int *i;
alloc_and_init_int(&i);
printf("*i=%d\n", *i);
return 0;
}
I'm still learning C and the difference between the stack and the heap. When we declare and initialize the variable si in the function alloc_and_init_some_thing, doesn't this value exist on the stack? Hence it should get wiped out when the function finishes?
But I can see that that doesn't actually occur. Back in the main function, when we print s->n, we get the value 41.
Similarly, when we print the value for *i in the main function, it prints 21.
Why is that?
The line memcpy(*s, &si, sizeof(**s)); copies the the structure si on the stack into the heap allocated structure s, thus making it persist in memory as heap allocations can be accessed anywhere in the program. It's merely a pointer to an address in memory.
The same thing happens in the similar function.
You are right that the lifetime of "si" and "j" are limited to their respective functions and not available after the return from those functions. However, their contents have been replicated via malloc/memcpy prior to the return of the functions and the pointers to the replicas are stored in variables "s" and "i", which are still alive at the time of printing (or using) those replicas.

Pointer to a local variable survives

I'd like to ask a simple question. Please, consider the attached code. In the main function, a pointer to a struct is built in two different ways by means of either ctor1 or ctor 2. In both cases the program works no matter which constructor I use.
The reason why ctor1 works is that memory for struct instance is allocated outside the function frame (i.e. in the heap). Therefore, it will be available in the main function after ctor1 termination.
My question boils down to ctor2 function. As far as I know, the local variable "myPtr foo" is expected to be destroyed at the function end. Hence, "that" pointer should point to nothing from now on. Having executed the program however, I found out that both constructors work flawlessly.
Obviously, there is a subtle detail that eludes me. Could you explain why function ctor2 works?
Thank you in advance!
#include <stdio.h>
#include <malloc.h>
int _method(void) {
return 0;
}//_foo
typedef struct vTable {
int (*method)(void);
} myPtr;
myPtr *ctor1(void) {
myPtr *foo;
foo = (myPtr*)malloc(1 * sizeof(myPtr));
foo->method = &_method;
return foo;
}//ctor1
void ctor2(myPtr *that) {
myPtr foo = { &_method };
that = &foo;
return;
// having reached the function end "foo" is destroyed
// and "that" should point to nothing, supposedly
}//ctor2
int dtor(myPtr *foo) {
free(foo);
foo->method = NULL;
foo = NULL;
return 0;
}//dtor
int main(void) {
myPtr *vPtr;
// it works as expected
vPtr = ctor1();
printf("%p\n\n", vPtr); // 003E0F68
dtor(vPtr);
// it works surprisingly enough
ctor2(vPtr);
printf("%p\n", vPtr); // 003E0F68
printf("%p\n", vPtr); // 003E0F68
// it keeps on working
printf("%p\n", vPtr); // 003E0F68
dtor(vPtr);
return 0;
}//main
Screenshot
The code void ctor2(myPtr *that) declares that to be a parameter that points to an object of type myPtr. Parameters are passed by value, so the parameter that is only a copy of whatever was passed. Changing that does not change the thing that was passed.
If you want to change the value of a pointer to myPtr, you must pass a pointer to a pointer to myPtr:
void ctor2(myPtr **that)
Then you can change it with:
*that = malloc(…);
There are several problems here, let's go through them one by one.
First, in your ctor2 function:
void ctor2(myPtr *that) {
myPtr foo = { &_method };
that = &foo;
return;
}//ctor2
This function is actually taking in a pointer to myPtr by value and modifying it locally to point to something allocated on the stack in the function. This has on effect on the pointer passed in. If you wanted to modify the pointer passed in, you would have passed in a double pointer and dereference it:
void ctor2(myPtr **that) {
//malloc foo
*that = foo;
return;
}
Secondly, because you never modified vPtr through the call to ctor2 the second call to dtor is freeing already freed memory, which is undefined behavior that usually leads to a crash. I'm surprised it didn't crash on your system, but that's the thing with UB, you never know.
Thirdly, the behavior you wanted to emulate is:
/* constructor */
void Shape_ctor(Shape * const me, int16_t x, int16_t y) {
static struct ShapeVtbl const vtbl = { /* vtbl of the Shape class */
&Shape_area_,
&Shape_draw_
};
me->vptr = &vtbl; /* "hook" the vptr to the vtbl */
me->x = x;
me->y = y;
}
The difference is that in this case the ShapeVtbl structure is statically allocated. This is OK because it only points to functions, which will not change from object instance to object instance. But having it statically allocated allows it to be allocated within a function like that and assigned to the object.
To amplify Eric Postpischil's excellent answer, consider,
void foo( int i ) { i++; }
This function changes the value it was passed, but not that value is a copy of the original when it was invoked,
int j=8;
foo(j);
You wouldn't expect j to change, right?
The same is true for
void ctor2(myPtr *that) { // my version
that = NULL;
}
that is a copy of the parameter passed on invocation,
ctor2(vPtr);
Because vPtr doesn't change, your program prints ... its unchanged value.
ctor2 can change the value of anything pointed to by that, but any change to the parameter itself has only a local effect.
There are other errors in your program, as other answers point out. But the answer to why ctor2 "works" is basically that it doesn't do anything.

simple pointers to pointers

I know why this works:
#include <stdio.h>
void cool_number(int **number) {
int value = 42;
int *p = &value;
*number = p;
}
int main () {
int *number;
cool_number(&number);
printf("number is %d\n", *number);
return 0;
}
What I don't understand is why this doesn't (in my machine it prints 3700 or something like that).
#include <stdio.h>
void cool_number(int **number) {
int value = 42;
int *p = &value;
int **x = &p;
number = x;
}
int main () {
int *number;
cool_number(&number);
printf("number is %d\n", *number);
return 0;
}
Why aren't both equivalent?
both are evil as they capture the address of a stack variable.
Second one doesn't do what you expect because you are assigning directly to the parameter number, which is only temporary, the first one changes something the parameter number pointers to, which is the same thing as number in main points to.
I assume they're not equivalent because number is passed by value, on the stack, as is standard for function parameters. Any changes that you make directly to number inside of cool_number() are modifying the local copy on the stack, and are not reflected in the value of number in main().
You get around this in the first example by dereferencing number, which tells the computer to modify some specific location in memory that you also happen to have a pointer to back in main(). You don't have this in the second example, so all that happens is that you make the local number pointer point to somewhere else, without actually updating any memory location being referred to back in main(). Thus nothing you do shows up once you get back to main().
And since value is local to the cool_number() function, setting a reference to it that will be accessed after cool_number() returns isn't guaranteed to work and certainly shouldn't be used in any code outside of a trivial/toy example. But in this specific instance it's not really related to why you're seeing different results between the two pieces of code.
As I understand, in both cases, your code is wrong.
In the first case, you are returning an address to a variable allocated on stack, which will be deallocated as soon as the function returns.
In the second case, the error of the first case exists, plus you are passing number by value, so an updation to number will not get reflected in the caller function.
In 'C', arguments are always passed by value. So, you cannot update the argument passed as it is. For Ex:
int func(int a)
{
a = 5; // In this case the value 5 will not be reflected in the caller as what is updated is the local copy of a on the stack
}
int func(int *a)
{
*a = 5; // This update will show in caller as you are directly updating the memory pointed to by a
a = malloc(4); //This update will not show in caller as again you are updating the local copy of stack
}
#include <stdio.h>
void cool_number(int **number) {
int value = 42; /* this "value" hold 42 value,
and it lifetime is only in this function */
int *p = &value; /* here we get the address of "value" in memory */
*number = p;
}
int main () {
int *number;
cool_number(&number); /* after this function the "value" in memory had been recyled
and may be used by other program */
printf("number is %d\n", *number); /* so when we print value here it will be
a unpredictable value, somehow may be crash */
return 0;
}
both the same principle

Resources