char **info; /*dynamic allocation*/ 
Author Message
 char **info; /*dynamic allocation*/

I've wrestling with this on and off (rm *.core is my friend). Is it possible
to dynamically allocate something like this.
msg[unknown_number][max_string_size];
I've been hacking away at it but always seem to wind up colouring outside
the lines.
For your amu{*filter*}t I present my current version of logic mangling. It takes
the  input just fine but crashes when I ask for it back.
TIA Greg Martin

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXSIZE 80

int main(void)
{
 int cnt, i;
 char **info;
 char someinfo[MAXSIZE];

 cnt = 0;
 if((info = malloc(MAXSIZE)) == NULL)
 {
  puts("malloc() failed");
  exit(EXIT_FAILURE);
 }

 while((fgets(someinfo, MAXSIZE, stdin)))
 {
  if((*someinfo == '\n')) break;

  memmove(info + (cnt * MAXSIZE), someinfo, strlen(someinfo)+1);
  info[(cnt * MAXSIZE) + strlen(someinfo)+1] = '\0';
  ++cnt;
  if((info = realloc(info, (MAXSIZE * cnt))) == NULL)
  {
    puts("realloc() failed");
    free(info);
    exit(EXIT_FAILURE);
  }

 }

 for (i = 0; i < cnt; ++i)
  puts(info[i * MAXSIZE]);

 free(info);
 return 0;

Quote:
}



Sun, 02 Dec 2001 03:00:00 GMT  
 char **info; /*dynamic allocation*/
Greg Martin schrieb:

Quote:

> I've wrestling with this on and off (rm *.core is my friend). Is it possible
> to dynamically allocate something like this.
> msg[unknown_number][max_string_size];

Hi Greg Martin,

The annswer is a definite almost :-) You can use "malloc()" to allocate
something that is very similar, but not identical to a 2D (or
multidimensional) array. The comp.lang.c FAQ list explains two different
ways to do this (including sample code). Please look up the answer to:
   6.16:   How can I dynamically allocate a multidimensional array?

[snipped source code]

Sorry, but your source code is pretty much on the wrong track. You should
better take a look at the sample code and start over.

The more popular solution for dynamically allocated arrays essentially
involves allocating an array of "char*" first (this is the outer or
leftmost dimension] and assigning the memory for one line of the 2D array
(the inner or rightmost dimension) to each of these pointers.

You can get the FAQ at http://www.eskimo.com/~scs/C-faq/top.html or
at ftp://rtfm.mit.edu/pub/usenet/comp.lang.c/C-FAQ-list and it gets
posted to this newsgroup and to news.answers regularly (at the
beginning of each month).

Stephan
(initiator of the campaign against grumpiness in c.l.c)



Mon, 03 Dec 2001 03:00:00 GMT  
 char **info; /*dynamic allocation*/

Quote:

> I've wrestling with this on and off (rm *.core is my friend). Is it possible
> to dynamically allocate something like this.
> msg[unknown_number][max_string_size];
> I've been hacking away at it but always seem to wind up colouring outside
> the lines.
> For your amu{*filter*}t I present my current version of logic mangling. It takes
> the  input just fine but crashes when I ask for it back.
> TIA Greg Martin

> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>

> #define MAXSIZE 80

> int main(void)
> {
>  int cnt, i;
>  char **info;
>  char someinfo[MAXSIZE];

>  cnt = 0;
>  if((info = malloc(MAXSIZE)) == NULL)
>  {
>   puts("malloc() failed");
>   exit(EXIT_FAILURE);
>  }

>  while((fgets(someinfo, MAXSIZE, stdin)))
>  {
>   if((*someinfo == '\n')) break;

>   memmove(info + (cnt * MAXSIZE), someinfo, strlen(someinfo)+1);
>   info[(cnt * MAXSIZE) + strlen(someinfo)+1] = '\0';
>   ++cnt;
>   if((info = realloc(info, (MAXSIZE * cnt))) == NULL)
>   {
>     puts("realloc() failed");
>     free(info);
>     exit(EXIT_FAILURE);
>   }

>  }

>  for (i = 0; i < cnt; ++i)
>   puts(info[i * MAXSIZE]);

>  free(info);
>  return 0;
> }

Have a look at this. We create a dynamic array of pointers to char
and initialize it to NULL.  Then read the next line from the input
stream (in) into buff.  Then we increase the size of the array by one,
allocate memory for the string and replace the NULL pointer with a
pointer to the new space and copy buff to it.  Then make the last
pointer NULL.  Keep it up until fgets() returns NULL (at EOF).

   char buff[1024];
   int i, line = 0;
   char **array = malloc(sizeof(char *));
   array[line] = NULL;

   while (fgets(buff, sizeof(buff), in) != NULL) {
      array = realloc(array, (line + 2) * sizeof(char *));
      array[line] = malloc(strlen(buff) + 1);
      strcpy(array[line], buff);
      array[++line] = NULL;
   }

Placing a NULL at the end of the array of pointers allows us to go
through the array without knowing how many elements there are.
Consider simply printing the strings:

   for (i = 0; array[i]; ++i)
      fputs(array[i], stdout);

Free the array like this:

   for (i = 0; array[i]; ++i)
      free(array[i]);
   free(array);

