Allocating spaces for char type 
Author Message
 Allocating spaces for char type

I know that a statement like:

        char someString[80];

would allocate 80 bytes of contiguous block of memory to hold
characters .....

BUT..... what if someString is more then 80 bytes when entered by the
the user?  I don't want to write to other parts in memory, is there a
way of not knowing, then once I do know, I can allocate enough memory
to hold the string?

Thanks....
--



Sat, 18 Jan 2003 03:00:00 GMT  
 Allocating spaces for char type

Quote:

> I know that a statement like:

>         char someString[80];

> would allocate 80 bytes of contiguous block of memory to hold
> characters .....

> BUT..... what if someString is more then 80 bytes when entered by the
> the user?  I don't want to write to other parts in memory, is there a
> way of not knowing, then once I do know, I can allocate enough memory
> to hold the string?

You can use fgets(someString, sizeof someString, in_fp) multiple times
until you get the newline character indicating the end of the line.

A simple line-numbering program might go like this:

void number(FILE* in_fp, FILE* out_fp)
{
        char buf[80];
        int lines = 0;
        int eol = 1;            /* end-of-line flag */

        while(fgets(buf, sizeof buf, in_fp)) {
                /* breaks on EOF or error */

                if(eol)                 /* start of line */
                        fprintf(out_fp, "%5d: ", ++lines);
                fputs(buf, out_fp);
                eol = (strrchr(buf, '\n') != NULL);
        }

Quote:
}

If you should gather the whole line into a buffer, you can declare
another variable - say 'wholeString' - to be a char* (initially NULL),
realloc() it each time you get a chunk with fgets(), and append the
chunk to wholeString using strcat().

--
Kim Sung-bom
--



Sun, 19 Jan 2003 03:00:00 GMT  
 Allocating spaces for char type

Quote:
>I know that a statement like:

>    char someString[80];

>would allocate 80 bytes of contiguous block of memory to hold
>characters .....

>BUT..... what if someString is more then 80 bytes when entered by the
>the user?  I don't want to write to other parts in memory, is there a
>way of not knowing, then once I do know, I can allocate enough memory
>to hold the string?

>Thanks....

Some input functions allow you to specify a maximum length( e.g.,
fgets).  Others do not (e.g., scanf).  See the FAQ
(www.eskimo.com/~scs/C-faq/top.html) for a discussion of this problem
and its solutions.

<<Remove the del for email>>
--



Sun, 19 Jan 2003 03:00:00 GMT  
 Allocating spaces for char type

Quote:

>    char someString[80];
> BUT..... what if someString is more then 80 bytes when entered by the
> the user?  

Depends on how you read the input string. If you use gets(), hell
breaks loose. Using fgets(), you can limit the input string length, so
the only bad thing to happen will be that you don't read all of the
input in that line (yet).

Quote:
> I don't want to write to other parts in memory, is there a
> way of not knowing, then once I do know, I can allocate enough memory
> to hold the string?

To be completely general, you have to set up some 'growable'
datastructure, like a realloc()ed array, or a linked list of arrays,
and fill it, repeatedly reading, say, 80 bytes maximum, until line end
is reached. Then you can collect all the 80-byte fragments and set up
a single, looong string.
--

Even if all the snow were burnt, ashes would remain.
--



Sun, 19 Jan 2003 03:00:00 GMT  
 Allocating spaces for char type

Quote:

> I know that a statement like:

>    char someString[80];

> would allocate 80 bytes of contiguous block of memory to hold
> characters .....

> BUT..... what if someString is more then 80 bytes when entered by the
> the user?  I don't want to write to other parts in memory, is there a
> way of not knowing, then once I do know, I can allocate enough memory
> to hold the string?

You can use malloc() if you know how long the string is going to be
before you need to allocate the memory; if you need to grow the string
as you run, try realloc(). For example:

char buffer[BUFFERSIZE];
char *somestring, *tstring;
size_t somestringsize;

