[comp.sys.ibm.pc] TC function returns rubbish. why?

burleigh@cica.cica.indiana.edu (Frank Burleigh) (12/07/89)

Please observe the following (reduced) function and, below it,
a function returning pointer to char, which it calls:

void mark_cmp( char flag )
{
	int i;
	unsigned memleft;
	char sav_str[13], *p, *q;
	newfblk **f;
        ...
	f = fp;
	memleft = coreleft();
	for( i = 0; i < files; i++ ) {
		if( !((*f)->f_attrib & FA_DIREC) ) {
			p = (*f)->f_name;
			q = make_fn( p );  /*<big problems right here*/
                ...
		}
		f++;
	}
        ...
}
char *make_fn( char * file_name )
{
    int i;
    char *w, *p = file_name;
    char name[13];

    for( w = name; *p; p++ )
        if( *p != ' ' )
            *w++ = *p;                                  /*don't copy ws*/
    *w = '\0';
    return name;
}

make_fn receives a pointer to a file name prepared for display, 
that is, with spaces:

   fn     .ext

and changes it to 'fn.ext.'  The result is fine as it leaves
make_fn, but when we get back to mark_cmp, the string has 
been destroyed.  You may see only part of the name followed
by garbage (part of the name is lost), or you may see the
full name, but with trailing garbage, as though the terminating
null got lost.  I've tried a few modifications, to no avail.

I had handy a global string sufficient to hold the result, and
so to continue I have used that within make_fn instead of 'name',
and returned a pointer to that.  That works fine.

The program is compiled with TC 2, small model.  I really doubt
I've filled up the data segment, but don't have any way to
prove it (read: *I* don't know how to tell how much memory
is unallocated in the data segment).  If people suspect a
memory allocation problem, I might report that coreleft shows
around 32K left.  I don't know that that is within the data
segment.  (What sort of memory does coreleft report as "free?")

As long as I'm talking about memory, I might also complain that
I've had problems using TC malloc before; that is, I've had
experiences where I'd allocate a block of size N, put stuff in
it, then go to show it and find some junk in the space.  In all 
cases conversion to calloc fixed that problem.  Am I alone
in this?  But this is really a side complaint...

Please, fill my mbox with your ideas about why an apparently
good string upon exit from make_fn turns bad on return to
mark_cmp.

Thanks muchly.

-- 
Frank Burleigh  burleigh@cica.cica.indiana.edu
USENET: ...rutgers!iuvax!cica!burleigh BITNET: BURLEIGH@IUBACS.BITNET
Department of Sociology, Indiana University, Bloomington, Indiana 47405

Ralf.Brown@B.GP.CS.CMU.EDU (12/07/89)

In article <272@cica.cica.indiana.edu>, burleigh@cica.cica.indiana.edu (Frank Burleigh) wrote:
 >char *make_fn( char * file_name )
 >{
 >    char name[13];
 >
 >    return name;
 >}

 >make_fn, but when we get back to mark_cmp, the string has 
 >been destroyed.  You may see only part of the name followed

That's because you are returning the address of a variable which ceases to
exist as soon as you leave the function.  What you need is
      static char name[13] ;

--
UUCP: {ucbvax,harvard}!cs.cmu.edu!ralf -=-=-=-=- Voice: (412) 268-3053 (school)
ARPA: ralf@cs.cmu.edu  BIT: ralf%cs.cmu.edu@CMUCCVMA  FIDO: Ralf Brown 1:129/46
FAX: available on request                      Disclaimer? I claimed something?
"How to Prove It" by Dana Angluin
 13.  proof by reference to inaccessible literature:
      The author cites a simple corollary of a theorem to be found in a
      privately circulated memoir of the Slovenian Philological Society, 1883.

bobmon@iuvax.cs.indiana.edu (RAMontante) (12/07/89)

burleigh@cica.cica.indiana.edu (Frank Burleigh) <272@cica.cica.indiana.edu> :
-
-char *make_fn( char * file_name )
-{
-    int i;
-    char *w, *p = file_name;
-    char name[13];
-
-    for( w = name; *p; p++ )
-        if( *p != ' ' )
-            *w++ = *p;                                  /*don't copy ws*/
-    *w = '\0';
-    return name;
-}


Your `name[]' array is an automatic variable, created on the stack.
Thus it is guaranteed to be valid *only while make_fn() is active*.
Once control returns to the caller that storage may be legally trashed.
This isn't peculiar to Turbo C, it's a property of C itself (and of most
languages that can distinguish between "temporary" local storage and
"permanent" global storage).

Library functions such as ctime() avoid this same problem by making the
string storage be static data.  Such storage stays put, until a
subsequent function call overwrites it.  Another choice is to let the
caller supply the workspace --- this works better when the new string is
of varying length.

Try this:

char *make_fn( char * file_name )
{
    static char name[13], *w;

    for( w = name; *file_name; file_name++ )
        if( *file_name != ' ' )
            *w++ = *file_name;			/* copy only non-blanks */
    *w = '\0';
    return name;
}

leo@dduck.ctt.bellcore.com (Leo Zvenyatsky) (12/07/89)

In article <272@cica.cica.indiana.edu> burleigh@cica.cica.indiana.edu (Frank Burleigh) writes:
>        ...
>char *make_fn( char * file_name )
>{
>    int i;
>    char *w, *p = file_name;
>    char name[13];
>
>    for( w = name; *p; p++ )
>        if( *p != ' ' )
>            *w++ = *p;                                  /*don't copy ws*/
>    *w = '\0';
>    return name;
>}
> ... stuff deleted ...

Sorry for posting - mail bounced.

The problem is that name[] is NOT static (it is dynamic) and IS local
to make_fn.  When make_fn returns, all of its dynamic storage is
returned to the free pool and may or may not be overwritten by anything
else.  The point is that you CANNOT trust it!

The simplest solution is to declare name[] static, i.e. char static name[13].

Another solution is to pass to it a char pointer pointing to a storage within
the CALLING routine, and have make_fn populate that array.  Since calling
routine has not yet completed, all of its storage is still intact.

Hope that helps.
   _           ___	| If any views or opinions are found
 _//             /	| in this article, please return to:
 /    _  __     /	|          Leo Zvenyatsky
/___ </_(_)    /__ o	|       ...bellcore!ctt!leo