[comp.lang.c] More 2D array woes...

eychaner@suncub.bbso.caltech.edu (Amateurgrammer) (03/04/91)

Here we go again, warm up the flame guns...

Ok, suppose I have an array like
    char strings[NUMBER][SIZE];
How do I add more strings to this array, i.e. make it larger, portably and
easily.  I can't realloc it, since it's not a pointer!  Argh!  Is there some
sneaky way to declare it so that I can do what I want, or should I just use
    char *strings;
and a lot of pointer arithmetic?  How about
    char **strings;
    strings = (char **) calloc (NUMBER, sizeof (char *));
    strings[0] = (char *) malloc (SIZE);
    strings[1] = (char *) malloc (SIZE);
    ...
(I don't care if the 2d array is contiguous or not...)
Then strings is a pointer and I can realloc it, allowing me to add more
strings!  And can I even access them as
    (strings [string_num]) [string_pos] = 'x';
which becomes
    *(*(strings + string_num) + string_pos) = 'x';
or does it?  I'm not sure....
:-)
Glenn Eychaner - Big Bear Solar Observatory - eychaner@suncub.bbso.caltech.edu
"You Have the Right to Remain DEAD."
					-The Simpsons

dave@cs.arizona.edu (Dave P. Schaumann) (03/04/91)

In article <1991Mar3.235114.12154@nntp-server.caltech.edu> eychaner@suncub.bbso.caltech.edu writes:
>Here we go again, warm up the flame guns...
>
>Ok, suppose I have an array like
>    char strings[NUMBER][SIZE];
>How do I add more strings to this array, i.e. make it larger, portably and
>easily.  I can't realloc it, since it's not a pointer!  Argh!

It's beginning to sound like what you really want is C++.  In C++, you can
simulate arrays cleanly using pointers, and thus you can use realloc to
increase (or decrease) the size of your array dynamically.  You could even
program it so that accessing an element beyond the end of your array
automagically made it bigger.

C is good for writing quick, reasonably simple (at least as far as data
structure manipulation goes) programs.  When you find you need some
heavy-duty data structures, like dynamically sized arrays, or associative
arrays, you should seriously consider moving to C++.  The learning curve
is kind of steep (even for C-literates), but ultimately a useful tool to
be able to use.


-- 
		Dave Schaumann		dave@cs.arizona.edu
'Dog Gang'!  Where do they get off calling us the 'Dog Gang'?  I'm beginning to
think the party's over.  I'm beginning to think maybe we don't need a dog.  Or
maybe we need a *new* dog.  Or maybe we need a *cat*! - Amazing Stories

eychaner@suncub.bbso.caltech.edu (Amateurgrammer) (03/04/91)

dave@cs.arizona.edu (Dave P. Schaumann) writes:
>eychaner@suncub.bbso.caltech.edu writes:
>>Here we go again, warm up the flame guns...
>>
>>Ok, suppose I have an array like
>>    char strings[NUMBER][SIZE];
>>How do I add more strings to this array, i.e. make it larger, portably and
>>easily.  I can't realloc it, since it's not a pointer!  Argh!
>
>It's beginning to sound like what you really want is C++.  In C++, you can
>simulate arrays cleanly using pointers, and thus you can use realloc to
>increase (or decrease) the size of your array dynamically.  You could even
>program it so that accessing an element beyond the end of your array
>automagically made it bigger.

Well, actually, Chris Torek (torek@ee.lbl.gov) pointed out that the "cheap
and dirty way" (my phrase, not his) of doing this is to declare
      char (*dynamic)[N];
      dynamic = (char (*)[N]) malloc (M * N);
where N is the number of items in each row of the array, and M is the
number of rows.  This array can then be accessed by
      dynamic[x][y] = SOME_CHAR;
and reallocated by
      dynamic = realloc (dynamic, NEWSIZE * N);
so you CAN do it in C.  It's just a little tricky.  Ok, a LOT tricky.

>C is good for writing quick, reasonably simple (at least as far as data
>structure manipulation goes) programs.  When you find you need some
>heavy-duty data structures, like dynamically sized arrays, or associative
>arrays, you should seriously consider moving to C++.  The learning curve
>is kind of steep (even for C-literates), but ultimately a useful tool to
>be able to use.

Yeah.  So point out some C++ compilers for VMS that are reasonably priced,
and my boss will be more than happy to turn down my request for one.  No
smiley here, it's true.  I'm stuck with C, and that's how it is.  Unless I
want to use FORTRAN.  Ugh.
:-)
Glenn Eychaner - Big Bear Solar Observatory - eychaner@suncub.bbso.caltech.edu
"You Have the Right to Remain DEAD."
					-The Simpsons

eychaner@suncub.bbso.caltech.edu (Amateurgrammer) (03/04/91)

A followup to my followup...

eychaner@suncub.bbso.caltech.edu (Amateurgrammer) writes:
>>eychaner@suncub.bbso.caltech.edu writes:
>>>Here we go again, warm up the flame guns...
>>>
>>>Ok, suppose I have an array like
>>>    char strings[NUMBER][SIZE];
>>>How do I add more strings to this array, i.e. make it larger, portably and
>>>easily.  I can't realloc it, since it's not a pointer!  Argh!

