Proper use of malloc [closed]-Collection of common programming errors

I think the answers are missing an important point. The size of memory is a relatively specific technical detail which isn’t of primary interest. The crucial difference is that between automatic and dynamic storage, and the associated lifetime:

  • Automatic storage ends at the end of the scope.

  • Dynamic storage begins with malloc() and ends with free(), entirely at the discretion (and responsibility) of the user.

If you can and if it makes sense, everything should be automatic. This entails locality and well-defined interfaces. However, in C (not so much in C++) there comes a time when you need to talk about objects that aren’t local to the scope. That’s when we need dynamic allocation.

The prime example is your typical linked list. The list consists of nodes:

typedef struct node_tmp
{
  int data;
  struct node_tmp * next;
  struct node_tmp * prev;
} node;

Now to talk about such a list boils down to talking about any of its nodes and brachiate along the prev/next pointers. However, the actual nodes cannot sensibly be part of any local scope, so they are usually dynamically allocated:

node * create_list()
{
  node * p = malloc(sizeof node);  // [1]
  p->prev = p->next = 0;
  return p;
}

void free_list(node * p) // call with head node
{
  while (p->next)
  {
    node * tmp = p;
    p = p->next;
    free(tmp);                     // [2a]
  }
  free(p);                         // [2b]
}

void append_to_end(node * p, int data); // etc.

Here the list nodes exist outside any scope, and you have to bring them to life manually using malloc(), and clean them up when you’re done.

You can use linked lists even in the tiniest of programs, but there’s no real way around the manual allocation.

Edit: I thought of another example that should really convince you: You might think that you can just make the list with automatically allocated nodes:

node n1, n2, n3;      // an automatic linked list
n1.prev = n3.next = 0;
n1.next = &n2; n2.prev = &n1; n2.next = &n3; n3.prev = &n2;

But note that you cannot do this dynamically! “Dynamic” means “at runtime”, but automatic variables have to be determined entirely at compile time.

Suppose you wanted a program that reads integers from the user. If it’s even, you add it to the list, if it’s odd you ignore it, and if it’s zero you stop. You cannot possibly realize such a program with automatic allocation, because the allocation needs are only determined at runtime.

It is in such a scenario that you require malloc().