[comp.lang.c] Allocating two dimensional arrays

n62@nikhefh.hep.nl (Klamer Schutte) (01/20/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.
 
and as a proposed solution:

>#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)])

Why not simple something like this:

struct matrix
{	float	data[n][m];
}	*foo;

...

foo = ( struct matrix * )malloc( sizeof( struct matrix ));

and accessing the data like:

foo->data[n][m];

In this way the source code will reflect ecxactly how the data is accessed;
I think C programming should be done that way. 

chris@mimsy.UUCP (Chris Torek) (01/21/88)

[These attributions look vaguely suspicious, but are as they were
in the parent article (do I *really* need to put in such disclaimers?)]
>>Spencer@ogg.cgrg.ohio-state.edu (PROCEED) writes:
>>>... 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.)
>>#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)])

In article <419@nikhefh.hep.nl> n62@nikhefh.hep.nl (Klamer Schutte) writes:
>Why not simple something like this:
>
>struct matrix
>{	float	data[n][m];
>}	*foo;
>
>...
>
>foo = ( struct matrix * )malloc( sizeof( struct matrix ));
>
>and accessing the data like:
>
>foo->data[n][m];

Why not indeed.  Have you tried it?

  1	f()
  2	{
  3		int n, m;
  4		struct matrix {
  5			float data[n][m];
  6		} *foo;
  7	}

	xx.c, line 5: constant expected
	xx.c, line 5: constant expected

>In this way the source code will reflect exactly how the data is accessed;
>I think C programming should be done that way. 

As much as possible, certainly.  But arrays must have all but the
first dimension declared as a compile-time constant.  The various
previous solutions (which include vectors of vectors) will work.

Incidentally, one solution I did not see is this:

	typedef float data_t;	/* whatever we are storing in matrices */
		/* (please change `data' to reflect the actual stuff) */

	/*
	 * Create an N by N matrix of data type data_t.
	 * Return NULL if it cannot be made.
	 */
	data_t **
	create_matrix(n)
		int n;
	{
		register data_t *mem;
		register data_t **rows;
		register int i;

		mem = (data_t *)malloc(n * n * sizeof(*mem));
		if (mem == NULL)
			return (NULL);
		rows = (data_t **)malloc(n * sizeof(*rows));
		if (rows == NULL) {
			free((char *)mem);
			return (NULL);
		}
		for (i = 0; i < n; i++) {
			rows[i] = mem;
			mem += n;
		}
		return (rows);
	}

	/*
	 * Free such a matrix.  Note that we need not know N.
	 */
	void
	free_matrix(mat)
		data_t **mat;
	{

		free((char *)*mat);
		free((char *)mat);
	}

How it works, and how to modify it for M by N matrices, and for
matrices of higher dimensionality, is left as an exercise for the
reader.

=====
Exercises:
1.  How *does* it work?
2.  Modify it to create a four-dimensional matrix of size W by X by
    Y by Z.
3.  Modify it to produce upper or lower triangular matrices, without
    using any more calls to malloc, and without wasting space (no
    `mem' elements left over).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

ix426@sdcc6.ucsd.EDU (tom stockfish) (01/22/88)

In article <10278@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
X 
X [code defining create_matrix() which returns "data_t **", a "matrix" of
X  the sort that "argv" is, and free_matrix() ]
X 
X Exercises:
X 1.  How *does* it work?
X 2.  Modify it to create a four-dimensional matrix of size W by X by
X     Y by Z.
X 3.  Modify it to produce upper or lower triangular matrices, without
X     using any more calls to malloc, and without wasting space (no
X     `mem' elements left over).


4.  Modify it so that it uses only *one* malloc() call, the pointer
    it returns can be handed *directly* to free() (no "free_matrix()"
    routine needed), and a "true" matrix (or rather, pointer to
    the first element of it) can be easily obtained so it can be
    sent to a fortran routine (assuming the fortran routine can
    operate on the transpose).  Oh yes, it must be portable, too.
    (Solution to follow at later date).


5.  Prove that #4 cannot be done portably if the type of the matrix
    is not specified at compile time.
-- 

||  Tom Stockfisch, UCSD Chemistry   tps@chem.ucsd.edu

blarson@skat.usc.edu (Bob Larson) (01/22/88)

In article <3590@sdcc6.ucsd.EDU> ix426@sdcc6.ucsd.edu.UUCP (tom stockfish) writes:
>4. ... so it can be sent to a fortran routine ...

>5.  Prove that #4 cannot be done portably if the type of the matrix
>    is not specified at compile time.

How many proofs do you want?

A.  I don't have fortran on my  qt+, so calling fortran is unportable.

(dito A for upteen machines where fortran is either unavailable or
prohibitavly expensive.)

B.  Fortran calling in Prime C is completly different that that in
4.2 BSD C.

(Dito B for upteen trillion combiniations of operating systems and
compilers.)

Why would I want to mess things up with a matrix in my proof?

[Repeat after me: all the world is not a vax 780 running 4.1c BSD with
no modifacations.]
--
Bob Larson	Arpa: Blarson@Ecla.Usc.Edu	blarson@skat.usc.edu
Uucp: {sdcrdcf,cit-vax}!oberon!skat!blarson
Prime mailing list:	info-prime-request%fns1@ecla.usc.edu
			oberon!fns1!info-prime-request