Global pointer pointing to locally defined type

A

Andrej Prsa

Hi!

What happens to a globally defined pointer, e.g.

void *value;

that points to a particular type in a function:

int dummy_func (int a)
{
value = &a;
return 0;
}

after the function returns to main? If this doesn't work, how could I make
it work? Do I have to allocate memory for this int and copy the original
int to that and then point value to this newly allocated int?

Thanks for your time,

Andrej
 
J

Joona I Palaste

Andrej Prsa said:
What happens to a globally defined pointer, e.g.
void *value;
that points to a particular type in a function:
int dummy_func (int a)
{
value = &a;
return 0;
}
after the function returns to main?

It points to a variable that is no longer in scope, thus no longer
accessible. Any attempt to indirect through that pointer will cause
undefined behaviour. In short, the pointer points to garbage and
cannot be used until reassigned.
If this doesn't work, how could I make
it work? Do I have to allocate memory for this int and copy the original
int to that and then point value to this newly allocated int?

That could be one way, yes.

--
/-- Joona Palaste ([email protected]) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"'It can be easily shown that' means 'I saw a proof of this once (which I didn't
understand) which I can no longer remember'."
- A maths teacher
 
B

Bernhard Holzmayer

Andrej said:
Hi Andrej,
What happens to a globally defined pointer, e.g.

void *value;

that points to a particular type in a function:

int dummy_func (int a)
{
value = &a;
return 0;
}

after the function returns to main?
I agree to Joona's opinion: it's undefined.
If the pointer is evaluated before its content has been modified,
it might work. But since you cannot rely on this, don't do it.
Even worse, some compilers transfer the parameter via a register,
so that a doesn't have an address location, and the pointer
evaluation would fail.

If this doesn't work, how
could I make it work? Do I have to allocate memory for this int
and copy the original int to that and then point value to this
newly allocated int?
That would work, but you mustn't forget to deallocate it afterwards,
or you'll end up with a memory leak. Your program would crash or
starve.

The better solution would be to transfer the pointer to a:

int dummy_func (int * a)
{
value = a;
return 0;
}

and then, instead of calling it with
dummy_func(toStore)
now you use dummy_func(&toStore).

If this isn't possible, because the caller doesn't know the address,
the function dummy_func wouldn't know the address, either.

Thanks for your time,

Andrej

Bernhard
 
B

Bernhard Holzmayer

Andrej said:
Hi!



This particular function builds a global parameter table and once
it's complete, it isn't modified ever again. When the program is
about to finish, I free all parameter values consecutively. This
brings me to another question: I have read at numerous places that
freeing memory just before the end of the program isn't necessary,
since the OS claims the memory back when the program execution is
over. Is this true?

Thanks,

Andrej

I guess you do the same thing, if you define a local variable in a
block like
{
int x;
use_of_x(x);
x = x+1;
...
}
the closing bracket removes the variable from the heap or from the
stack, wherever it has been allocated.

If you explicitely allocate memory, it's taken from heap or stack,
which has been granted to this program, and will be returned to the
OS after termination of the program.
Usually, you'll find this situation, which means that you're right.

This might be different if you use your own memory management
and allocate memory from additional resources which the compiler
isn't aware of. If you don't know how this works, you will
certainly not have to bother.

Bernhard
 
B

Bernhard Holzmayer

Andrej said:
Hi!


Unfortunately, I cannot do that, since I don't have the actual
variables when calling this function, rather the actual constants,
and e.g. &5 obviously doesn't work directly. I would lose
transparency if I used int a = 5; and then passing &a to the
function, because this function is called a zillion times with
default parameter values.

Thanks,

Andrej

Maybe you can use a global variable which you fill with the
parameters, and then call the function without parameters.
In this case, you'd avoid the lifetime problem.

Bernhard
 
M

Martin Dickopp

Andrej Prsa said:
Is there any better way you'd suggest?

I recommend to avoid "global" (file scope) objects whenever possible.

What's the best solution to your problem depends on what your problem
is. :) If you describe a bit more elaborately what you're actually
trying to achieve, we might be able to make better suggestions.

