[comp.lang.c] Allocating a two-dimensional array

spencer@ogg.cgrg.ohio-state.edu (PROCEED) (01/18/88)

Maybe this can't be done.  Maybe I'm not thinking about it the right way.
But I can't figure out how to dynamically allocate a two-dimensional 
array of floats.  (I have to have an N by N matrix of floats, but don't
know N beforehand.)  Can anyone help me on this one?  Thanks.


-- 
                       "I'm growing older but not up..." 
Stephen Spencer, Graduate Student	|
The Computer Graphics Research Group	| {cbosgd,ucbvax}!osu-cis!ogg!spencer
The Ohio State University		| spencer@ogg.cgrg.ohio-state.edu
1501 Neil Avenue, Columbus OH 43210	|

kurt@hi.unm.edu (Kurt Zeilenga) (01/18/88)

Spencer@ogg.cgrg.ohio-state.edu (PROCEED) writes:
>Maybe this can't be done.  Maybe I'm not thinking about it the right way.
>But I can't figure out how to dynamically allocate a two-dimensional 
>array of floats.  (I have to have an N by N matrix of floats, but don't
>know N beforehand.)  Can anyone help me on this one?  Thanks.

You can not allocate multi-dimensional arrays dynamically.  However,
you can do is something like:

#define malloc_matrix(p,n,m,t) ((p) = ((t) *) malloc((n)*(m)*sizeof(t)))
#define matrix(p,n,m,x,y)      ((p)[(n)*(x)+(y)])

where
	t = element type
	p = pointer to type
	n,m = dimensions
	x,y = indexes

malloc_matrix() allocates the space and matrix() is used to pick the
element.

There are many similiar macros that will do the same thing, these ones
may be an overkill.
-- 
	Kurt (zeilenga@hc.dspo.gov)

g-rh@cca.CCA.COM (Richard Harter) (01/18/88)

In article <22941@hi.unm.edu> kurt@hi.unm.edu (Kurt Zeilenga) writes:
>Spencer@ogg.cgrg.ohio-state.edu (PROCEED) writes:
>>Maybe this can't be done.  Maybe I'm not thinking about it the right way.
>>But I can't figure out how to dynamically allocate a two-dimensional 
>>array of floats.  (I have to have an N by N matrix of floats, but don't
>>know N beforehand.)  Can anyone help me on this one?  Thanks.
>
>You can not allocate multi-dimensional arrays dynamically.  However,
>you can do is something like:

	.... macros deleted ....

I will defer the question of whether Kurt is correct or not to people
more knowledgable in the arcana of C than I am.  I don't know whether
you can cast something as being a pointer to an N by N array where N
is a variable.  However a rather simple approach is to use an array of
pointers, e.g.

	float **array;
	char *malloc();	/* No one forgets this declaration, right? */
	int i;
	.....
	array = (float **)malloc(N*sizeof(float *));
	for (i=0;i<N;i++) array[i] = (float *)malloc(N*sizeof*float));

You can then reference array[i][j] just as though it were a two
dimensional array.  For most applications this is satisfactory and,
in fact, likely to execute faster.

This technique will not work if want to treat the array both as an
N by N two dimensional array and as a N**2 length one dimensional array.
(I.e. you want to exploit contiguity of storage.)  No problem.

	float **arr2, *arr1, *tmp;
	char *malloc();
	int i;
	.....
	arr1 = (float *)malloc(N*N*sizeof(float));
	arr2 = (float **)malloc(N*sizeof(float *));
	tmp = arr1;
	for (i=0;i<N;i++) {
	  arr2[i] = tmp;
	  tmp += N;
	  }

All very simple minded, I'm sure, but it does the trick.  
-- 

In the fields of Hell where the grass grows high
Are the graves of dreams allowed to die.
	Richard Harter, SMDS  Inc.

gwyn@brl-smoke.ARPA (Doug Gwyn ) (01/18/88)

In article <1050@ogg.cgrg.ohio-state.edu> spencer@ogg.cgrg.ohio-state.edu (PROCEED) writes:
>But I can't figure out how to dynamically allocate a two-dimensional 
>array of floats.  (I have to have an N by N matrix of floats, but don't
>know N beforehand.)  Can anyone help me on this one?  Thanks.

There are two parts to this.  The actual memory allocation is the easy
part.  The hard part is deciding how your code is to access a matrix
element.  Since C does not support multi-dimensional arrays that don't
have a compile-time constant for every dimension except the first, you
cannot directly use C array subscript notation to access the data in a
single "rectangular" allocated matrix.  There are two solutions, one of
them to allocate a one-dimensional array and perform the indexing
arithmetic explicitly, using the matrix width, and the other solution
is to allocate an extra array of "row vector pointers" then use double
indexing.  The first method is simpler but usually slower (because
index arithmetic is slower than indirection).

	/* METHOD 1: */
	float *matrix = (float *)malloc( M * N * sizeof(float) );
