Code snippets:realloc use

From C

Jump to: navigation, search
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

/*** Object types */

enum e_grow_status {
    grow_status_success,
    grow_status_invalid_param,
    grow_status_too_big,
    grow_status_out_of_memory,
    grow_status_count
  };
typedef enum e_grow_status e_grow_status;

/*** Function declarations */

e_grow_status realloc_str_buf(
    char ** buf_ptr,
    unsigned int new_size
  );

e_grow_status append_buf(
    char ** buf_ptr,
    char ** tail_ptr,
    unsigned int tail_size
  );

int grow_status_msg(e_grow_status code);

/*** Function definitions */

int main(void) {
    /*
     * We will attempt to grow our storage by this
     * amount, each time we need to grow it
     */
    const unsigned int growth = 10;

    /*
     * This will point to where we put our data.
     * Initially, it points to no storage
     */
    char * buf = NULL;

    /* Where we append data when the buffer is grown */
    char * tail;

    /* Buffer-growing status */
    e_grow_status status;

    /*
     * Keep getting lines of input until there's no
     * more input to be had.  We append the new data
     * to the end of the current data
     */
    do {
        /* Make sure we have some buffer available */
        status = append_buf(&buf, &tail, growth);
        if (status != grow_status_success) {
            /* There was a problem with the buffer */
            free(buf);
            return grow_status_msg(status);
          }

        /* Read a line of input */
        if (!fgets(tail, growth, stdin)) {
            /* What is the nature of the problem? */
            if (ferror(stdin)) {
                /* An unexpected error */
                fprintf(stderr, "Unexpected input error!\n");
                free(buf);
                return EXIT_FAILURE;
              }
          }

        /* Do it all again */
        continue;
      } while (!feof(stdin));

    /* All done */
    printf(
        "----- All input: -----\n\n%s\n\n"
        "----- Final size: %u -----\n",
        buf,
        (unsigned int) (tail - buf)
      );
    free(buf);
    return EXIT_SUCCESS;
  }

e_grow_status realloc_str_buf(
    char ** buf_ptr,
    unsigned int new_size
  ) {
    /*
     * When we use 'realloc', we don't want to lose
     * track of where '*buf_ptr' currently points, so
     * we use another pointer to capture the result
     */
    char * new_buf;

    /* Check for invalid parameters */
    if (!buf_ptr || !new_size) {
        return grow_status_invalid_param;
      }

    /* Allocate more storage */
    new_buf = realloc(*buf_ptr, new_size);
    if (!new_buf) {
        /* Problem */
        return grow_status_out_of_memory;
      }

    /* Update the caller's pointer */
    *buf_ptr = new_buf;

    return grow_status_success;
  }

e_grow_status append_buf(
    char ** buf_ptr,
    char ** tail_ptr,
    unsigned int tail_size
  ) {
    /* The current length of stored data */
    unsigned int data_len;

    /* The next size for a grown buffer */
    unsigned int new_size;

    /* Buffer-growing status */
    e_grow_status status;

    /* Check for invalid parameter */
    if (!buf_ptr || !tail_ptr || !tail_size) {
        return grow_status_invalid_param;
      }

    /* How much storage is used? */
    if (*buf_ptr) {
        data_len = strlen(*buf_ptr);
      } else {
        data_len = 0;
      }

    /* How much total storage do we need? */
    new_size = data_len + tail_size;
    if (new_size < data_len) {
        /* Uh oh, we've wrapped around the maximum size */
        return grow_status_too_big;
      }

    /* Allocate 'tail_size' more storage */
    status = realloc_str_buf(buf_ptr, new_size);
    if (status != grow_status_success) {
        /* Problem */
        return status;
      }

    /* Tell the caller where the unused storage begins */
    *tail_ptr = *buf_ptr + data_len;

    /*
     * Ensure the tail begins with a null terminator,
     * for the sake of 'strlen' safety
     */
    **tail_ptr = 0;

    return grow_status_success;
  }

int grow_status_msg(e_grow_status code) {
    char * msg;

    switch (code) {
        case grow_status_success:
          /* No error */
          return EXIT_SUCCESS;

        case grow_status_invalid_param:
          msg = "An invalid parameter was passed!";
          break;

        case grow_status_too_big:
          msg = "Buffer too big!";
          break;

        case grow_status_out_of_memory:
          msg = "Out of memory!";
          break;

        default:
          msg = "Invalid status!";
          break;
      }

    fprintf(stderr, "grow_status_msg: %s\n", msg);
    return EXIT_FAILURE;
  }
Personal tools