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.
Related
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.
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
I am trying to define a pointer to a struct as a global variable and access the value of its variables in different functions. But I realized that the values are cleared after the next function call. Am I doing something wrong?
struct St {
double* varDouble;
};
struct St* StGlobal;
void Fun1(){
double initDouble[2][1] = {{1},{2}};
StGlobal = (struct St*)malloc(sizeof(struct St));
StGlobal->varDouble = *initDouble;
};
void Func2(){
for (i =0;i<2;i++){
printf("%d\n", StGlobal->varDouble);
}
};
int main(){
Func1();
Func2(); // value of StGlobal->varDouble is no longer what was assigned to it in Func1
};
void Fun1(){
double initDouble[2][1] = {{1},{2}};
StGlobal = (struct St*)malloc(sizeof(struct St));
// OK. StGlobal points to a memory that was returned by malloc.
// The memory will be valid after the function returns.
StGlobal->varDouble = *initDouble;
// Not OK. initDouble is a local 2D array. *initDouble is a pointer
// that is valid as long as initDouble is in scope. When the function
// returns the pointer is not valid.
};
And
void Func2(){
for (i =0;i<2;i++){
printf("%d\n", StGlobal->varDouble);
// StGlobal->varDouble is dangling pointer.
// Also, you are printing a pointer using %d. ???
// If you try to access the pointer here, the program will exhibit
// undefined behavior since it is a dangling pointer.
}
};
After you allocate memory for StGlobal, you'll have to:
Allocate memory for StGlobal->varDouble also using malloc, or
Assign it to some other pointer that will be valid after the function returns.
Also. Don't cast the return value of malloc in C. See Do I cast the result of malloc?.
Additional info
You can force MSVC to treat a file as a C program file by setting a compiler option. In VS2008, I can do that in the following dialog box.
There is probably a similar way to change the setting in MSVC 2010.
I have a bug in which an incorrect value gets passed as an argument to a function in a C program. The way it works is, I declare a static pointer to a typedef-ed data structure as a global variable. There is an initialization function where this variable is initialized. This function allocates memory, initializes data fields and returns the pointer. Something like this:
static my_type *my_ptr;
...
void init(void){
my_ptr = init_my_type();
}
The function init_my_type is pretty straight forward:
void *init_my_type(void){
my_type *x = malloc(sizeof(my_type);
x->arg1 = 0;
... // more field initializations
return x;
}
Later on I use my_ptr as an argument to another function:
void do_stuff(void){
func(my_ptr);
}
The problem I have is that I seg fault in the guts of func when some of the data in the data structure that my_ptr points to is accessed.
When I run the debugger I get a nice looking hex value when I break on the init_my_type:
(gdb) finish
Value returned is $26 (void *) 0x79b6c0
Later, inside the do_stuff function, my_ptr has the same hex value:
(gdb) print my_ptr
$26 = (my_type *) 0x79b6c0
but, when I break on func the argument it gets has a totally different value.
Breakpoint 2, func(arg=0x1388)
I am type-punning pointers all over the place, but I don't see that that should change the address in memory that they point to, right? Also, the function func is declared inline but why should that affect this? This all seems correct to me -- it is entirely possible that I'm doing something stupid that I don't see.
Here is a complete program of the simplified code. In reality, all these functions don't get called by main, but by dynamically loaded helper functions. Still, I don't see how the address pointed to by my_ptr should change when passed to func.
#include "stdlib.h"
#include "stdio.h"
typedef struct _type{
int *i1;
float *f1;
}my_type;
static my_type *my_ptr;
void *init_my_type(void){
my_type *x = malloc(sizeof(my_type));
x->f1 = malloc(sizeof(float));
x->i1 = malloc(sizeof(int));
x->f1[0] = 123.456;
x->i1[0] = 789;
return x;
}
void init(void){
my_ptr = init_my_type();
}
inline void func(void *arg){
my_type *x = (my_type *)arg;
printf("%d %f\n", *x->i1, *x->f1);
}
void do_stuff(void){
func(my_ptr);
}
int main(void){
init();
do_stuff();
}
The following is not the cause of the issue (and can't, since static globals are initialised to zero by default). Though the basic idea is still relevant: whether the passed pointer is really the same that got initialised.
A wild guess:
static my_type *my_ptr;
Could it be that this line is part of some header file? Because then you have a global my_ptr in every source file that includes this header.
Since you wrote that this is a very large project, I assume that you separated the code and put it into multiple source files. Assuming the init function is in a different source file than the using function, then this would mean they're accessing different pointers. While the one init deals with gets initialised, the one func is using is uninitialised.
To check this you should print the address of the global pointer variable (&my_ptr) in both functions.
I have an assignment in C to implement a abstract data type STACK. The nature of the data type requires key structure that needs to have memory allocated. My problem is that my instructor insists, for now, for the initialization function to take in a pointer to the key structure. The init() function will do nothing more than allocate the memory necessary for the structure and set a field to zero, but the pointer that is passed in needs to be assigned that memory location.
I can't think of a way to do this without either having the function return a pointer, or to pass in a 2-star pointer - both of which are not allowed. I know The function prototype must be (where stackT* is a pointer to the key STACK data structure):
void init(stackT* stack);
I came up with this and it works fine:
void init(stackT** stack){
*stack = (stackT*) malloc(sizeof(stack));
(*stack)->count = 0;
return;
}
But it does not abide by the restrictions of the assignment.
tl;dr version:
Basically, how can I pass in the address of my original pointer to the STACK data structure (&stackPtr) into a function that takes one-star pointers as arguments and not get a pointer-type warning? Further, once you change the arguments to (stackT* stack) the below code does not work, even though I am passing the same thing either way - this is where my problem is.
I thought it is REQUIRED to have the argument as a 2-star pointer if you intend to pass in a pointer to a pointer .. the compiler must know what it is dealing with when you dereference a pointer.
At any rate, I am not sure how to do this given the restrictions. In my opinion this is only making it unnecessarily more difficult.
I believe, as pointed out in a comment, that you're missing the intention.
I think the idea is that the "root" stackT instance should be a well-known structure, so that you can declare one locally. Then you call init() to set up the actual stack described by the stackT instance:
int push_four(void)
{
stackT my_stack;
init(&my_stack);
push(&my_stack, 1);
push(&my_stack, 2);
push(&my_stack, 3);
push(&my_stack, 4);
}
The above assumes that the stack stores integers, i.e. the allocation inside init() should be something like:
void init(stackT *stack)
{
stack->items = malloc(64 * sizeof *items);
stack->count = 0;
}
And this, in turn, assumes a declaration like:
typedef struct {
int *items;
size_t count;
} stackT;
Of course, the default maximum depth (64) should be a parameter to init(), you must check (but not cast!) the return value of malloc(), and so on.
Typically when you have complex structures then there is a control struct and that one will have a pointer to the real memory.
Example:
struct stack_control_s {
void * memory;
size_t memory_size;
size_t current_size;
};
Then you would pass a pointer to the control structure to your initialiser and make it do the real work;
#define STACK_MIN_SIZE 0x100
int stack_init(struct stack_control_s * stack) {
memset(stack, 0, sizeof(*stack));
stack->memory = calloc(STACK_MIN_SIZE, 1);
if (!stack->memory)
return -1; //error
stack->memory_size = STACK_MIN_SIZE;
return 0; // all good
}
Here is a slightly modified header for a generic C list that I once made. I have added to macros to make it useable as a stack. Maybe this will give you some inspirations:
list_t.h
Use:
list_t(char) mylist;
list_init(&mylist);
list_push(&mylist, 'A');
printf("%c\n", list_pop(&mylist));
Probably it is not the best solution, but you can define your stack globally.
In this case it will look like a:
stackT G_stack;
....
void init(stackT* stack){
stack->count = 0;
return;
}
int main() {
.....
init(&G_stack);
.....
}
In this case you don't need to change prototype.
This assignes the pointer the address of the definition of STACK and passes the pointer to be initialized (using a single * :)... Will this work for you?
#include <ansi_c.h>
typedef struct {
int count;
} COUNT;
typedef struct {
COUNT count;
int *element1;
int *element2;
int address;
} STACK;
STACK stack, *pStack;
void InitStack(STACK *iS);
int main(void)
{ //This is how I think you will meet the
//criteria you are talking about (single *)
pStack = &stack; //assigning address of stack to pointer
InitStack(pStack);
//pStack->address == pStack
return 0;
}
void InitStack(STACK *iS)
{
iS->count.count = 0;
iS->address = (int)iS; //assigning address of stack to member of struct
iS->element1 = calloc(10, sizeof(int));
iS->element2 = calloc(10, sizeof(int));
}