ПРИВЕТ, ХАРБ!

В статье, я расскажу базу про то, как управлять памятью в языке программирования в C. Для понимания материала, вам уже нужно знать как работать с указателями.

Начнем

Сначало разберем 2 самые простые функции, это malloc и free. Эти функции нкходятся в заголовочном файле "stdlib.h", так что подключаем его для работы.

Что делают это функции? malloc выделяет память, а free освобождает, сейчас разберем поподробнее.

Malloc

Как вы уже поняли выделяет память, если более оффициально то возвращает адрес первого байта в памяти, или указатель. В него мы просто должны передать столько байт, сколько нам надо. С помощью этой функции нельзя выделять биты, она работает исключительно с байтами.

Например если нужно выделить память под переменную типа данных int, то в параметры нужно передать sizeof(int), эта операция возвратиь размер в байтах переданного обьекта. Также можно сразу указать 4 байта, так как в основном int требует именнт столько (зависит от архитектуры процессора).

Free

Эта же функция освобождает выделеную память и после освобождения мы уже не сможем воспользоваться тем что освободили. В параметры передаем указатель на выделеную память.

Ее необходимо нужно вызывать тогда, когда указатель вам уже не нужен, иначе будет случаться утечка памяти.

Пример

Ну и конечно же приведу пример использования выше написаного материала. Создадим структуру Point с полями x и y, и выделим, а потом и освободим память выделеную под этот обьект.

#include<stdio.h>
#include<stdlib.h>

typedef struct {
  int* x;
  int* y;
} Point;

int main() {
  Point* p = 
    (Point*)
      malloc(sizeof(Point));
  p->x = 162;
  p->y = 13;
  printf("%x - x: %d, y: %d",
    p, p->x, p->y);
  free(p);
}

В консоль выведется что-то вроде:

0x7ffe42fo - x: 162, y: 13

Остальные функции

realloc - изменяет размер выделеной памяти, имеет следующие параметры: realloc(void* ptr, size_t new_size). ptr - это указатель на уже выделеную память, а new_size это новый размер выделеной памяти.

memcpy - копирует данные другого указателя, имеет следующие параметры: memcpy(void* dest, const void* src, size_t n). dest - указатель на область куда нужно скопировать данные, src - указатель на источник данных, n - сколько байт нужно скопировать.

calloc - выделяет блок памяти для n элементов каждый размером с sizе байт, заполняя все нулями. Имеет параметры: calloc(size_t n, size_t size). Немного бесполезно, так как это же можно провернуть с malloc переиножив n и size.

Это еще не все функции, но для начала вам с головой хватит которые я предоствил для практики.

Дополнительное

Это не совсем про выделение памяти, а скорее про указатели, но может быть полезно.

Возможно вы видели в параметрах void*, это неопределенный тип данных указателя, тоесть туда можно поместить указатель любого другого типа данных. Если вы до этого изучали Java, то это некоторое подобие класса Object

#include<stdlib.h>

void main() {
  void* a = (int*)malloc(4);
  *a = 7;
  free(a);
}

Это простой пример который никто не использует)

Пока, Хабр.