Martin
 
A

Andrej Prsa

Hi!
I recommend to avoid "global" (file scope) objects whenever possible.

What's the best solution to your problem depends on what your problem
is. :) If you describe a bit more elaborately what you're actually
trying to achieve, we might be able to make better suggestions.

Sure! I'm making a script language for modeling of eclipsing binaries. I
want to be able to reach a parameter table from all kinds of plug-ins to
this language, thus I have a global table like this:

typedef struct PHOEBE_parameter_tag
{
GtkWidget *widget;
char *qualifier;
char *keyword;
char *description;
PHOEBE_type type;
void *valueptr;
} PHOEBE_parameter_tag;

PHOEBE_parameter_tag *PHOEBE_parameters;
int PHOEBE_parameters_no;

Here PHOEBE_type is a simple enumeration that defines all types that a
particular argument can be and GtkWidget is a GTK+ widget (GUI related).
PHOEBE_parameters is a global array, to which parameters are added by
calling a function:

void declare_parameter (char *qualifier, GtkWidget *parent, char *widget,
char *keyword, char *description, ...)

The variable argument list holds the type and the initial value, e.g.:

declare_parameter ("phoebe_name_value", PHOEBE, "data_star_name_entry",
"NAME", "Star name", TYPE_STRING, "New star");

As you may imagine, I want the valueptr of the global PHOEBE_parameters
variable to point to whatever value corresponds to the given parameter.
Since it can be int, double, char *, but also an array of those, I hoped a
generic pointer void * would do the trick for me. And since this is a
back-end for a very large project (PHOEBE - PHysics Of Eclipsing
BinariEs), I want it to be, well, perfect! That's why I'm consulting you
guys!

Thanks for your time reading and answering!

Best wishes,

Andrej
 
A

Andrej Prsa

Hi!
Pass the address of a variable as a parameter to your function.

Unfortunately, I cannot do that, since I don't have the actual variables
when calling this function, rather the actual constants, and e.g. &5
obviously doesn't work directly. I would lose transparency if I used int a
= 5; and then passing &a to the function, because this function is called
a zillion times with default parameter values.

Thanks,

Andrej
 
A

Andrej Prsa

Hi!
That would work, but you mustn't forget to deallocate it afterwards,
or you'll end up with a memory leak. Your program would crash or
starve.

This particular function builds a global parameter table and once it's
complete, it isn't modified ever again. When the program is about to
finish, I free all parameter values consecutively. This brings me to
another question: I have read at numerous places that freeing memory just
before the end of the program isn't necessary, since the OS claims the
memory back when the program execution is over. Is this true?

Thanks,

Andrej
 
A

Al Bowers

Andrej said:
Hi!




Is there any better way you'd suggest?

Another way, perhaps not better, is the use of a static
variable.

#include <stdio.h>

void *value;

void dummy_func (int a)
{
static int buf;

buf = a;
value = &buf;
return;
}

int main(void)
{
dummy_func(21);
printf("Stored in value = %d\n",*(int *)value);
return 0;
}
 
D

Dan Pop

In said:
Hi Andrej,

I agree to Joona's opinion: it's undefined.
If the pointer is evaluated before its content has been modified,
it might work. But since you cannot rely on this, don't do it.
Even worse, some compilers transfer the parameter via a register,
so that a doesn't have an address location, and the pointer
evaluation would fail.

Nonsense! a DOES have an address inside dummy_func, regardless of how its
value was passed by the compiler and it's *always* legal to take its
address inside the function. The address becomes illegal after the
function returns. The canonical example is:

int *f(int a)
{
return &a;
}

or the similar

int *g(void)
{
int a;
return &a;
}

It is OK to call these functions *only* if their return value is
discarded.

Dan
 
M

Martin Dickopp

Andrej Prsa said:
I recommend to avoid "global" (file scope) objects whenever possible.

What's the best solution to your problem depends on what your problem
is. :) If you describe a bit more elaborately what you're actually
trying to achieve, we might be able to make better suggestions.

