[comp.lang.c] help needed about dynamic space allocation

fano@lifia.UUCP (11/21/86)

forgive the ignorance of a novice C-programmer:

I need advice on dynamic space allocation for multidimensionnal arrays:

Here is a way I have implemented dynamic allocation for a 2 X 2 matrix named
sig in a C-source file named combin1.c:
(I'll explain further the reason why I'm not satisfied with that solution)

  BEGINNING OF THE EXAMPLE:

  float **sig;                                    /* matrix declaration     */
  ....

  sig = (int *)malloc(n * sizeof(int));           /* allocates space for sig */
  for ( i = 0; i < n; i++)                        /* lines adresse           */
    {
      sig[i] = (float *)malloc(n * sizeof(float));/* allocates space for     */
    }                                             /* columns of line i       */
  ....

  for (i = n-1 ; i >= 0; i--)
    { 
      free(sig[i]);                                /* desallocates space     */
    }
  free(sig);

  END OF THE EXAMPLE


during the compiling time, I get the following warning:
     "combin1.c", line 220: warning: illegal pointer combination
any-way the program runs, and gives the desired results.


The compiler message suggests that I didn't use the proper way to implement
matrix dynamic allocation. So, could someone over there give me advices for
a cleaner solution.

Thanx.
-- 


    fano rampa*
///////////////////////////////////////////////////////////////////////////////

                           "Carmen lips are more exciting than Common lisp..."
                                                         -G.Bizet-

fano@lifia.UUCP      or     mcvax!lifia!fano

alastair@axis.UUCP (Alastair Adamson) (11/23/86)

In article <1046@lifia.UUCP> fano@lifia.UUCP (Rampa*) writes:
>
>  float **sig;                                    /* matrix declaration     */
>  ....
>  sig = (int *)malloc(n * sizeof(int));           /* allocates space for sig */
>
>during the compiling time, I get the following warning:
>     "combin1.c", line 220: warning: illegal pointer combination

Try changing the initialisation of sig to
	sig = (float **)malloc(n * sizeof(float *));
and the warning message will go away. Since sig is a double pointer to
a float, that is what you want malloc to return. You are creating a dope
vector, where each element of the vector is in fact a pointer a row
which in turn is a pointer to the elements of that row; thus:

	---		-----------
	| |------------>|         |
	| |-----        -----------
	---     |
	        |       -----------
	        ------->|         |
			-----------
The technique is common. Each element of the 2-dimensional table is float.
Thus the pointer to each row is a (float *). Sig points to these row pointers
ans is thus is (float **).

By the way, another solution which uses less memory is simplt to
get hold of enough space for all the elements of the table and do
the addressing yourself. For example a N x M table can be dealt with:

	table = (type *)malloc(N * M * sizeof(type));
	...
	table[i * N + j] = value;	/* put value in table[i][j] */
	...
	free((char *)table);		/* free the space */

Alternatively, to make acceses *look* better, use
#define	Table(i, j)	table[i * N + j]
and
	Table(i, j) = value;

Bonne chance,
	Alastair

throopw@dg_rtp.UUCP (Wayne Throop) (11/26/86)

> fano@lifia.UUCP (Rampa*)
> I need advice on dynamic space allocation for multidimensionnal arrays:

Well...  a little maybe.

>   float **sig;                          /* matrix declaration     */
>   sig = (int *)malloc(n * sizeof(int)); /* allocates space for sig */

OK.  Stop right here for a minute.  What's wrong with this picture?  It
is a little subtle, perhaps, but a pointer value of type (int *) is
being assigned to a pointer of type (float **).  Does anybody really not
see anything wrong with this?  Hmmmmmm?  Can you say "illegal pointer
combination"?  I knew you could.  Lint can say it too.  Let's say it
together, boys and girls...  (oh all right, I know I'm being nasty...
I'll behave myself the rest of the posting, alright?)

To fix this, make the allocation read:

        sig = (float **)malloc(n * sizeof(float *));

>       sig[i] = (float *)malloc(n * sizeof(float)); /* allocate a column */

This one is already correct.

>       free(sig[i]);           /* desallocates space     */

Should be: free((char *)sig[i]);

>   free(sig);

Should be: free( (char *)sig );

> during the compiling time, I get the following warning:
>      "combin1.c", line 220: warning: illegal pointer combination
> any-way the program runs, and gives the desired results.

The program will run correctly on systems where integers have the same
length as pointers to float, and where pointers to float have the same
format as pointers to char.  I don't know what kind of system that would
be.  Maybe... oh, I don't know... could it be... *A* *VAX*????  (Isn't
that special? :-)

> The compiler message suggests that I didn't use the proper way to implement
> matrix dynamic allocation. So, could someone over there give me advices for
> a cleaner solution.

In fact, the program seemed quite clean and well written already, except
for the pointer type mismatches and the hidden assumption about the size
of floats and ints.  Fix that, and the program should still work, and
lint will shut up also... who could ask for more?

--
A programming language is low level when its programs require attention
to the irrelevant.
                                --- Alan J. Perlis
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

turk@apple.UUCP (Ken "Turk" Turkowski) (11/27/86)

>> fano@lifia.UUCP (Rampa*)
>> I need advice on dynamic space allocation for multidimensionnal arrays:
>>
>>   float **sig;                          /* matrix declaration     */
>>   sig = (int *)malloc(n * sizeof(int)); /* allocates space for sig */

There have been numerous responses to get the declarations consistent, so I
won't belabor them here.

However, I would like to point out the use of a function that can speed up the
program considerably when you are only allocating temporary variables.  The
function is alloca(), and allocates memory from the stack, rather than from
the heap.  The result is that allocation is simpler, and vanishes automatically
when you exit the routine.

The purpose of alloca() is to compensate for the deficiency in C that does not
allow you to do something like this:

	func(a, n)
	int *a, n;
	{
		int b[n+1];	/* <- C doesn't allow this */
		. . .
	}

by doing this:

	func(a, n)
	int *a, n;
	{
		int *b;
		b = (int *)(alloca((n+1) * sizeof(int)));
		. . .
-- 
Ken Turkowski @ Apple Computer, Inc., Cupertino, CA
UUCP: {sun,nsc}!apple!turk
CSNET: turk@Apple.CSNET
ARPA: turk%Apple@csnet-relay.ARPA

mlandau@Diamond.BBN.COM (Matt Landau) (11/27/86)

In newsgroup comp.lang.c (article <332@apple.UUCP>), turk@apple.UUCP 
(Ken "Turk" Turkowski) writes:
>
>There have been numerous responses to get the declarations consistent, so I
>won't belabor them here.
>
>However, I would like to point out the use of a function that can speed up the
>program considerably when you are only allocating temporary variables.  The
>function is alloca(), and allocates memory from the stack, rather than from
>the heap.  The result is that allocation is simpler, and vanishes automatically
>when you exit the routine.

Well, there are going to be a lot of people pointing this out, but I
thought I'd be the first :-)  Alloca is nonstandard, nonportable, and 
doesn't exist on a lot of machines.  In fact, the last time this subject
came up was when a lot of people were having trouble porting Gnu Emacs
bacause it used alloca().  At the time, I think the conclusion was that
there exist machine architectures for which it is practically impossible
to even implement it.

The bottom line: Don't use alloca if you expect your code to port.
-- 
 Matt Landau      	 		BBN Laboratories, Inc.
    mlandau@diamond.bbn.com		10 Moulton Street, Cambridge MA 02238
 ...seismo!diamond.bbn.com!mlandau      (617) 497-2429