2

Here is my code:

struct movie {
    char movie_name[30];
    float score;
    struct movie *next;
};

typedef struct movie *p_movie;
void print_all(struct movie *head);

int main() {
    p_movie head = NULL;
    p_movie new_node = malloc(sizeof(struct movie));
    if (new_node == NULL) {
        exit(1);
    }
    strcpy(new_node->movie_name, "Avatar");
    new_node->score = 9.5f;
    new_node->next = NULL;
    if (head == NULL)
        head = new_node;
    print_all(head);
    new_node = malloc(sizeof(struct movie));
    if (new_node == NULL) {
        exit(1);
    }
    strcpy(new_node->movie_name, "Aladdin");
    new_node->score = 8.0f;
    new_node->next = NULL;
    p_movie temp = head;
    head = new_node;
    new_node->next = temp;

    print_all(head);
}

void print_all(struct movie *head) {
    printf("---------------------\n");
    printf("Head address = %zd\n", (size_t)head);
    struct movie* search = head;
    while (search != NULL) {
        printf("%zd \"%s\" %f %zd\n", (size_t)search, search->movie_name,
               search->score, (size_t)search->next);
        search = search->next;
    }
}

I'm confused because of malloc: It runs well, but I don't know why this code is running well.

My question is about new_node: first, I allocate memory to new_node and I don't free that and allocate memory again.

Then, what's happening with the first memory (Avatar)? Is that deleted? or saved somewhere..?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
tohardtme
  • 101
  • 4
  • 1
    while there is free (virtual) memory you can allocate. There is no garbage collector in C, when you lost the address of an allocate block that one is 'lost' for you but still present in memory, this is a memory leak. – bruno Apr 28 '20 at 08:45
  • I recommend you to not use `typedef` to define 'pointer to' type like you do in `typedef struct movie* p_movie;`, to hide pointer make the code difficult to read and is a good way to easily introduce bug – bruno Apr 28 '20 at 08:53
  • You don't need `p_movie temp = head;` you are just confusing yourself. What is happening is `new_node->next = head; head = new_node;` which is a method called *forward chaining* that adds nodes at the front of the list (like a stack). The downside, your list is in the reverse order of your input. – David C. Rankin Apr 28 '20 at 08:54

3 Answers3

2

First, I allocate memory to new_node. And I did not freed that and allocate memory again. Then, what's going on with the first memory (Avatar)? Is that deleted? or saved somewhere..?

As long as you didn´t free()d the memory allocated by previous calls to memory-management functions, it will reside in memory until the program finishes.

Can I constantly malloc memory without free?

It depends upon your memory capacity (how long it is capable to hold the constantly summarizing not deallocated memory chunks and allocate new memory). At a certain point you will be out of memory if you continue to stock up memory and your program and the working machine might crash.


Nonetheless, it isn´t a good practice to stock up unused memory even if your memory technically could handle it. Always free() not anymore needed dynamic memory.

2

Can I constantly malloc memory without free?

In theory, yes. In practice, only until you run out of memory.

first, I allocate memory to new_node.

And I didnt' free that and allocate memory again.

then, what's going on first memory (Avatar)?

Is that deleted? or saved somewhere..?

In your concrete example: if head == NULL, it is (obviously) saved. Here, "it" refers to a pointer to that memory.

If head wasn't NULL (which is impossible at that place), you would have a memory leak: you had allocated memory which you cannot refer any longer.

In general, after malloc(), you can keep this memory as long as you need it. This includes keeping it until your program ends. But if you don't save the pointer to that memory, you cannot do anything with it: neither use nor free it. In this case, your program needs more memory than it should, and if that occurrs regularly, it eventually will clog your memory needlessly.

In your case, however, you save this new_node in head, so it isn't lost. After doing so, you can use new_node (which is just a variable for holding the pointer!) for other purposes.

I'd suggest to move allocation of a new node to a separate function:

p_movie alloc_movie(char * name, float score)
{
    p_movie new_node = malloc(sizeof(struct movie));
    if (new_node == NULL) {
        return NULL; // let the caller handle that
    }
    strcpy(new_node->movie_name, name);
    new_node->score = score;
    new_node->next = NULL;
    return new_node;
}

and use that with

int main()
{
    p_movie head = NULL;
    p_movie new_node = alloc_movie("Avatar", 9.5f);
    if (new_node == NULL)
    {
        exit(1);
    }
    // if (head == NULL) is unnecessary, as we can be sure it is null
    head = new_node;
    print_all(head);

    new_node = alloc_movie("Aladdin", 8.0f);
    if (new_node == NULL)
    {
        exit(1);
    }

    // Put the new node as the head, let the old head then be the next item.
    p_movie temp = head;
    head = new_node;
    new_node->next = temp;

    print_all(head);
}

or even shorter:

p_movie alloc_movie(char * name, float score, p_movie next)
{
    p_movie new_node = malloc(sizeof(struct movie));
    if (new_node == NULL) {
        return NULL; // let the caller handle that
    }
    strcpy(new_node->movie_name, name);
    new_node->score = score;
    new_node->next = next;
    return new_node;
}

int main()
{
    p_movie new_node = alloc_movie("Avatar", 9.5f, NULL);
    if (new_node == NULL)
    {
        exit(1);
    }
    p_movie head = new_node;
    print_all(head);

    // Create a new node, with the old head as its "next".
    new_node = alloc_movie("Aladdin", 8.0f, head);
    if (new_node == NULL)
    {
        exit(1);
    }

    // Overwrite the head, as its old value is already saved in the "Aladdin" node.
    head = new_node;
    print_all(head);
}
Community
  • 1
  • 1
glglgl
  • 89,107
  • 13
  • 149
  • 217
1

Can I constantly malloc memory without free?

Yes, in practice, and many programs are malloc ing some data -at initialization time- without bothering to free it. But if you do it too often, you have a huge memory leak.

No, in theory. Read the C11 standard n1570.

Don't forget that malloc can fail.

It does make sense to write a program which malloc data at startup; make complex computations on it, and just exit-s. Most (but not all) operating systems can handle that, because when a process is terminated, the operating system kernel (e.g. Linux) would release the resources consumed by the process. Read about virtual address space and a good textbook about operating systems.

But such practice is ugly and brittle. If coding this way, you cannot transform your program into a reusable library. Several serious programs (including the GCC compiler, at some point in time) did malloc without free-ing before exit-ing or returning from their main

On Linux, see also pmap(1), mmap(2) -used by malloc(3)- and strace(1) and of course valgrind.

Be aware of the world's fastest malloc. Practically not very useful. (but standard conforming).

Be also aware of memory overcommitement.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547