#define	Matrix(i,j) matrix[(i)*N + (j)];	/* for convenience */
	/* ... */
	matrix_ij = Matrix(i,j);

	/* METHOD 2: */
	float *data = (float *)malloc( M * N * sizeof(float) );
	float **matrix = (float **)malloc( M * sizeof(float *) );
	for ( i = 0; i < M; ++i )
		matrix[i] = &data[i*N];
	/* ... */
	matrix_ij = matrix[i][j];

pmd@cbdkc1.ATT.COM (Paul Dubuc) (01/19/88)

In article <1050@ogg.cgrg.ohio-state.edu> spencer@ogg.cgrg.ohio-state.edu (PROCEED) writes:
}Maybe this can't be done.  Maybe I'm not thinking about it the right way.
}But I can't figure out how to dynamically allocate a two-dimensional 
}array of floats.  (I have to have an N by N matrix of floats, but don't
}know N beforehand.)  Can anyone help me on this one?  Thanks.

First allocate an array of N pointers to N arrays of floats, then
allocate N arrays of N floats and assign the resulting pointers to
the elements of the first array.

float **fa;

fa = (float **)calloc(N, sizeof(float *));
for(i=0;i<N;++i) fa[i] = (float *)calloc(N, sizeof(float));

Now "fa" is your matrix.  When you want to free the space 

for(i=0;i<N;++i) free((char *)fa[i]);
free((char *)fa);

-- 

Paul Dubuc	{ihnp4,cbosgd}!cbdkc1!pmd

daniel@sco.COM (daniel edelson) (02/02/88)

	In article <22941@hi.unm.edu> kurt@hi.unm.edu (Kurt Zeilenga) writes:
	>Spencer@ogg.cgrg.ohio-state.edu (PROCEED) writes:
	>>But I can't figure out how to dynamically allocate a two-dimensional 
	>>array of floats.  (I have to have an N by N matrix of floats...)
	>
	>You can not allocate multi-dimensional arrays dynamically.  However,
This statement is wrong. Your example is itself allocating a
multidimensional array dynamically. Perhaps what you intend to say is
that you cannot allocate a multidimensional array in one statement. That
is more nearly accurate.
	>you can do is something like:
	>
	>#define malloc_matrix(p,n,m,t) ((p)=((t)*)malloc((n)*(m)*sizeof(t)))
	>#define matrix(p,n,m,x,y)      ((p)[(n)*(x)+(y)])
	>
	>where
	>	t = element type
	>	p = pointer to type
	>	n,m = dimensions
	>	x,y = indexes
	>
	>malloc_matrix() allocates the space and matrix() is used to pick the
	>element.
	>-- 
	>	Kurt (zeilenga@hc.dspo.gov)

You cannot allocate an array of an anonymous aggregate type. However 
you can allocate an array of a named aggregate type. If your named type
is a vector type, then allocating an array of them yields a
multidimensional array. 

The other way of allocating multidimensional structures in C, since the
language lacks parameterized multidimensional arrays, is to repeatedly
allocate vectors for each dimension of the array. Something like this.

/* Allocate an array of floats */
typedef	float	*floatp;	/* A vector type */
typedef floatp	*array;		/* An array type */

array
allocate(r,c)
unsigned r,c;
{
	int i;
	floatp *A;
	char	*calloc(unsigned, unsigned);

	A=(floatp*)calloc(r,sizeof(floatp));
	for (i=0; i<c; i++)
		A[i]=(float*)calloc(c,sizeof(float));
	return(A);
}

This scheme is disadvantageous in that it takes time proportional to
the number of rows to allocate the array. However, that is probably 
a trivial cost compared to operating on the array elements. Furthermore,
this scheme easily generalizes to arrays of arbitrary dimension. 
The logical and appropriate extension of this is to make an array
type a structure which contains its dimensions. This supports 
general, defensive and transparent programming.

This mechanism also allows A[i] to refer to the i'th row of the
array. When the array is allocated as a continuous block of memory,
A[i] refers to the i'th element. This, of course, stems from C's 
linear storage mapping. 

-- 
uucp:   {uunet|decvax!microsoft|ucbvax!ucscc|ihnp4|amd}!sco!daniel
ARPA:   daniel@sco.COM     Inter:  daniel@saturn.ucsc.edu--------------
pingpong: a dink to the right side with lots of top spin | Disclaimed |
fishing:  flies in morning and evening, day - spinners   | as usual   |