This is NOT a complete program.  I don't want to do it all for you. :)
You will also want to check the returns from malloc() and realloc(),
perhaps some kind of wrapper.
--

"Everything should be made as simple as possible, but not simpler."
                    --- Albert Einstein ---



Mon, 03 Dec 2001 03:00:00 GMT  
 char **info; /*dynamic allocation*/
Wed, 16 Jun 1999 17:08:41 -0700,
[snip]
Quote:
> #define MAXSIZE 80

> int main(void)
> {
>  int cnt, i;
>  char **info;
>  char someinfo[MAXSIZE];

>  cnt = 0;
>  if((info = malloc(MAXSIZE)) == NULL)

[snip reasonable error handling]

Quote:
>  while((fgets(someinfo, MAXSIZE, stdin)))
>  {
>   if((*someinfo == '\n')) break;

>   memmove(info + (cnt * MAXSIZE), someinfo, strlen(someinfo)+1);
>   info[(cnt * MAXSIZE) + strlen(someinfo)+1] = '\0';
>   ++cnt;
>   if((info = realloc(info, (MAXSIZE * cnt))) == NULL)
>   {
>     puts("realloc() failed");
>     free(info);
>     exit(EXIT_FAILURE);
>   }
>  }

>  for (i = 0; i < cnt; ++i)
>   puts(info[i * MAXSIZE]);

>  free(info);
>  return 0;
> }

1) Before the first fgets, you malloc for 1*MAXSIZE,
which "leaves room" for the line you then put there.  
But after the first line is there, you realloc to
1*MAXSIZE; then you put the second line outside the
allocated space and then realloc to 2*MAXSIZE; then
put the third line outside the allocated space, etc.  

2) Your memmove() copies the data read by fgets(),
plus the terminating null, and then the next statement
adds another null character.  This is unnecessary,
and if fgets() stored its maximum of MAXSIZE-1
characters before the null, your extra null is
written outside the allocated MAXSIZE chars.  
Dyn-alloc (heap) and auto (stack) objects cannot overlap,
so strcpy() accomplishes the same thing as your memmove()
and will be clearer to most C programmers, and
at least as efficient (probably more so).  

Or maybe you meant to use strlen()-1 to strip the '\n'
left by fgets() *unless* it encountered a long line
or a partial line at EOF (if implementation allows such)?  

3) realloc() may need to copy the affected data,
depending on the implementation and especially
if your program does anything much more complex
than this simplified example.  Copying an amount
that increases one line each time is quadratic;
if you run your program on large inputs (many lines)
it will get slower and sloooooowwwwerrrr.  

One solution is to allocate in a geometric (exponential)
rather than arithmetic (linear) progression, such as
10 lines to start and double each time you reach
the current limit.  Alternatives would be structures
that do not require copying, like a linked list or tree,
of lines or groups of lines or chars, or as Joe Wright
proposed, two-level pointers, although moving all the
pointers will also be quadratic but with smaller K.  

4) If realloc() fails and returns NULL, there's no point
in free()'ing that NULL.  What you should do is save
the prior pointer and free() that.  Although when you
exit, as you do here, *most* platforms/OS's will
deallocate all memory for you en masse.  Whether
it's wise and/or good style to rely on this
has been discussed at great length previously;
see deja or other archive.  

5) You can have the compiler do most of the scaling
for you by treating this as a 2-D array, or rather
pointers to elements of a 2-D array.  

6) If you keep/store the '\n' from fgets(), puts()
adds another one, creating double-spaced output.  

Putting all these together (and breaking up
the longer statements for posting):  

int main(void)
{
  typedef char Infoline [MAXSIZE];
  Infoline *info, *newinfo, someinfo;
  /* without typedef have to write:
    char (*info)[MAXSIZE] etc. */
  int alloc, cnt, i;

  info = malloc( (alloc = 10) * sizeof *info );
  if( info == NULL )
  /* puts() etc. as before */
  cnt = 0;

  while( fgets(someinfo, sizeof someinfo, stdin)
      && someinfo[0] != '\n' )
  {
    if( cnt == alloc )
    {
      newinfo = realloc(info, (alloc *= 2) * sizeof *info);
      if( newinfo == NULL )
      /* free(info) etc. as before */
      info = newinfo;
    }
    strcpy( info[cnt++], someinfo );
  }

  for( i = 0; i < cnt; ++i)
    fputs(info[i],stdout);
    /* or printf("%s",info[i]); */
  free(info);
  return 0;

Quote:
}

(CCed) david.thompson at but not for trintech.com


Mon, 03 Dec 2001 03:00:00 GMT  
 
 [ 4 post ] 

 Relevant Pages 

1. dynamic allocation

2. Multi-dimensional array using dynamic memory allocation

3. C Dynamic allocation of Pointers

4. Dynamic array allocation;

5. Need help with dynamic memory allocation (malloc) in C

6. Dynamic Allocation of Multi-Dimensional Array (Simple Question)

7. dynamic memory allocation

8. memory allocation / "dynamic arrays" / portability

9. Help Please!(linked lists/dynamic memory allocation etc.)

10. Dynamic Allocation

11. Dynamic allocation!

12. dynamic memory allocation

 

 
Powered by phpBB® Forum Software