if (!(somestring=calloc(1,1)) { Error; can't allocate even one byte. }
somestringsize=1;
while (fgets(buffer, BUFFERSIZE, stdin)) {
  if (!(tstring=realloc(somestring, somestringsize+strlen(buffer))))
    break; /* No more memory; use what we could read. */
  somestring=tstring;
  strcat(somestring, buffer);
  somestringsize+=strlen(buffer);
  if (somestring[somestringsize-1]=='\n') { /* End of line reached. */
    somestring[somestringsize-1]='\0';
    break;
  }

Quote:
}

Richard
--



Sun, 19 Jan 2003 03:00:00 GMT  
 Allocating spaces for char type

Quote:

> I know that a statement like:

>    char someString[80];

> would allocate 80 bytes of contiguous block of memory to hold
> characters .....

> BUT..... what if someString is more then 80 bytes when entered by the
> the user?  I don't want to write to other parts in memory, is there a
> way of not knowing, then once I do know, I can allocate enough memory
> to hold the string?

It's a good point to think about.  Writing to other parts of memory is
a typical technique used by intruders to crash or gain control of a
computer.  Search the web for "buffer overflow" to see all the {*filter*}
things that can happen.

The usual technique is to allocate a typical size and read just that
much.  If you haven't reached the end of the data (e.g. newline),
reallocate a larger size and go back for more data.  Keep going until
you have all the data.

For this type of code, use realloc, which takes a size variable and
can iterate, rather than allocating on the stack, which is one time
and fixed size.

Variations:

You can start with size = 0 and someString = NULL the first time
through, and the realloc becomes a malloc.

You can keep the pointer until the end of the program if you're
reading more than one data record.

Typical realloc algorithms include adding a constant size or doubling
the size in each loop.

You might want to program a maximum size before you decide the data is
bad, or just let the realloc() go until it runs out of memory.  Watch
for size_t overflow.

In some programs, it might be possible to process fixed data chunks
rather than getting the entire user input into a string.  The latter
is typically easier.

Legend?

I've read that the UNIX (grep, ls, find, ...) utilities are tested
by feeding them user input with 100's of megabytes before a newline,
and weird control characters, to insure that they don't overflow.

--

--



Sun, 19 Jan 2003 03:00:00 GMT  
 Allocating spaces for char type

Quote:

> I know that a statement like:

>    char someString[80];

> would allocate 80 bytes of contiguous block of memory to hold
> characters .....

> BUT..... what if someString is more then 80 bytes when entered by the
> the user?  I don't want to write to other parts in memory, is there a
> way of not knowing, then once I do know, I can allocate enough memory
> to hold the string?

No, not usually.  The normal thing to do is allocate an initial buffer,
read enough of the string as will fit.  Then you need to decide whether
you got the whole thing or just the first bit.  In the former case,
you're done; in the latter, you grow the buffer, read some more, and
repeat.  Alternatively, you could just read as much as will fit, and if
there's meant to be more, you can either throw it away silently or emit
an error.

Some interface designers write functions which will let you do a `dry
run' if you give them magical arguments: they don't produce any output
but will tell you how big the output would have been if they'd made
any.  Then you allocate enough and do whatever it was again for real.
This tends to involve less fiddling with memory management, at the
expense of doing things twice.

-- [mdw]
--



Sun, 19 Jan 2003 03:00:00 GMT  
 Allocating spaces for char type
# I know that a statement like:

#       char someString[80];

# would allocate 80 bytes of contiguous block of memory to hold
# characters .....

# BUT..... what if someString is more then 80 bytes when entered by the
# the user?  I don't want to write to other parts in memory, is there a
# way of not knowing, then once I do know, I can allocate enough memory
# to hold the string?

You need to realloc as you read along. Here's what I'm using for quite
some time now: char *fgetline (FILE *stream) reads an arbitrary long
line, has almost perfect error (apart from the ungetc, left as an
excercise) and seems to do its job well for years. Do whatever you
like with it, but don't blame me for anything. :-)

/*
 * $Id: fgetline.c,v 1.1 1996/08/13 18:10:46 root Exp schweikh $
 */

#include <stdlib.h>         /* malloc */
#include <stdio.h>          /* fgetc */

/*
 * fgetline:
 *                 reads a stream up to the next \n and
 *                 returns the pointer to that line. The \n is replaced
 *                 by a \0. Returns NULL on EOF or error. To distinguish
 *                 between EOF and error use feof(fp) which is nonzero
 *                 on EOF. Memory is allocated using malloc(). The caller
 *                 is responsible for freeing.
 */

/*
 * M_START is the initial size of the allocated memory. It must be
 * even and is doubled every time the line fills up the memory.
 */
#define M_START 16

#if M_START % 2 == 1
#error M_START must be even
#endif

char *
fgetline (FILE *fp)
{
        char *mem, *new_mem, *write_to; /* mem is const, write_to changes */
        int input;
        size_t mem_size = M_START;

        input = fgetc (fp);
        if (input == EOF) {
                return NULL; /* feof(fp) now is nonzero */
        }
        (void)ungetc (input, fp);
        /* okay, there is at least one character to read */
        mem = malloc (mem_size);
        if (mem == NULL) {
                return NULL;
        }
        while ((new_mem = realloc (mem, mem_size)) != NULL) {
                mem = new_mem;
                /*
                 * On the first iteration, make write_to = mem, otherwise
                 * let write_to point to the newly allocated memory.
                 */
                write_to = (mem_size == M_START ? mem : mem + mem_size/2);
                while (write_to != mem + mem_size) { /* while we have space to write */
                        input = fgetc (fp);
                        if (input == '\n' || input == EOF) {
                                *write_to = '\0';
                                return mem;
                        }
                        *write_to++ = (char) input;
                }
                /*
                 * We have written mem+mem_size-write_to chars into mem[], it's full.
                 * But there might be more to read or an EOF coming. Even if EOF is
                 * next, we have to realloc to have space for the terminating \0.
                 */
                mem_size *= 2;
        }       /* while realloc != NULL */

        /* Out of memory. Free what we allocated so far to avoid memory leak. */

        free (mem);
        return NULL;

Quote:
}

Regards,

        Jens
--
Jens Schweikhardt  http://www.schweikhardt.net/
SIGSIG -- signature too long (core dumped)
--



Sun, 19 Jan 2003 03:00:00 GMT  
 Allocating spaces for char type
Do you really not know the maximum size?

An option would be to switch language. You might find Perl would be as
good.

Paul

Quote:

> I know that a statement like:

>         char someString[80];

> would allocate 80 bytes of contiguous block of memory to hold
> characters .....

> BUT..... what if someString is more then 80 bytes when entered by the
> the user?  I don't want to write to other parts in memory, is there a
> way of not knowing, then once I do know, I can allocate enough memory
> to hold the string?

> Thanks....
> --


--



Sat, 25 Jan 2003 03:00:00 GMT  
 Allocating spaces for char type

Quote:

> Do you really not know the maximum size?

> An option would be to switch language. You might find Perl would be as
> good.

An alternative, if you want to stick with C, might be to read a
character at a time into a linked list of buffers:

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

#define ERROR(s)        do {                    \
    fprintf(stderr, "Error in %s (%s): %s\n",   \
            __FUNCTION__, s, strerror(errno));  \
    exit(EXIT_FAILURE);                         \

Quote:
} while (0)

struct bufnode {
  char                  *buf;
  char                  *cp;
  size_t                capacity;
  struct bufnode        *next;

Quote:
};

void bufnode_init(struct bufnode *bn, size_t capacity)
{
    bn->next             = NULL;

    if (! (bn->buf = malloc(sizeof(char) * capacity)) )
      ERROR("malloc bufnode buffer");
    bn->capacity         = capacity;

Quote:
}

int bufnode_getline(struct bufnode *bn, FILE *f)
{
    int                 ch;
    int                 i;
    int                 end      = bn->capacity;
    char                *buf;

    for (;;) {
      buf        = bn->buf;
      for (i = 0; i < end; ++i) {
        ch       = getc(f);
        if ( (ch == '\n' || ch == EOF) ) {
          buf[i]         = '\n';
          return 0;
        }
        buf[i]   = ch;
      }
      if (i == end) {
        struct bufnode  *newnode;
        if (! (newnode = malloc(sizeof(struct bufnode))) )
          ERROR("malloc new bufnode");
        bufnode_init(newnode, bn->capacity);
        bn->next         = newnode;
        i        = 0;
        bn       = newnode;
      }
    }
    return -1;

Quote:
}

void bufnode_print(struct bufnode *bn, FILE *f)
{
    int         i;
    int         end      = bn->capacity;
    char        *buf;

    do {
      buf        = bn->buf;
      for (i = 0; i < end; ++i)
        fputc(buf[i], f);
    } while ( (bn = bn->next) );

Quote:
}

void bufnode_free(struct bufnode *bn)
{
    if (! bn)
      return;
    free(bn->buf);
    bufnode_free(bn->next);
    free(bn);
Quote:
}

void bufnode_reset(struct bufnode *bn)
{
    int         i;
    int         end      = bn->capacity;
    char        *buf     = bn->buf;

    if (! bn)
      return;
    bufnode_free(bn->next);
    bn->next     = NULL;

    for (i = 0; i < end; ++i)
      buf[i]     = '\0';

Quote:
}

int main(void)
{
    struct bufnode      bn;
    /* set this to a reasonable length or suffer performance hit
     * from excessive memory management. */
    const int           default_capacity         = 80;

    bufnode_init(&bn, default_capacity);
    for (;;) {
      if (bufnode_getline(&bn, stdin) < 0)
        ERROR("bufnode_getline");
      bufnode_print(&bn, stdout);
      bufnode_reset(&bn);
    }

    return 0;

Quote:
}

--
--Ed Cashin                     PGP public key:

    Note: If you want me to send you email, don't munge your address.
--



Sun, 26 Jan 2003 03:00:00 GMT  
 
 [ 10 post ] 

 Relevant Pages 

1. Reg.allocating memory for double char pointer(char ** buf)

2. difference in space reserved between a char use[] and char *use

3. allocating string space for long decimal

4. Allocating space to arrays:

5. Allocating "Space"

6. Using free() in the middle of dynamically allocated space

7. allocating space for a struct including struct

8. do I need to allocate space twice?

9. determining amoutn of allocated space

10. Need help defining heap/stack space allocated by program

11. delete memory space that hasn't been allocated

12. allocate space for an array

 

 
Powered by phpBB® Forum Software