Комментарии (50)


  1. wataru
    09.11.2024 16:07

    Вомзожно вы видели в параметрах void*, ... В этот указатель можно помещать не только обычные значения, а даже функции!

    *facepalm*

     void (*zero)(Vec* v);

    Это указатель на функцию, возвращающую void (и принимающую указатель на Vec), а не void*


    1. Xedox_SlimeLime Автор
      09.11.2024 16:07

      Я сначало хотел написать вектор, но потом изменил на Point.


      1. wataru
        09.11.2024 16:07

        Тут не в этой опечатке, а в том, что указатель на void тут вообще не при чем!


  1. pfemidi
    09.11.2024 16:07

    memcry - копирует данные другого указателя,


    О чём плачет mem? И почему?


    1. Xedox_SlimeLime Автор
      09.11.2024 16:07

      Упс, не так написал...


  1. Serpentine
    09.11.2024 16:07

    в параметры нужно передать sizeof(int), эта функция возвращает размер в байтах переданного обьекта (хз как это подругому назвать, так что пусть будет так).

    sizeof - это ключевое слово, а выражение sizeof(int) не функция, а операция. Как, например, &var, это операция взятия адреса. Об этом в каждом сишном букваре написано, если, конечно, сейчас их кто-нибудь читает.


    1. Xedox_SlimeLime Автор
      09.11.2024 16:07

      Я потеряное поколение


      1. JerryI
        09.11.2024 16:07

        @Xedox_SlimeLime, автор, вы наверно расстроились. Но не рекомендую отвечать так на критику, это прям только хуже сделает. Критика ведь конструктивная.

        Принять, если есть мотивация - отшлифовать материал, разобраться по-лучше и опубликовать новый с учётом все упомянутого с референсом на комментарии (вероятно лучше по другой, но схожей теме).


        1. Xedox_SlimeLime Автор
          09.11.2024 16:07

          Спасибо, учту.

          Не надо было писать статью по инфе которую узнал час назад...


          1. obabichev
            09.11.2024 16:07

            И публиковать ее для тех, кто мог изучать ее вплоть до полувека ^_^

            Извините, не удержался, вы все равно молодец, тоже буду рад, если вы доразберетесь и дополируете статью


            1. Xedox_SlimeLime Автор
              09.11.2024 16:07

              Читая комментарии я иаправляю ошибки допущенные мною. Удачи.


          1. Zalechi
            09.11.2024 16:07

            А шо так можно было? Ну ладно, пойду напишу статью про попугаев. Выделю два часа на изучение…


  1. segment
    09.11.2024 16:07

    Пока, Хабр!

    До свидания! Не приходите больше =)


    1. Xedox_SlimeLime Автор
      09.11.2024 16:07

      Ладно, больше приходить не буду.


  1. lrrr11
    09.11.2024 16:07

    я-то думал, тут будет что-нибудь про паттерны с goto, про аттрибуты cleanup, constructor, destructor, про использование стека с оверкоммитментом, про правильное построение архитектуры программы, про всякие -fanalyzer, в общем про все, что поможет избежать выходов за пределы, двойных free и прочих бяк в софте на Си...

    А по факту тут какой-то даже не детский сад, а просто приветмир.


    1. Xedox_SlimeLime Автор
      09.11.2024 16:07

      Я уже осознал насколько я бездарь


      1. Tzimie
        09.11.2024 16:07

        Вы написали статью честно, без ChatGPT. Первый блин комом, но не стоит из-за этого прекращать писать


        1. Xedox_SlimeLime Автор
          09.11.2024 16:07

          Я вобщем не ожидал что на статью так набросятся. Я думал что она будет просто вечно весеть на хабре, как вобщем на других платформах...


          1. Za4emsu
            09.11.2024 16:07

            Но зачем тогда вы ее написали?


            1. Xedox_SlimeLime Автор
              09.11.2024 16:07

              Просто захотелось в один момент.


  1. KirillBelovTest
    09.11.2024 16:07

    Эта статья намного лучше чем абсолютное большинство статей на современном Хабре. Здесь пишут про здоровье, ИИ, набросы про околополитические новости и всё что угодно, что только отдаленно похоже на технические темы. Лучше бы комментаторы минусовали и так едко комментировали всем надоевшие новости про ИИ, где сплошное балабольство. Поэтому желаю автору не бросать это дело, а дальше написать про что-то ещё посложнее. А ваще ещё в стародавние времена говорили «Хабр покажет насколько ты не прав» поэтому прочитав статью, но еще не читая комментарии я их все предвидел


    1. Xedox_SlimeLime Автор
      09.11.2024 16:07

      Вот совсем не ожидал положительного комментария сегодня, спасибо :>


      1. Tzimie
        09.11.2024 16:07

        Поэтому минус за статью и плюс в карму. Потому что вы живой человек


    1. JerryI
      09.11.2024 16:07

      Статья максимально наивная и поверхностная, но автор хоть что-то попытался сам сделать и разобраться, в отличие от сгенерированного шлака, реклам курсов и ТГ каналов, который льется каждый день и получает десяток плюсов почти сразу после выхода если имеет в тегах ИИ.

      Я б влепил текущей статье минус, написал что не так, но гасить карму автору - это антипаттерн. Это отрицательный отбор


    1. Serpentine
      09.11.2024 16:07

      Это больше похоже на рождение очередного виртуала, о котором все забудут через пару дней, и которому затем ему поднимет карму его ботовод вместе с такими же виртуалами, чтобы потом он мог минусовать "неугодные" комментарии и сливать карму авторам этих комментариев, заодно поднимать рейтинг нужных пользователей. Поэтому не удивляйтесь, когда оставив свое мнение в каком-нибудь блоге компании или подобной статье, вам через пару-тройку дней начнут по тихому сливать карму с причиной "Личная неприязнь" или "Придерживаюсь другой позиции".

      Не в первый раз вижу, когда из песочницы достается откровенный шлак с кучей грамматических ошибок и нелепицей вместо содержания и набирает плюсы.

      Если на эту статью посмотреть: при компиляции первого примера вылетит пачка предупреждений (видно невооруженным глазом), второй пример по идее вообще не соберется благодаря заголовку stdlin.h. Про дюжину опечаток и ошибок почти в каждом предложении я промолчу.


      1. Xedox_SlimeLime Автор
        09.11.2024 16:07

        Я уже понял что статья хуйня


        1. Serpentine
          09.11.2024 16:07

          Статья не х%*ня, а скорее халтура. Поленились проверить на грамматические ошибки, взгляните на рекомендации от редакции Хабра, там есть ссылки даже на сервисы для проверки орфографии.

          Затем, поленились прочитать несколько источников по теме - в интернете полно статей о динамическом выделении памяти в Си, а до этого хотя бы основы языка неплохо бы подтянуть.

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

          Насчет выбора темы и т.н. уровня погружения в тему, скажу, что и статью для новичков можно было написать если не хорошо, так удовлетворительно, просто не допуская ваших ошибок.


          1. Xedox_SlimeLime Автор
            09.11.2024 16:07

            Я теперь уже понял что тут нельзя халтурить и тебя спросят за каждый лишний символ. И да, лучше нормально изучать материал, спасибо за рекомендации!


      1. KirillBelovTest
        09.11.2024 16:07

        Есть такая вероятность. Но я видимо все ещё наивен и слабо верю, что кому то придет в голову создавать аккаунт для минусования используя очевидное хабро-самоубийство


        1. Serpentine
          09.11.2024 16:07

          Каюсь, в данном конкретном случае я перегнул - автор на виртуала не похож.

          Тем более загуглив его ник понял, что он просто пишет под мобилки вроде на Java (при этом зачем про Си писать, не понятно) и делает ролики в свое удовольствие, т.е. человек творческий. Поэтому поставлю плюс ему в карму и пожелаю творческих успехов.


          1. Zalechi
            09.11.2024 16:07

            Вот бы меня так плюсовали когда я про политику пишу))


          1. Zalechi
            09.11.2024 16:07

            Вот бы меня так плюсовали когда я про политику пишу))


          1. Zalechi
            09.11.2024 16:07

            Вот бы меня так плюсовали когда я про политику пишу))


        1. Zalechi
          09.11.2024 16:07

          Ага, вы наверно и не знали, что прежде чем написать статью он изучал вопрос один час. Конечно ботоферма. Ну или попытка получить доступ к лайкам.


        1. Zalechi
          09.11.2024 16:07

          Ага, вы наверно и не знали, что прежде чем написать статью он изучал вопрос один час. Конечно ботоферма. Ну или попытка получить доступ к лайкам.


    1. Tzimie
      09.11.2024 16:07

      Согласен, чел написал сам, без ChatGPT. Плохая статья своими словами лучше, чем хорошая от ChatGPT


      1. randomsimplenumber
        09.11.2024 16:07

        Плохая статья своими словами лучше, чем хорошая от ChatGPT

        Плохая статья всегда хуже хорошей. А хорошей статьи от chatgpt я что-то не могу вспомнить. В лучшем случае она никакая.


        1. Xedox_SlimeLime Автор
          09.11.2024 16:07

          Первый блин - комом. Я посмотраюсь написать следующую статью лучше.


  1. SIISII
    09.11.2024 16:07

    Помимо крайней поверхностности, терминологических неточностей и т.п., полно синтаксических, грамматических и прочих ошибок. В общем, за оркографию и лапописание твёрдая 2.


    1. Xedox_SlimeLime Автор
      09.11.2024 16:07

      Спасибо что не 1!


  1. alamat42
    09.11.2024 16:07

    #include<stdio.h>

    #include<stdlib.h>

    typedef struct {

    int* x;

    int* y;

    } Point;

    int main()

    {

    Point* p =

    (Point*)

    malloc(sizeof(Point));

    p->x = 162; p->y = 13;

    printf("%x - x: %d, y: %d",

    p, p->x, p->y); free(p);}

    Этот код, может, и рабочий, но в нкм есть смысловые ошибки.

    Во-первых, в структоре точки x и y - имеют тип не int, а указатель на int. Чисто технически, конечно, с указателем можно работать как с целочисленной переменной, но все же, мне кажется, указатели нужны не для этого)

    Соответственно, раз у нас х и у - это указатели, то и использовать %d для их печати потенциально некорректно

    printf("%x - x: %d, y: %d",

    p, p->x, p->y);

    Более корректно было бы примерно так:

    typedef struct{
        int x;
        int y;
    } Point;

    Судя по всему, автор новичек в си, так что желаю автору успехов в освоении этого простого, но одновременно сложного языка.


    1. Serpentine
      09.11.2024 16:07

      Чисто технически, конечно, с указателем можно работать как с целочисленной переменной, но все же, мне кажется, указатели нужны не для этого)

      Процитирую K&R § 5.4. Адресная арифметика:

      К числу разрешенных операций с указателями относятся:
      - присваивание указателей одного типа;
      - сложение или вычитание указателя и целого числа;
      - вычитание или сравнение указателей, указывающих на один и тот же массив данных;
      - присваивание нуля или сравнение с ним.


      Любые другие операции с адресами
      являются ошибками и не разрешены. Нельзя складывать два указателя, умножать, делить, сдвигать или применять маски к указателям, прибавлять к ним числа типа float или double. За исключением указателей типа void * нельзя даже присвоить указатель одного типа указателю другого без явного приведения типов.

      ________________

      Ну и "вопрос со звездочкой", оставив в коде поля структуры Point указателями, и присвоив им те же значения (x = 162, y = 13), чему будет равна знаковая целочисленная переменная d - результат следующего арифметического выражения (вычитания x и y)?

      ptrdiff_t d = p->x - p->y;


    1. Xedox_SlimeLime Автор
      09.11.2024 16:07

      Спасибо!


  1. Einherjar
    09.11.2024 16:07

    Немного бесполезно, так как это же можно провернуть с malloc переиножив n и size.

    malloc нулями не инициализирует


    1. Xedox_SlimeLime Автор
      09.11.2024 16:07

      А... Спасибо большое за информацию!


      1. randomsimplenumber
        09.11.2024 16:07

        Если в статье написано то же, что и в man'ах - она бесполезна. Если там написано что то иное - она вредна.


  1. skyazimuth
    09.11.2024 16:07

    void* a = (int*)malloc(4); *a = 7;

    Зачем приводить к указателю на int, а затем присваивать указателю на void если malloc и так возвращает указатель на void?

    На вторую строчку компилятор не ругается?


    1. Xedox_SlimeLime Автор
      09.11.2024 16:07

      Эту статью я писал довольно лениво, я писал код сразу в статье без компиляции и проверки его...


  1. Spider55
    09.11.2024 16:07

    Технически calloc не такой уж и бесполезный. Им наглядно аллочить "массивы" каких то структур, да это по факту тот же malloc с произведением кол-ва на размер. Но есть но. Память после calloc всегда содержит нули, так если бы вызвали memset(,0,) после malloc. А так же при больших объёмах памяти calloc может оказаться быстрее, т.к. он немного жульничает. Он изначально старается выделить память из области памяти, которая предварительно была обнулена при выделении страницы (конечно же это имеет место быть, если у вас ещё не каша в куче)


  1. szt_1980
    09.11.2024 16:07

    void* a = (int*)malloc(4);

    *a = 7;

    Это даже не соберётся, разыменование void* не имеет смысла.

    int, кстати, далеко не везде 4-байтный.