Advertisement
drankinatty

C - read file into dynamically allocated 2D array

Jan 8th, 2016
303
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.74 KB | None | 0 0
  1. /*  Read file or stdin into a dynamically allocated 2D array
  2.     filename is expected as 1st argument, otherwise read from stdin.
  3.     initial allocation of ROWS pointers to array of COLS long,
  4.     rows and columns are reallocated as needed. an equal number of
  5.     colums is enforced. conversion from string to long is provided
  6.     by strtol. input file format is flexible. all values within a
  7.     line are considered in the same row. all separators and
  8.     delimiters are ignored.
  9. */
  10.  
  11. #include <stdio.h>
  12. #include <stdlib.h> /* for strtol   */
  13. #include <string.h> /* for memset   */
  14. #include <limits.h> /* for INT_MIN/INT_MAX */
  15. #include <errno.h>  /* for errno    */
  16.  
  17. #define ROWS 128    /* max number of rows in array  */
  18. #define COLS 32     /* max number of cols in array  */
  19.  
  20. void *xcalloc (size_t n, size_t s);
  21. void *xrealloc (void *ptr, size_t psz, size_t *nelem);
  22.  
  23. int main (int argc, char **argv)
  24. {
  25.     long **array = NULL;
  26.     char *ln = NULL;
  27.     size_t n, row, nrows, col, ncols, rmax = ROWS;
  28.     FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
  29.     n = row = nrows = col = ncols = 0;
  30.  
  31.     if (!fp) { /* validate file open */
  32.         fprintf (stderr, "error: file open failen '%s'.\n", argv[1]);
  33.         return 1;
  34.     }
  35.  
  36.     /* allocate ROWS pointers initially */
  37.     array = xcalloc (ROWS, sizeof *array);
  38.  
  39.     /* read each line in file */
  40.     while (getline (&ln, &n, fp) != -1) {
  41.  
  42.         char *p = ln;   /* p & ep -- pointers for strtol */
  43.         char *ep = p;
  44.         size_t cmax = COLS;
  45.         col = errno = 0;
  46.  
  47.         /* allocate COLS number of int for each row */
  48.         array[row] = xcalloc (COLS, sizeof **array);
  49.  
  50.         /* convert each string of digits into number */
  51.         while (errno == 0) {
  52.  
  53.             /* skip any non-digit characters */
  54.             while (*p && ((*p != '-' && (*p < '0' || *p > '9')) ||
  55.                 (*p == '-' && (*(p+1) < '0' || *(p+1) > '9')))) p++;
  56.             if (!*p) break;
  57.  
  58.             /* convert string to number */
  59.             array[row][col++] = strtol (p, &ep, 10);
  60.  
  61.             if (errno) break;   /* check for error - covers all strtol err */
  62.  
  63.             if (col == cmax)    /* check if column full */
  64.                 array[row] = xrealloc (array[row], sizeof *array[row], &cmax);
  65.  
  66.             /* skip delimiters/move pointer to next digit */
  67.             while (*ep && *ep != '-' && (*ep < '0' || *ep > '9')) ep++;
  68.             if (*ep)
  69.                 p = ep;
  70.             else  /* break if end of string */
  71.                 break;
  72.         }
  73.  
  74.         if (row == 0)           /* set number of columns in file on 1st row */
  75.             ncols = col;
  76.  
  77.         if (col != ncols) {     /* if columns not equal, throw error */
  78.             fprintf (stderr, "error: invalid number of columns, row '%zu'.\n",
  79.                      nrows);
  80.             exit (EXIT_FAILURE);
  81.         }
  82.  
  83.         if (++row == rmax)      /* increment row, check against ROWS */
  84.             array = xrealloc (array, sizeof *array, &rmax);
  85.     }
  86.     nrows = row;                    /* set final numer of rows          */
  87.     free (ln);                      /* free mem allocated by getline    */
  88.     if (fp != stdin) fclose (fp);   /* close file if not default stdin  */
  89.  
  90.     printf ("\narray read from '%s'\n\n", argc > 1 ? argv[1] : "stdin");
  91.     for (row = 0; row < nrows; row++)
  92.     {
  93.         printf (" [");
  94.         for (col = 0; col < ncols; col++)
  95.         {
  96.             printf (" %3ld", array[row][col]);
  97.         }
  98.         printf (" ]\n");
  99.     }
  100.  
  101.     for (row = 0; row < nrows; row++)   /* free allocated memory */
  102.         free (array[row]);
  103.     free (array);
  104.  
  105.     return 0;
  106. }
  107.  
  108. /** xcalloc allocates memory using calloc and validates the return.
  109.  *  xcalloc allocates memory and reports an error if the value is
  110.  *  null, returning a memory address only if the value is nonzero
  111.  *  freeing the caller of validating within the body of code.
  112.  */
  113. void *xcalloc (size_t n, size_t s)
  114. {
  115.     register void *memptr = calloc (n, s);
  116.     if (memptr == 0) {
  117.         fprintf (stderr, "xcalloc() error: virtual memory exhausted.\n");
  118.         exit (EXIT_FAILURE);
  119.     }
  120.  
  121.     return memptr;
  122. }
  123.  
  124. /** realloc 'ptr' of 'nelem' of 'psz' to 'nelem * 2' of 'psz'.
  125.  *  returns pointer to reallocated block of memory with new
  126.  *  memory initialized to 0/NULL. return must be assigned to
  127.  *  original pointer in caller.
  128.  */
  129. void *xrealloc (void *ptr, size_t psz, size_t *nelem)
  130. {
  131.     void *memptr = realloc ((char *)ptr, *nelem * 2 * psz);
  132.     if (!memptr) {
  133.         fprintf (stderr, "realloc() error: virtual memory exhausted.\n");
  134.         exit (EXIT_FAILURE);
  135.     }   /* zero new memory (optional) */
  136.     memset ((char *)memptr + *nelem * psz, 0, *nelem * psz);
  137.     *nelem *= 2;
  138.     return memptr;
  139. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement