[comp.lang.c] memory management between functions

jjk@jupiter.astro.umd.edu (Jim Klavetter) (04/29/91)

A few weeks ago I asked about where to allocate memory, in main()
or in the function.  The general idea I got back was that it
doesn't matter as long as you do it correctly (either place is
ok).

I wanted to make the functions completely autonomous, so this is
what I did (in some c-like metacode)

[includes]
double *subtract(a, b, n)
int n;
double *a, *b;
{
int i;
double *c;

[malloc c array here]

for(i=0; i<n; i++)
	c[i]=a[i]-b[i];
free(c);
return(c);
}

(Again, don't worry about efficiency, this isn't the code, just an
example of the malloc() and free() that is important).

The main program would have the fragments:

[malloc result]

result=subtract(vector1, vector2, n);

...

Conceptually, I like the above.  The problem is that it doesn't
work quite as expected:  when I take a look at the pointer result
(that is &*result, not the result of the pointer) before and after
the function it CAN (but not always does) change.  OK, I know I am
freeing the c array, but the very next thing I do is return it, so
I thought the result pointer would have the information
uncorrupted.

The question:  am I on the right track, or is it completely
impossible the way in which I am doing it?  I am calling subtract
(and many other vector operations) many times so I need to worry
about memory management.

In my first posting, someone offered the advice that the call to
subtract should be:

double *subtract(a, b, n, result)

where result is an "empty" array that will be used to return the
subtracted vector.  I think this would solve the problem, but I am
reluctant to use this idea because of the duplication (as well as
the fortranish look).  Is this NECESSARY duplication that I must
live with?

Thanks to all who helped me out enough last time to get into
trouble this time.

jjk@astro.umd.edu also for Athabasca and Reudi
Jim Klavetter
Astronomy
UMD
College Park, MD  20742

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (04/29/91)

In article <8504@umd5.umd.edu> jjk@astro.umde.edu (Jim Klavetter) writes:
> for(i=0; i<n; i++)
> 	c[i]=a[i]-b[i];
> free(c);
> return(c);

A pointer is just an address. The pointer variable c holds the address
of a malloc'ed array. When you blow away the array, c's address is out
of date, and once the array elements are dead and buried the postmaster
can't forward your mail (c[i]) to the cemetery.

---Dan

john@newave.UUCP (John A. Weeks III) (04/30/91)

In article <8504@umd5.umd.edu> jjk@astro.umde.edu (Jim Klavetter) writes:
> A few weeks ago I asked about where to allocate memory, in main()
> or in the function.

> I wanted to make the functions completely autonomous, so this is
> what I did (in some c-like metacode)

Stand back folks....

> [malloc c array here]
>
> for(i=0; i<n; i++)
>	c[i]=a[i]-b[i];
> free(c);
> return(c);
> }

Don't ever try to use memory that has been freed.  You never know
what the operating system is doing behind your back, or what other
programs running on your machine might be doing.  You would be
better off not freeing anything if you system frees memory for you
on exit, but this is not a good habit either.

Also, be careful passing back a value that was a local value in
your procedure.  You do not have this problem in your code, but
watch out for something like return(&c).  The address of c is an
address on the stack, and c might be wiped out as soon as the
procedure returns.

> In my first posting, someone offered the advice that the call to
> subtract should be:
> double *subtract(a, b, n, result)

> where result is an "empty" array that will be used to return the
> subtracted vector.  I think this would solve the problem, but I am
> reluctant to use this idea because of the duplication (as well as
> the fortranish look).  Is this NECESSARY duplication that I must
> live with?

There is a benefit to passing in the result.  You can have a pre-allocated
scratch vector or two laying around.  This will allow you to call
subtract without having to allocate memory on each call.  Also, you
can write a seperate vector allocation routine that would worry about
the house keeping details associated with memory management (like keeping
a list of pointer to free later on and worring about what to do if
the alloc fails).

By the way, once you get this working, think about optimizing your
subtract loop a bit.  I have seen some C compilers that generate
much better code for a loop like:

	aP = &( a[ 0 ] );
	bP = &( b[ 0 ] );
	cP = &( c[ 0 ] );

	for ( i = 0; i < n; i++ )
		*cP++ = *aP++ - *bP++;

rather than:

	for ( i = 0; i < n; i++ )
		c[ i ] = a[ i ] - b[i ];

Play with it in one procedure before going hog wild.  The Metaware
compiler for 68K UNIX generates the same code for both, in which case
the array notation is easier to understand a first glance.

-john-

-- 
=============================================================================
John A. Weeks III               (612) 942-6969             john@newave.mn.org
NeWave Communications                       ...uunet!tcnet!wd0gol!newave!john