В приведенном вами примере
int *numbers;
numbers = malloc ( sizeof(int) * 10 );
явных преимуществ нет. Однако представьте, что 10 - это значение, которое изменяется во время выполнения (например, пользовательский ввод), и вам нужно вернуть этот массив из функции. Э.Г.
int *aFunction(size_t howMany, ...)
{
int *r = malloc(sizeof(int)*howMany);
// do something, fill the array...
return r;
}
Маллок занимает место из кучи, а что-то вроде
int *aFunction(size_t howMany, ...)
{
int r[howMany];
// do something, fill the array...
// you can't return r unless you make it static, but this is in general
// not good
return somethingElse;
}
будет использовать стек, который не такой большой, как вся доступная куча.
Более сложный пример существует. Например. если вам нужно построить двоичное дерево , которое растет в соответствии с некоторыми вычислениями, выполненными во время выполнения, у вас в основном нет другого выбора, кроме как использовать динамическое выделение памяти.