[comp.unix.wizards] Problems with pointers

GLASGOW@NOSC-TECR.arpa (09/28/87)

     I am working ona a Sun 3/50 running SunOS V4.2.  I am trying to
use a generic pointer that I can use to point to one of several different
data structures.  I declare the pointer as:

typedef struct {
   /*  massive declarations  */
   ...
   } some_big_structure;

int    *p;

and by using:

p = (some_big_structure *)malloc(sizeof(some_big_structure));

I can get p pointing to a memory block of the correct size for the structre.

My problem arises when I try to release this memory back to the system. If
I use free(), will it assume that p points to an integer and release only
two bytes, or will it know that p is a larger structure and release the
proper number of bytes.  Also, if it releases only two bytes, is there a
way around this.  All of the different structures are large and memory is
tight, so this is definitely a problem.

All repsonses will be greatly appreciated.

michael

glasgow@marlin.nosc.mil
NOSC - San Diego

gew@dnlunx.UUCP (09/29/87)

In article <9519@brl-adm.ARPA>, GLASGOW@NOSC-TECR.arpa writes:
) int    *p;
) 
) and by using:
) 
) p = (some_big_structure *)malloc(sizeof(some_big_structure));
) 
) I can get p pointing to a memory block of the correct size for the structre.
) 
) My problem arises when I try to release this memory back to the system. If
) I use free(), will it assume that p points to an integer and release only
) two bytes, or will it know that p is a larger structure and release the
) proper number of bytes.

free() uses size information left behind by malloc() or calloc()
(usually in a few bytes just preceding the memory allocated).
there is no way of deciding from the C code which size the allocated
object is, as you can in Pascal. So the answer is *GO*RIGHT*AHEAD*.
Using an integer pointer probably won't pose any problems, but generic
pointers can be declared like this:

union gptr {
	struct big *big_p;
	struct even_bigger *ebgr_p;
	struct huge *huge_p;
}

If you happen to know the type of object you're freeing, you might
even use

switch(ptrtype){
	case a_big_p:
		free(p.bigp);
		break;
	case an_ebgr_p:
		free(p.ebgr_p);
		break;
	case a_huge_p:
		free(p.huge_p);
		break;
	default:
		panic();
}

None of this will make any difference though on 'normal' computer architectures.

If you don't use the above strategy, use a char * pointer (this is malloc()s 
result type anyway)


-- 
| Ge' Weijers                            |  Disclaimer: the views expressed |
| PTT Dr. Neher Laboratories             |  are usually entirely my own,    |
| Leidschendam, the Netherlands          |  not my employers'. I don't own  |
| uucp:  ...!mcvax!dnlunx!gew            |  a cat to share them with.       |

wietse@eurifb.UUCP (Wietse Venema) (09/29/87)

In article <9519@brl-adm.ARPA>, GLASGOW@NOSC-TECR.arpa writes:
> int    *p;
> p = (some_big_structure *)malloc(sizeof(some_big_structure));
> 
> My problem arises when I try to release this memory back to the system. If
> I use free(), will it assume that p points to an integer and release only
> two bytes, or will it know that p is a larger structure and release the
> proper number of bytes.  Also, if it releases only two bytes, is there a
> way around this.  All of the different structures are large and memory is
> tight, so this is definitely a problem.

The calling sequence of free() is (from /usr/lib/llib-lc):

	free(p) char *p; 

All pointer values should be converted to char * before passing them to
free(). Hence, from the pointer value alone free() can't tell what block
of memory a pointer is pointing to. Malloc() keeps its own administration 
of the size of blocks of memory it doles out so that free() knows how much 
memory is being released. 

A nice example of an implementation of malloc() can be found in "The C 
programming language" by Kernighan & Ritchie.

	Wietse Venema		(uucp:		mcvax!eutwc1!wietse)
				(bitnet:	wswietse@heithe5)

mike@BRL.ARPA (Mike Muuss) (10/01/87)

malloc(3) puts a small "header" in memory immediately before the
address of the pointer that it returns to you.  In there, it stores
the size of the block.  Thus, just handing the pointer back to free(3)
has the proper effect.

Here is some code that I often use to do this sort of thing:

/* Acquire storage for a given struct, eg, GETSTRUCT(ptr,structname); */
#define GETSTRUCT(p,str) \
	if( (p = (struct str *)malloc(sizeof(struct str)) == \
	    (struct str *)0 ) {\
		fprintf(stderr,"malloc str failure\n"); \
		exit(17); } \
	bzero( (char *)p, sizeof(struct str));

Memory acquired in this way is then released just by saying:

	free( (char *) p );

The cast is desirable as free(3) expects a char * argument.
	Best,
	 -Mike