Sure! I'm making a script language for modeling of eclipsing binaries. I
want to be able to reach a parameter table from all kinds of plug-ins to
this language, thus I have a global table like this:

typedef struct PHOEBE_parameter_tag
{
GtkWidget *widget;
char *qualifier;
char *keyword;
char *description;
PHOEBE_type type;
void *valueptr;
} PHOEBE_parameter_tag;

PHOEBE_parameter_tag *PHOEBE_parameters;
int PHOEBE_parameters_no;

Here PHOEBE_type is a simple enumeration that defines all types that a
particular argument can be and GtkWidget is a GTK+ widget (GUI related).
PHOEBE_parameters is a global array, to which parameters are added by
calling a function:

void declare_parameter (char *qualifier, GtkWidget *parent, char *widget,
char *keyword, char *description, ...)

The variable argument list holds the type and the initial value, e.g.:

declare_parameter ("phoebe_name_value", PHOEBE, "data_star_name_entry",
"NAME", "Star name", TYPE_STRING, "New star");

As you may imagine, I want the valueptr of the global PHOEBE_parameters
variable to point to whatever value corresponds to the given parameter.
Since it can be int, double, char *, but also an array of those, I hoped a
generic pointer void * would do the trick for me.


You could allocate memory (e.g. using `malloc') and point `valueptr' to
it. However, this seems a bit wasteful when you only want to store a
single `int' or `double' object. Maybe you could use a union?

typedef struct PHOEBE_parameter_tag {
/* ... */
PHOEBE_type type;
union {
int i;
double d;
char *str;
int *i_array;
double *d_array;
} value;
};

In your `declare_parameter' function, you could then allocate memory for
strings or arrays, but avoid doing so for `int' or `double' objects:

switch (type)
{
case TYPE_INT:
PHOEBE_parameters .value.i = va_arg (ap, int);
break;

case TYPE_DOUBLE:
PHOEBE_parameters .value.d = va_arg (ap, double);
break;

case TYPE_STRING:
{
const char *const str = va_arg (ap, const char *);

PHOEBE_parameters .value.str = malloc (strlen (str) + 1);
if (PHOEBE_parameters .value.str != NULL)
strcpy (PHOEBE_parameters .value.str, str);
else
{
/* Handle memory allocation failure. */
}
break;
}

/* ... */
}

Martin
 
M

Martin Dickopp

Andrej Prsa said:
This brings me to another question: I have read at numerous places
that freeing memory just before the end of the program isn't
necessary, since the OS claims the memory back when the program
execution is over. Is this true?

That depends on the OS. All modern desktop or server systems reclaim
the memory automatically, but that's not necessarily the case for
embedded devices.

If you search the archives of this newsgroup on what's considered better
style, you'll find there's no consensus. I personally usually don't
bother to free memory immediately before the program terminates, because
I'm very sure that the kind of programs I write will never be ported to
embedded devices. :)

Martin
 
A

Andrej Prsa

Hi, Martin!
You could allocate memory (e.g. using `malloc') and point `valueptr' to
it. However, this seems a bit wasteful when you only want to store a
single `int' or `double' object. Maybe you could use a union?

:) This really makes me smile, because I had exactly these two options in
mind. I used mallocs for everything and void * to point to the space, but
after your reply I decided to go and change it to union. So now I am using
the code you suggested. Thank you very much!

Best wishes,

Andrej
 
C

CBFalconer

Martin said:
.... snip ...

If you search the archives of this newsgroup on what's considered
better style, you'll find there's no consensus. I personally
usually don't bother to free memory immediately before the
program terminates, because I'm very sure that the kind of
programs I write will never be ported to embedded devices. :)

In fact on some systems doing such frees can significantly slow
down program exit when there are a significant number of items to
be freed. Horrible examples include lcc-win32 and VC6, because
both depend on Microsoft libraries for the free operation. With
these systems it is not hard to generate an exit delay measured in
minutes.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,141
Messages
2,570,817
Members
47,362
Latest member
ChandaWagn

Latest Threads

Top