Search code examples
carraysmallocfree

Free first element of array


When I allocate an array using malloc, is there a way to only free the first element(s) of the array?

A small example:

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

int main() {
    char * a = malloc(sizeof(char) * 8);
    strcpy(a, "foo bar");

    // How I would have to do this.
    char * b = malloc(sizeof(char) * 7);
    strcpy(b, a+1);


    free(a);
    free(b);
}

Is there a way to free just the first char of a, so that I can use the rest of the string using a+1?


Solution

  • If you want to remove the first character of a, you could use memmove() to move the remainder of the characters in the string to the left by 1, and you could use realloc() to shrink the allocation if desired:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(void)
    {
        char * a = malloc(sizeof(char) * 8);
        strcpy(a, "foo bar");
    
        puts(a);
    
        size_t rest = strlen(a);
    
        memmove(a, a+1, rest);
    
        /* If you must reallocate */
        char *temp = realloc(a, rest);
        if (temp == NULL) {
            perror("Unable to reallocate");
            exit(EXIT_FAILURE);
        }
        a = temp;
    
        puts(a);
    
        free(a);
    
        return 0;
    }
    

    Update

    @chux has made a couple of good points in the comments.

    First, instead of exiting on a failure in realloc(), it may be better to simply continue without reassigning temp to a; after all, a does point to the expected string anyway, the allocated memory would just be a little larger than necessary.

    Second, if the input string is empty, then rest will be 0. This leads to problems with realloc(a, rest). One solution would be to check for rest == 0 before modifying the string pointed to by a.

    Here is a slightly more general version of the above code that incorporates these suggestions:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(void)
    {
        char *s = "foo bar";
        char *a = malloc(sizeof *a * (strlen(s) + 1));
        strcpy(a, s);
    
        puts(a);
    
        size_t rest = strlen(a);
    
        /* Don't do anything if a is an empty string */
        if (rest) {
            memmove(a, a+1, rest);
    
            /* If you must reallocate */
            char *temp = realloc(a, rest);
            if (temp) {
                a = temp;
            }
        }
    
        puts(a);
    
        free(a);
    
        return 0;
    }