На какую область памяти (кучу или стек) ссылается указатель после вызова malloc в C/C++?

Ответ

Указатель, возвращённый malloc (или calloc, realloc), ссылается на память, выделенную в куче (heap).

Ключевые отличия кучи от стека в контексте malloc:

Характеристика Память из malloc (Куча) Автоматическая память (Стек)
Время жизни Контролируется программистом. Существует от malloc до free. Автоматическое. Уничтожается при выходе из области видимости.
Управление Явное. Программист отвечает за выделение и освобождение. Неявное. Компилятор вставляет код для управления стеком.
Размер Ограничен объёмом виртуальной памяти ОС. Можно запросить большой блок. Ограничен размером стека потока (обычно 1-8 МБ).
Скорость Относительно медленнее (требуется поиск свободного блока, возможен вызов ОС). Очень быстро (просто сдвиг указателя стека).
Фрагментация Возможна внешняя и внутренняя фрагментация. Нет фрагментации.

Пример:

#include <cstdlib>
#include <iostream>

void stackAllocation() {
    int onStack[100]; // Выделено в стеке. Уничтожится при выходе из функции.
    // onStack = ...
} // Память для onStack автоматически освобождается здесь.

void heapAllocation() {
    // Выделение в куче
    int* onHeap = static_cast<int*>(malloc(100 * sizeof(int)));
    if (onHeap == nullptr) { // Всегда проверяем результат!
        // Обработка ошибки выделения памяти
        return;
    }
    // Использование памяти...
    onHeap[0] = 42;

    free(onHeap); // ЯВНОЕ освобождение. Без этого — утечка памяти.
    // onHeap теперь висячий указатель (dangling pointer).
}

int main() {
    stackAllocation();
    heapAllocation();
    return 0;
}

Важно: В современном C++ для работы с кучей предпочтительнее использовать операторы new/delete или, что ещё лучше, умные указатели (std::unique_ptr, std::shared_ptr) и контейнеры STL (например, std::vector), которые управляют памятью автоматически и безопасно.

Ответ 18+ 🔞

Давай разберёмся, где же эта память на самом деле живёт, а то у некоторых в голове уже каша, ёпта.

Вот ты вызываешь malloc (ну или его братьев calloc/realloc), и он тебе возвращает указатель. Так вот, этот указатель ведёт прямиком в кучу (heap). Не в стек, не в статическую память, а именно туда, в эту большую, неупорядоченную кучу свободной памяти, которой управляет операционная система.

Чем куча отличается от стека, если говорить на пальцах:

Что сравниваем Память от malloc (Куча) Обычные локальные переменные (Стек)
Живёт сколько? Пока ты её сам не убьёшь через free. Хоть до конца программы. Автоматически сдохнет, как только выйдешь из функции или блока.
Кто за неё отвечает? Ты, целиком и полностью. Забыл free — получил утечку памяти, и программа жрёт оперативку как не в себя. Компилятор. Он сам вставляет код, который подчищает за тобой.
Сколько можно взять? Овердохуища, в пределах разумного и доступной оперативки. Очень мало, обычно несколько мегабайт. Попробуй создать большой массив на стеке — получишь stack overflow и краш программы.
Скорость работы Относительно медленная, потому что там менеджер памяти ищет свободный кусок, может даже к ядру ОС обращаться. Молниеносная, просто двигают указатель стека.
Порядок Со временем может превратиться в швейцарский сыр — фрагментация. Полный порядок, всё лежит аккуратными слоями.

Простой пример, чтобы совсем всё стало ясно:

#include <cstdlib>
#include <iostream>

void работаСоСтеком() {
    int вСтеке[100]; // Выделили в стеке. Всё, бля, само очистится.
    // ... используем ...
} // Всё, вышли из функции — память сама освободилась. Красота.

void работаСКучой() {
    // Вот тут мы лезем в кучу
    int* вКуче = static_cast<int*>(malloc(100 * sizeof(int)));
    if (вКуче == nullptr) { // АХТУНГ! Всегда проверяй, не вернул ли malloc хуй в пальто вместо памяти!
        // Тут обработка пиздеца, если память не дали
        return;
    }
    // Используем...
    вКуче[0] = 42;

    free(вКуче); // ВОТ ОН, МОМЕНТ ИСТИНЫ! Сам, явно, освобождаем. Не сделаешь — будет утечка.
    // После free указатель `вКуче` стал висячим — указывает в пизду, в никуда. Трогать его нельзя.
}

int main() {
    работаСоСтеком();
    работаСКучой();
    return 0;
}

И главное, на что хочу обратить внимание: в современном C++ заморачиваться с malloc/free — это как будто на дворе 2002-й год. Нормальные пацаны используют new/delete, а ещё лучше — умные указатели вроде std::unique_ptr или контейнеры STL (std::vector). Они сами всё за тебя почистят, и волнение ебать по поводу утечек памяти отпадёт само собой.