Re: memory and subroutines



Eric Sosman wrote:

Frank Silvermann wrote On 06/14/06 15:57,:
Eric Sosman wrote:
[...]
Also, when writing a function that our C++ friends
might call a "constructor," consider writing a companion
"destructor" function at the same time. In this case the
companion would simply call free(), but other uses may
eventually appear and you'll be prepared for them. For
example, you might decide that the program creates and
destroys so many of these things that it's worth while to
implement a little cache instead of thrashing back and
forth so much with malloc() and free(). This will be easy
to do if the "clients" call your destructor function, much
harder if they're in the habit of calling free() directly.
Even a question like "What is the maximum number of these
things the program ever uses at any one time?" is easy
to answer if you've followed the constructor/destructor
pattern, hard if you can't "see both ends" of a thing's
lifetime.
I see your point. Here I might put the output in a function:
void print_it_and_free_it{char * p, n)

There's a fairly important design principle known as
KISS for "Keep It Simple, Stupid!" Try to get a function
to do one easily-described job and do it well; avoid writing
functions that resemble Swiss Army pocket knives with fifty-
leven folding blades. Here, I'd suggest writing a print_it()
function and a separate free_it() function; the two tasks
(printing and freeing) don't seem to have much to do with
each other, and probably don't belong together. What if you
someday want to print it, adjust it, print it again, and
then free it? What if you want to free it without printing?
You can build more different kinds of things out of the simple
shape of a brick than from the complex shape of a fireplace.

(This advice isn't really C-specific or even programming-
specific; it applies in a lot of endeavors. If anything, C
offers less "active help" to the programmer than some other
languages do, so there's a higher premium on simplicity as
an aid to understanding -- and error avoidance ...)

I'm a little sketchier on what a cache would mean in this context. frank

The example you gave probably wouldn't have much use for
a cache. (But then, the example didn't seem all that realistic:
How frequently do you find yourself needing an array of the
integers 0 through n-1?) But suppose you're writing something
like a chess-playing game that allocates lots and lots of data
structures to represent possible game positions. After it
ponders matters for a while, your program chooses one of the
available moves and thereby discards all the positions that
resulted from moves not chosen. Then the opponent chooses a
move and once again your program discards a lot of data, and
then you start exploring the new situation and re-allocating
all those position records again. Instead of diving in and
out of malloc() and free() all the time, you might find it
advantageous to "free" a position by just sticking it on a
list of position records that are currently unused and "blank."
Then when you need a new position you can recycle one of the
old ones, and only use malloc() when the supply of recyclables
runs dry.

Anyhow, it's far from unlikely that you'll find reasons to
want to do something special when objects are deallocated,
even if those reasons aren't apparent from the start. If you've
written a free_it() function, even if it does nothing but call
free() when you first write it, you'll have given yourself a
convenient place to add the special sauce later on. But if your
callers just call free() behind your back, ...

Like an overeager apprentice, I have already gone and done what you told me not to do. I can claim, at least for the duration of this post, that I was acting in ignorance. The good news it that I've now got pointers that get passed properly and data to examine. I think that if I permute p, I'll have the random partition I want:


/* partition3.c */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#define SWAP(m, n) (tmp = (m), (m) = (n), (n) = tmp)
#define ITERATIONS 15

int rand_in_range(int, int);
int * partition(int, int);
void print_it_and_kill_it(int * , int);

int main(void)
{
int m=15, n=6, i;
int *p;
/* all declarations in main need to be north of here */
/* seed srand with time */
srand(time(NULL));
/* make subroutine calls ITERATION times and examine returns */
printf("set has %d elements and %d partitions\n", m, n);
for(i = 0; i < ITERATIONS; i++)
{
p = partition(m,n);
print_it_and_kill_it(p,n);
}
return 0;
}


int rand_in_range(int m, int n)
{
/*seed srand in main */
/* [m, n] is range */
int roll_again_threshold, divisor, result, tmp, offset, num_results;

if (m>n) SWAP(m, n);
offset = m;
num_results = n - m + 1;

if (num_results == 1) {
return m;
}

roll_again_threshold = RAND_MAX - RAND_MAX%num_results;
divisor = roll_again_threshold/num_results;

do {
result = rand();
} while (result >= roll_again_threshold);
result /= divisor;
return offset + result;
}

int * partition(int m, int n)
{
int top_range, i, p;
int *q;
/* end declarations */
q = malloc((n)*sizeof(*q));
/* if n>m bomb out */
if (n > m) return NULL;
top_range = m - n;

/* control */
for (i=0; i<(n-1); i++)
{
p=rand_in_range(0, top_range);
q[i] = p + 1;
top_range = top_range - p;
}
q[n-1]=top_range + 1;
return q;
}

void print_it_and_kill_it(int * p, int n)
{
int j;

for (j = 0;j < n; j++)
{
printf(" %d", p[j]);
}
printf("\n");
free(p);
}
/* end source */
I'll need to read your post as a hard copy and thank you explicitly for it. frank

.



Relevant Pages

  • Re: "EXT3-fs error" after resume from s2ram
    ... INT A disabled ... writing 0xe2000008) ... connection state: disconnected -> associated ... setting latency timer to 64 ...
    (Linux-Kernel)
  • Re: Rookie Student C++ Array question (reading from a file)
    ... >Start by writing down in plain english words what needs to be done. ... >int main ... >That's your overall plan. ... at the previous suggestion of mapping, ...
    (alt.comp.lang.learn.c-cpp)
  • Re: Rookie Student C++ Array question (reading from a file)
    ... >Start by writing down in plain english words what needs to be done. ... >int main ... >That's your overall plan. ... >do the additions inline in your real source code) ...
    (alt.comp.lang.learn.c-cpp)
  • Re: read and write columns
    ... You attempt to open the same file, "data", for writing and reading, ... Read the documentation for fscanf. ... int main ...
    (comp.lang.c)
  • Re: Inheritable Static methods
    ... the former encapsulates the conversion into the int type. ... writing "typeof.FullName" might not look quite as nice as "someClass.FullName". ... you've got a perfectly good alternative syntax that does _exactly_ the same thing. ...
    (microsoft.public.dotnet.languages.csharp)