c - dynamically allocating a string with unknown size -


i have names known number of names input 1 string each separated space, have dynamically allocate memory array of strings each string gets name,

    char** names;     char ch;     names = malloc(n*sizeof(char*); /*n defined*/      for(i=0; i<n; i++) { 

now have allocate each string without using defined number:

    i=0, j=0;     while ((ch=getchar) != '\n') {          while (ch != ' ') {               names[i][j++] = ch;          }          if (ch == ' ') {               names[i][j] = '\0';               i++}}     if (ch == '\n')          names[i][j] = '\0'; 

this classic question of how handle dynamic allocation , reallocation store unknown number of strings. (with twist separate each string individual tokens before saving array) worth understanding process in detail serve basis any other circumstance reading unknown number of values (whether structs, floats, characters, etc...).

there number of different types of data structures can employ, lists, trees, etc., basic approach creating array of pointer-to-pointer-to-type (with type being char in case) , allocating space for, filling data, , assigning starting address new block of memory each pointer data read. short-hand pointer-to-pointer-to-type double-pointer (e.g. char **array;, technically pointer-to-pointer-to-char or pointer-to-char* if like)

the general, , efficient, approach allocating memory unknown number of lines first allocate reasonably anticipated number of pointers (1 each anticipated token). more efficient calling realloc , reallocating entire collection every token add array. here, keep counter of number of tokens added array, , when reach original allocation limit, simmply reallocate twice number of pointers currenly have. note, free add incremental amount choose. can add fixed amount each time, or can use scaled multiple of original -- it's you. realloc twice current 1 of standard schemes.

what "a reasonably anticipated number of pointers?" it's no precise number. want take educated guess @ number of tokens roughtly expect , use initial number allocating pointers. wouldn't want allocate 10,000 pointers if expect 100. horribly wasteful. reallocation take care of shortfall, rough guess needed. if have no idea, allocate reasonable number, 64 or 128, etc.. can declare limit constant @ beginning of code, adjusted. e.g.:

#declare maxptr 128 

or accomplish same thing using anonymous enum

enum { maxptr = 128 }; 

when allocating pointers originally, , part of reallocation, can benefit setting each pointer null. accomplished original allocation. use calloc instead of malloc. on reallocation, requires set new pointers allocated null. benefit provides first null acts sentinel indicating point @ valid pointers stop. long insure have @ least 1 null preserved sentinel, can iterate without benefit of knowing precise number of pointers filled. e.g.:

size_t = 0; while (array[i]) {     ... stuff ... } 

when done using allocated memory, want insure free memory. while in simple piece of code, memory freed on exit, in habit of tracking memory allocate , freeing when no longer needed.

as particular task, want read line of unknown number of characters memory , tokenize (separate) string tokens. getline read , allocate memory sufficient hold size character string. can same thing of other input functions, have code repeated checks , reallocations yourself. if getline available (it in every modern compier), use it. matter of separating input tokens strtok or strsep. want duplicate each token preserve each token in own block of memory , assign location array of tokens. following provides short example.

included in example several helper functions opening files, allocating , reallocating. simple error checking keep main body of code clean , readable. on example , let me know if have questions.

#include <stdio.h> #include <stdlib.h> #include <string.h>  #define maxl  64    /* initial number of pointers  */  /* simple helper/error check functions */ file *xfopen (const char *fn, const char *mode); void *xcalloc (size_t n, size_t s); void *xrealloc_dp (void *ptr, size_t *n);  int main (int argc, char **argv) {      char **array = null;     char *line = null;     size_t i, idx = 0, maxl = maxl, n = 0;     ssize_t nchr = 0;     file *fp = argc > 1 ? xfopen (argv[1], "r") : stdin;      array = xcalloc (maxl, sizeof *array);    /* allocate maxl pointers */      while ((nchr = getline (&line, &n, fp)) != -1)     {         while (nchr > 0 && (line[nchr-1] == '\r' || line[nchr-1] == '\n'))             line[--nchr] = 0; /* strip carriage return or newline   */          char *p = line;  /* pointer use strtok */         (p = strtok (line, " \n"); p; p = strtok (null, " \n")) {              array[idx++] = strdup (p);  /* allocate & copy  */              /* check limit reached  - reallocate */             if (idx == maxl) array = xrealloc_dp (array, &maxl);         }     }     free (line);  /* free memory allocated getline */     if (fp != stdin) fclose (fp);      (i = 0; < idx; i++)  /* print tokens */         printf (" array[%2zu] : %s\n", i, array[i]);      (i = 0; < idx; i++)  /* free memory  */         free (array[i]);     free (array);      return 0; }  /* fopen error checking */ file *xfopen (const char *fn, const char *mode) {     file *fp = fopen (fn, mode);      if (!fp) {         fprintf (stderr, "xfopen() error: file open failed '%s'.\n", fn);         // return null;         exit (exit_failure);     }      return fp; }  /* simple calloc error checking */ void *xcalloc (size_t n, size_t s) {     void *memptr = calloc (n, s);     if (memptr == 0) {         fprintf (stderr, "xcalloc() error: virtual memory exhausted.\n");         exit (exit_failure);     }      return memptr; }  /*  realloc array of pointers ('memptr') twice current  *  number of pointer ('*nptrs'). note: 'nptrs' pointer  *  current number updated value preserved.  *  no pointer size required known (simply size  *  of pointer  */ void *xrealloc_dp (void *ptr, size_t *n) {     void **p = ptr;     void *tmp = realloc (p, 2 * *n * sizeof tmp);     if (!tmp) {         fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);         exit (exit_failure);     }     p = tmp;     memset (p + *n, 0, *n * sizeof tmp); /* set new pointers null */     *n *= 2;      return p; } 

input file

$ cat dat/captnjack.txt tale of captain jack sparrow pirate brave on 7 seas. 

output

$ ./bin/getline_strtok <dat/captnjack.txt  array[ 0] :  array[ 1] :  array[ 2] :  array[ 3] : tale  array[ 4] : of  array[ 5] : captain  array[ 6] : jack  array[ 7] : sparrow  array[ 8] :  array[ 9] : pirate  array[10] :  array[11] : brave  array[12] : on  array[13] :  array[14] : 7  array[15] : seas. 

memory/error check

in code write dynamically allocates memory, have 2 responsibilites regarding block of memory allocated: (1) preserves pointer starting address block of memory so, (2) can freed when no longer needed. imperative use memory error checking program insure haven't written beyond/outside allocated block of memory , confirm have freed memory have allocated. linux valgrind normal choice. there many subtle ways misuse block of memory can cause real problems, there no excuse not it. there similar memory checkers every platform. simple use. run program through it.

$ valgrind ./bin/getline_strtok <dat/captnjack.txt ==26284== memcheck, memory error detector ==26284== copyright (c) 2002-2012, , gnu gpl'd, julian seward et al. ==26284== using valgrind-3.8.1 , libvex; rerun -h copyright info ==26284== command: ./bin/getline_strtok ==26284==  array[ 0] :  array[ 1] : <snip>  array[14] : 7  array[15] : seas. ==26284== ==26284== heap summary: ==26284==     in use @ exit: 0 bytes in 0 blocks ==26284==   total heap usage: 18 allocs, 18 frees, 708 bytes allocated ==26284== ==26284== heap blocks freed -- no leaks possible ==26284== ==26284== counts of detected , suppressed errors, rerun with: -v ==26284== error summary: 0 errors 0 contexts (suppressed: 2 2) 

what want confirm each time "all heap blocks freed -- no leaks possible" , "error summary: 0 errors 0 contexts".


Comments

Popular posts from this blog

get url and add instance to a model with prefilled foreign key :django admin -

css - Make div keyboard-scrollable in jQuery Mobile? -

ruby on rails - Seeing duplicate requests handled with Unicorn -