ПРИВЕТ, ХАРБ!
В статье, я расскажу базу про то, как управлять памятью в языке программирования в 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)
Serpentine
09.11.2024 16:07в параметры нужно передать sizeof(int), эта функция возвращает размер в байтах переданного обьекта (хз как это подругому назвать, так что пусть будет так).
sizeof - это ключевое слово, а выражение sizeof(int) не функция, а операция. Как, например, &var, это операция взятия адреса. Об этом в каждом сишном букваре написано, если, конечно, сейчас их кто-нибудь читает.
Xedox_SlimeLime Автор
09.11.2024 16:07Я потеряное поколение
JerryI
09.11.2024 16:07@Xedox_SlimeLime, автор, вы наверно расстроились. Но не рекомендую отвечать так на критику, это прям только хуже сделает. Критика ведь конструктивная.
Принять, если есть мотивация - отшлифовать материал, разобраться по-лучше и опубликовать новый с учётом все упомянутого с референсом на комментарии (вероятно лучше по другой, но схожей теме).
Xedox_SlimeLime Автор
09.11.2024 16:07Спасибо, учту.
Не надо было писать статью по инфе которую узнал час назад...
obabichev
09.11.2024 16:07И публиковать ее для тех, кто мог изучать ее вплоть до полувека ^_^
Извините, не удержался, вы все равно молодец, тоже буду рад, если вы доразберетесь и дополируете статью
Zalechi
09.11.2024 16:07А шо так можно было? Ну ладно, пойду напишу статью про попугаев. Выделю два часа на изучение…
lrrr11
09.11.2024 16:07я-то думал, тут будет что-нибудь про паттерны с goto, про аттрибуты cleanup, constructor, destructor, про использование стека с оверкоммитментом, про правильное построение архитектуры программы, про всякие
-fanalyzer
, в общем про все, что поможет избежать выходов за пределы, двойных free и прочих бяк в софте на Си...А по факту тут какой-то даже не детский сад, а просто приветмир.
Xedox_SlimeLime Автор
09.11.2024 16:07Я уже осознал насколько я бездарь
Tzimie
09.11.2024 16:07Вы написали статью честно, без ChatGPT. Первый блин комом, но не стоит из-за этого прекращать писать
Xedox_SlimeLime Автор
09.11.2024 16:07Я вобщем не ожидал что на статью так набросятся. Я думал что она будет просто вечно весеть на хабре, как вобщем на других платформах...
KirillBelovTest
09.11.2024 16:07Эта статья намного лучше чем абсолютное большинство статей на современном Хабре. Здесь пишут про здоровье, ИИ, набросы про околополитические новости и всё что угодно, что только отдаленно похоже на технические темы. Лучше бы комментаторы минусовали и так едко комментировали всем надоевшие новости про ИИ, где сплошное балабольство. Поэтому желаю автору не бросать это дело, а дальше написать про что-то ещё посложнее. А ваще ещё в стародавние времена говорили «Хабр покажет насколько ты не прав» поэтому прочитав статью, но еще не читая комментарии я их все предвидел
Xedox_SlimeLime Автор
09.11.2024 16:07Вот совсем не ожидал положительного комментария сегодня, спасибо :>
JerryI
09.11.2024 16:07Статья максимально наивная и поверхностная, но автор хоть что-то попытался сам сделать и разобраться, в отличие от сгенерированного шлака, реклам курсов и ТГ каналов, который льется каждый день и получает десяток плюсов почти сразу после выхода если имеет в тегах ИИ.
Я б влепил текущей статье минус, написал что не так, но гасить карму автору - это антипаттерн. Это отрицательный отбор
Serpentine
09.11.2024 16:07Это больше похоже на рождение очередного виртуала, о котором все забудут через пару дней, и которому затем ему поднимет карму его ботовод вместе с такими же виртуалами, чтобы потом он мог минусовать "неугодные" комментарии и сливать карму авторам этих комментариев, заодно поднимать рейтинг нужных пользователей. Поэтому не удивляйтесь, когда оставив свое мнение в каком-нибудь блоге компании или подобной статье, вам через пару-тройку дней начнут по тихому сливать карму с причиной "Личная неприязнь" или "Придерживаюсь другой позиции".
Не в первый раз вижу, когда из песочницы достается откровенный шлак с кучей грамматических ошибок и нелепицей вместо содержания и набирает плюсы.
Если на эту статью посмотреть: при компиляции первого примера вылетит пачка предупреждений (видно невооруженным глазом), второй пример по идее вообще не соберется благодаря заголовку
stdlin.h.
Про дюжину опечаток и ошибок почти в каждом предложении я промолчу.Xedox_SlimeLime Автор
09.11.2024 16:07Я уже понял что статья хуйня
Serpentine
09.11.2024 16:07Статья не х%*ня, а скорее халтура. Поленились проверить на грамматические ошибки, взгляните на рекомендации от редакции Хабра, там есть ссылки даже на сервисы для проверки орфографии.
Затем, поленились прочитать несколько источников по теме - в интернете полно статей о динамическом выделении памяти в Си, а до этого хотя бы основы языка неплохо бы подтянуть.
Поленились хотя бы скомпилировать свой код и проверить его на ошибки, а это гораздо важнее грамматических ошибок.
Насчет выбора темы и т.н. уровня погружения в тему, скажу, что и статью для новичков можно было написать если не хорошо, так удовлетворительно, просто не допуская ваших ошибок.
Xedox_SlimeLime Автор
09.11.2024 16:07Я теперь уже понял что тут нельзя халтурить и тебя спросят за каждый лишний символ. И да, лучше нормально изучать материал, спасибо за рекомендации!
KirillBelovTest
09.11.2024 16:07Есть такая вероятность. Но я видимо все ещё наивен и слабо верю, что кому то придет в голову создавать аккаунт для минусования используя очевидное хабро-самоубийство
Serpentine
09.11.2024 16:07Каюсь, в данном конкретном случае я перегнул - автор на виртуала не похож.
Тем более загуглив его ник понял, что он просто пишет под мобилки вроде на Java (при этом зачем про Си писать, не понятно) и делает ролики в свое удовольствие, т.е. человек творческий. Поэтому поставлю плюс ему в карму и пожелаю творческих успехов.
Zalechi
09.11.2024 16:07Ага, вы наверно и не знали, что прежде чем написать статью он изучал вопрос один час. Конечно ботоферма. Ну или попытка получить доступ к лайкам.
Zalechi
09.11.2024 16:07Ага, вы наверно и не знали, что прежде чем написать статью он изучал вопрос один час. Конечно ботоферма. Ну или попытка получить доступ к лайкам.
Tzimie
09.11.2024 16:07Согласен, чел написал сам, без ChatGPT. Плохая статья своими словами лучше, чем хорошая от ChatGPT
randomsimplenumber
09.11.2024 16:07Плохая статья своими словами лучше, чем хорошая от ChatGPT
Плохая статья всегда хуже хорошей. А хорошей статьи от chatgpt я что-то не могу вспомнить. В лучшем случае она никакая.
Xedox_SlimeLime Автор
09.11.2024 16:07Первый блин - комом. Я посмотраюсь написать следующую статью лучше.
SIISII
09.11.2024 16:07Помимо крайней поверхностности, терминологических неточностей и т.п., полно синтаксических, грамматических и прочих ошибок. В общем, за оркографию и лапописание твёрдая 2.
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;
Судя по всему, автор новичек в си, так что желаю автору успехов в освоении этого простого, но одновременно сложного языка.
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;
Einherjar
09.11.2024 16:07Немного бесполезно, так как это же можно провернуть с malloc переиножив n и size.
malloc нулями не инициализирует
Xedox_SlimeLime Автор
09.11.2024 16:07А... Спасибо большое за информацию!
randomsimplenumber
09.11.2024 16:07Если в статье написано то же, что и в man'ах - она бесполезна. Если там написано что то иное - она вредна.
skyazimuth
09.11.2024 16:07void* a = (int*)malloc(4); *a = 7;
Зачем приводить к указателю на int, а затем присваивать указателю на void если malloc и так возвращает указатель на void?
На вторую строчку компилятор не ругается?
Xedox_SlimeLime Автор
09.11.2024 16:07Эту статью я писал довольно лениво, я писал код сразу в статье без компиляции и проверки его...
Spider55
09.11.2024 16:07Технически calloc не такой уж и бесполезный. Им наглядно аллочить "массивы" каких то структур, да это по факту тот же malloc с произведением кол-ва на размер. Но есть но. Память после calloc всегда содержит нули, так если бы вызвали memset(,0,) после malloc. А так же при больших объёмах памяти calloc может оказаться быстрее, т.к. он немного жульничает. Он изначально старается выделить память из области памяти, которая предварительно была обнулена при выделении страницы (конечно же это имеет место быть, если у вас ещё не каша в куче)
szt_1980
09.11.2024 16:07void* a = (int*)malloc(4);
*a = 7;
Это даже не соберётся, разыменование void* не имеет смысла.
int, кстати, далеко не везде 4-байтный.
wataru
*facepalm*
Это указатель на функцию, возвращающую void (и принимающую указатель на Vec), а не void*
Xedox_SlimeLime Автор
Я сначало хотел написать вектор, но потом изменил на Point.
wataru
Тут не в этой опечатке, а в том, что указатель на void тут вообще не при чем!