Some poeple have complained that this is in the FAQ; well, I did read the
FAQ beforehand and the solutions it gives either result in a non-contiguous
array or make it VERY DIFFICULT to make the array larger.  The following
solution is MUCH better (though a little more opaque) than the ones in the
FAQ, and IMHO should be included there.

>Well, actually, Chris Torek (torek@ee.lbl.gov) pointed out that the "cheap
>and dirty way" (my phrase, not his) of doing this is to declare
>
>      char (*dynamic)[N];
>      dynamic = (char (*)[N]) malloc (M * N);
>
>where N is the number of items in each row of the array, and M is the
>number of rows.  This array can then be accessed by
>
>      dynamic [x][y] = SOME_CHAR;
>
>and reallocated by
>
>      dynamic = realloc (dynamic, NEWSIZE * N);
>
>so you CAN do it in C.  It's just a little tricky.  Ok, a LOT tricky.

Also, I would like to point out that to call realloc (to add a new row to 
the array) with a function could be (I HOPE I got this right, PLEASE):

      void increase_array (char (**array)[N], int *num_of_elements)
      {
      *array = (char (*)[N]) realloc (*array, ++(*num_of_elements) * N);
      }

This is called as:

      char (*dynamic)[N]; 
      int num_elem;
      increase_array (&dynamic, &num_elem);

If your compiler lets you call realloc() with NULL, set dynamic = NULL and
num_elem to 0 to add the FIRST element.
This is VERY powerful, and is MUCH better than the FAQ answer.  It is also
EXACTLY what I wanted.  So the FAQ is not the be-all and end-all of C.
Neither is C++ (which some people suggested).
:-)
Glenn Eychaner - Big Bear Solar Observatory - eychaner@suncub.bbso.caltech.edu
"You Have the Right to Remain DEAD."
					-The Simpsons

scs@adam.mit.edu (Steve Summit) (03/05/91)

In article <1991Mar4.064805.22220@nntp-server.caltech.edu> eychaner@suncub.bbso.caltech.edu writes:
>Some poeple have complained that this is in the FAQ; well, I did read the
>FAQ beforehand and the solutions it gives either result in a non-contiguous
>array or make it VERY DIFFICULT to make the array larger.  The following
>solution is MUCH better (though a little more opaque) than the ones in the
>FAQ, and IMHO should be included there.
[detailed solution omitted]
>>so you CAN do it in C.  It's just a little tricky.  Ok, a LOT tricky.
>Also, I would like to point out that to call realloc (to add a new row to 
>the array) with a function could be (I HOPE I got this right, PLEASE):
>      *array = (char (*)[N]) realloc (*array, ++(*num_of_elements) * N);

You also need a (char *) or (void *) cast before the *array
argument to realloc.  (Strictly speaking, the second argument
needs to be a size_t, either by declaring *num_of_elements or N that
way, or by using another cast.)

>This is VERY powerful, and is MUCH better than the FAQ answer.  It is also
>EXACTLY what I wanted.  So the FAQ is not the be-all and end-all of C.

My humble apologies.  I hope the FAQ list was not misrepresented
to you.  Note, by the way, that it does tend to shy rather
deliberately away from tricky and/or opaque solutions.

As it happens, my working copy of the FAQ list has for some time
contained a note to myself that something like the proposed
technique could be used ("with vicious enough casts").  The
technique is not entirely unknown to me; omitting to mention it
was a deliberate choice, based on the observations that:

     1.	pointers to arrays can be confusing, and in fact other
	parts of the list recommend avoiding them, and

     2.	the suggested technique only works if one dimension -- and
	specifically, the "length" of one "row," or the "width"
	of the array -- remains constant, while only the overall
	"length" (number of "rows") varies.

I am not at all sure that an FAQ list answer based on the
declaration

	char (*dynamic)[N];

would not bring up more questions than it answered.

I've never felt that the need for a dynamically allocated
two-dimensional array with one dimension constant led to that
frequent a question, and I also don't think that reallocation of
a "dope vector" array (which lets you reallocate along either
dimension) is terribly difficult.  (To be sure, the FAQ list does
not present code for doing so.)

However, if dynamically allocating a pointer to a constant-width
array is in fact considered a mainstream technique, I can
certainly add it to the list.  (Send your suggestions by mail,
please; there's no need to discuss this on the net.)

                                            Steve Summit
                                            scs@adam.mit.edu

P.S. Here's how I reallocate "dope vector" arrays.  It's a little
verbose, but hardly difficult or obscure.

	int **array = NULL;
	int xdim = 0;
	int ydim = 0;

	/* now reallocate to new dimensions newxdim, newydim */

	for(i = newydim; i < ydim; i++)		/* only if newydim < ydim */
		free((char *)array[i]);

	array = (int **)realloc((char *)array, newydim * sizeof(int *));

	for(i = ydim; i < newydim; i++)		/* only if newydim > ydim */
		array[i] = NULL;

	for(i = 0; i < newydim; i++)
		array[i] = (int *)
			realloc((char *)array[i], newxdim * sizeof(int));

	xdim = newxdim;
	ydim = newydim;

Note that, as written, this does depend on a "new" realloc,
i.e. one that can handle null pointers.