Search code examples
cpointerscharmallocfree

C char array, pointers, malloc, free


I am trying to understand pointers and I've got this simple example

void third(char ****msg) {
    ***msg = malloc(5 * sizeof (char));
    printf("\nthe msg in third is :%s ", ***msg);
    strcpy(***msg, "third");
    printf("\nthe msg in third after is: %s", ***msg);
    // free(***msg);
}

void change(char***msg) {
    **msg = malloc(5 * sizeof (char));
    printf("\nthe msg in change is :%s ", **msg);
    strcpy(**msg, "change");
    printf("\nthe msg in change after is: %s", **msg);
    third(&msg);
    //   free(**msg);
}

void test(char ** msg) {
    *msg = malloc(5 * sizeof (char));
    printf("\n the msg in test is: %s", *msg);

    strcpy(*msg, "test");
    printf("\nthe msg in test after is: %s\n", *msg);

    change(&msg);
    free(*msg);
}

int main(int argc, char** argv) {

    char * msg;
    test(&msg);
    printf("\nthe msg back in main is: %s", msg);
}

I could say it is working fine, but could you tell me when and how I need to free the allocated memory, because if I remove the // from functions change and third and run it I am having errors. And is there a way to get the content of the message in the first print statement of each function - see the otuput:

the msg in test is: 
the msg in test after is: test
the msg in change is :0�� 
the msg in change after is: change
the msg in third is :P�� 
the msg in third after is: third
the msg back in main is: 

Is there a way to get the msg in change is : test and then the msg in third is : change


Solution

  • Just forget about that program, there's just too much wrong with it:

    • You don't need multiple levels of indirection. Two levels is enough. Simply pass on the pointer-to-pointer to the next function, if that function needs to change the address.
    • You try to print the string before it has been initialized.
    • You try to use the string after freeing it.
    • You create memory leaks by repeatedly calling malloc without cleaning up the old contents. Use realloc instead.
    • You allocate incorrect amounts of memory so the arrays aren't large enough to hold the strings you strcpy into them. Also note that you need to allocate enough room for the null terminator.

    And so on. Here's a fixed version:

    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    
    void third(char** msg) {
        const char str[] = "third";
    
        *msg = realloc(*msg, sizeof(str));
        printf("the msg in third is :%s\n", *msg);
    
        strcpy(*msg, str);
        printf("the msg in third after is: %s\n", *msg);
    }
    
    void change(char** msg) {
        const char str[] = "change";
    
        *msg = realloc(*msg, sizeof(str));
        printf("the msg in change is :%s\n", *msg);
    
        strcpy(*msg, str);
        printf("the msg in change after is: %s\n", *msg);
    
        third(msg);
    }
    
    void test(char** msg) {
        const char str[] = "test";
    
        *msg = malloc(sizeof(str));
        printf("the msg in test is just garabage at this point, no need to print it.\n");
    
        strcpy(*msg, str);
        printf("the msg in test after is: %s\n", *msg);
    
        change(msg);
    }
    
    int main(int argc, char** argv) {
    
        char* msg;
        test(&msg);
        printf("the msg back in main is: %s\n", msg);
    
        free(msg);
    }