Всем доброе утро!
Я часто прохожу собеседования, на одном из последних встретил интересную задачу.
Решение выложу после 10 неудачных попыток в комментариях.
Надо определить, что будет выведено на экране. Допустим, у изначального потока
Я часто прохожу собеседования, на одном из последних встретил интересную задачу.
Решение выложу после 10 неудачных попыток в комментариях.
Надо определить, что будет выведено на экране. Допустим, у изначального потока
id равен 1, а при смене потока ему можно присвоить любой другой (2, 3, 10, 77 и так далее).
public static async Task<int> GetValue1()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // ?
return await Task.FromResult(100500);
}
public static async Task<int> GetValue2()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // ?
return 500100;
}
public static Task<int> GetValue3()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // ?
return Task.Run(() => 500100);
}
static async Task Main(string[] args)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // 1
var val1 = await GetValue1();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // ?
var val2 = await GetValue2();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // ?
var val3 = await GetValue3();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // ?
}
🤯6🤔4👍2❤1⚡1
StepOne | Степан Минин
Всем доброе утро! Я часто прохожу собеседования, на одном из последних встретил интересную задачу. Решение выложу после 10 неудачных попыток в комментариях. Надо определить, что будет выведено на экране. Допустим, у изначального потока id равен 1, а при…
Из-за разных обстоятельств чуть-чуть задержался с выкладыванием решения, но всё же в этом посте расставлю все точки над "i", как и обещал.
Но прежде, хочу выразить огромную радость по поводу того, какие подкованные у меня подписчики. В комментариях было много людей, ответивших правильно, причём сразу.
Затем, там началась интересная дискуссия, а далее вообще прислали уже новую задачу.
Для меня, как автора, работающего с аудиторией это большая победа, спасибо вам!
Итак, как уже было верно подмечено в комментах, программа выведет
Почему ответ именно такой?
Задача проверяет понимание того, в какой момент поток из ThreadPool действительно понадобится в случае
В методе
С
Ну а в случае
Но прежде, хочу выразить огромную радость по поводу того, какие подкованные у меня подписчики. В комментариях было много людей, ответивших правильно, причём сразу.
Затем, там началась интересная дискуссия, а далее вообще прислали уже новую задачу.
Для меня, как автора, работающего с аудиторией это большая победа, спасибо вам!
Итак, как уже было верно подмечено в комментах, программа выведет
"1 1 1 1 1 <любое другое число>". Здесь не подразумевались какие-то дополнительные условия, только конфигурация по умолчанию.Почему ответ именно такой?
Задача проверяет понимание того, в какой момент поток из ThreadPool действительно понадобится в случае
await'а.В методе
GetValue2 всё очевидно, поскольку ключевого слова await не было, соответственно автомат компилятором не сгенерируется, и код метода останется неизменным.С
GetValue1 всё чуть интереснее. Кажется, что произойдут все манипуляции, ведь есть и задачка, и await. Но runtime умнее, чем мы думаем и он понимает, что Task.FromResult, ровно как и Task.CompletedTask, создаёт уже завершенную задачу, которую не требуется ожидать. Соотвественно, смена потока не требуется.Ну а в случае
GetValue3, конечно смена потока произойдёт. Несмотря на элементарность задачи, Task.Run уже возвращает запущенную, но не завершённую.❤10👍1🔥1👏1🤩1
Внедрение конкретной реализации в стандартном контейнере
Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций:
И мы хотим, используя стандартный DI контейнер .NET Core, внедрить в определённый сервис конкретную реализацию этого контракта.
То есть:
К сожалению, стандартный контейнер не предоставляет встроенных возможностей для решения этой задачи.
Он спроектирован просто и минималистично, чтобы новый функционал было легко добавлять согласно индивидуальным потребностям.
Здесь есть несколько вариантов решения:
1⃣ Создание фабрики
2⃣ Создание Service Delegate
3⃣ Внедрение коллекции зависимостей
4⃣ Явная регистрация, например:
Конечно, указанные решения не идеальные.
В такой ситуации стоит посмотреть в сторону других контейнеров.
Ставьте реакции на этот пост, если хотите, чтобы я о них написал.
Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций:
public interface IDependency {}
public class DependencyImplOne : IDependency {}
public class DependencyImplTwo : IDependency {}
И мы хотим, используя стандартный DI контейнер .NET Core, внедрить в определённый сервис конкретную реализацию этого контракта.
То есть:
public class BarService : IBarService
{
public BarService(IDependency dependency) // DependencyImplOne
{
}
}
public class BazService : IBazService
{
public BazService(IDependency dependency) // DependencyImplTwo
{
}
}
К сожалению, стандартный контейнер не предоставляет встроенных возможностей для решения этой задачи.
Он спроектирован просто и минималистично, чтобы новый функционал было легко добавлять согласно индивидуальным потребностям.
Здесь есть несколько вариантов решения:
1⃣ Создание фабрики
2⃣ Создание Service Delegate
3⃣ Внедрение коллекции зависимостей
IEnumerable<IDependency> с её последующим перебором4⃣ Явная регистрация, например:
services.AddTransient<IBazService, BazService>(_ => new BazService(new DependencyImplTwo()))Конечно, указанные решения не идеальные.
В такой ситуации стоит посмотреть в сторону других контейнеров.
Ставьте реакции на этот пост, если хотите, чтобы я о них написал.
🔥32👍8🤩1
StepOne | Степан Минин
Внедрение конкретной реализации в стандартном контейнере Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций: public interface IDependency {} public class DependencyImplOne : IDependency {} public class DependencyImplTwo : IDependency…
Итак, любители внедрения зависимостей! Поскольку пост получил большой отклик, начинаю публиковать про другие контейнеры!
🔥6
StepOne | Степан Минин
Внедрение конкретной реализации в стандартном контейнере Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций: public interface IDependency {} public class DependencyImplOne : IDependency {} public class DependencyImplTwo : IDependency…
Simple Injector. Условная регистрация
Возможность внедрять конкретную реализацию зависимости согласно определённому контексту в этом контейнере реализована с помощью метода
Из приведённого примера видно, что условная регистрация позволяет настроить поставку зависимости на основе определения типа потребителя.
То есть,
Возможность внедрять конкретную реализацию зависимости согласно определённому контексту в этом контейнере реализована с помощью метода
RegisterConditional:
container.RegisterConditional<ILogger, NullLogger>(
c => c.Consumer.ImplementationType == typeof(HomeController));
container.RegisterConditional<ILogger, FileLogger>(
c => c.Consumer.ImplementationType == typeof(UsersController));
container.RegisterConditional<ILogger, DatabaseLogger>(c => !c.Handled);Из приведённого примера видно, что условная регистрация позволяет настроить поставку зависимости на основе определения типа потребителя.
То есть,
HomeController получит NullLogger, UsersController получит FileLogger, а все остальные потребители ILogger получат DatabaseLogger.⚡7👍2🔥2
StepOne | Степан Минин
Внедрение конкретной реализации в стандартном контейнере Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций: public interface IDependency {} public class DependencyImplOne : IDependency {} public class DependencyImplTwo : IDependency…
Castle Windsor. Явное указание зависимостей
Возвращаясь к нашему примеру с логгером, допустим, что у сервиса
В нём указывается конкретная зависимость, которую требуется внедрить.
Перегрузок метода много, соответственно вариантов это сделать несколько: от именованных зависимостей до явного указания типов.
Самый простой вариант будет выглядеть так:
Возвращаясь к нашему примеру с логгером, допустим, что у сервиса
ILogger есть две реализации: некий стандартный Logger и безопасный SecureLogger, который требуется использовать в некотором сервисе TransactionProcessingEngine.
В контейнере Castle Windsor это можно настроить, используя метод Dependency.OnComponent.В нём указывается конкретная зависимость, которую требуется внедрить.
Перегрузок метода много, соответственно вариантов это сделать несколько: от именованных зависимостей до явного указания типов.
Самый простой вариант будет выглядеть так:
container.Register(
Component.For<ITransactionProcessingEngine>().ImplementedBy<TransactionProcessingEngine>()
.DependsOn(Dependency.OnComponent<ILogger, SecureLogger>())
);👍10❤1👏1
Autofac. Именованные сервисы
Контейнер Autofac предоставляет возможность внедрять конкретные зависимости, явно указывая некоторый ключ, который соотносится с желаемой зависимостью.
Например, у нас есть сервис
Чтобы указать, что мы хотим внедрить конкретную реализацию
По указанному ключу, он проведёт фильтрацию и выберет нужную зависимость.
Пример:
Контейнер Autofac предоставляет возможность внедрять конкретные зависимости, явно указывая некоторый ключ, который соотносится с желаемой зависимостью.
Например, у нас есть сервис
IDisplay, отображающий какие-то произведения искусства IArtwork.Чтобы указать, что мы хотим внедрить конкретную реализацию
MyPainting, можно использовать атрибут KeyFilterAttribute.По указанному ключу, он проведёт фильтрацию и выберет нужную зависимость.
Пример:
public class ArtDisplay : IDisplay
{
public ArtDisplay([KeyFilter("MyPainting")] IArtwork art) { ... }
}
// ...
var builder = new ContainerBuilder();
builder.RegisterType<MyPainting>().Keyed<IArtwork>("MyPainting");
builder.RegisterType<ArtDisplay>().As<IDisplay>().WithAttributeFiltering();
// ...
var container = builder.Build();
⚡7👍1👏1
С Днём Победы!
Эта война и праздник останутся сакральными для русского человека, это глубоко в нас прописано на каком-то неизученном языке программирования человеческой сути.
Я точно также храню память и благодарен бабушкам и дедушкам, ковавшим победу.
Одним из этих людей является мой прадед, Воротников Николай Семёнович, кавалер Ордена Славы 3 степени, Ордена Красной Звезды и двух медалей За Отвагу.
Орден Славы он получил за то, что, выполняя приказ командования 24 декабря 1943 года, под вражеским обстрелом 13 раз устранял порванную связь с наблюдательными пунктами батарей дивизиона.
Дважды подвергаясь автоматному обстрелу, он сумел смотать 3 километра вражеского кабеля и, использовав его, установил связь с передовыми наблюдательными пунктами.
Чем обеспечил своевременное открытие огня дивизиону.
Смог бы так я?
Большой вопрос.
Хотя в мирной жизни прадед работал начальником АХО завода «Калибр».
Светлая память, с Праздником!
Эта война и праздник останутся сакральными для русского человека, это глубоко в нас прописано на каком-то неизученном языке программирования человеческой сути.
Я точно также храню память и благодарен бабушкам и дедушкам, ковавшим победу.
Одним из этих людей является мой прадед, Воротников Николай Семёнович, кавалер Ордена Славы 3 степени, Ордена Красной Звезды и двух медалей За Отвагу.
Орден Славы он получил за то, что, выполняя приказ командования 24 декабря 1943 года, под вражеским обстрелом 13 раз устранял порванную связь с наблюдательными пунктами батарей дивизиона.
Дважды подвергаясь автоматному обстрелу, он сумел смотать 3 километра вражеского кабеля и, использовав его, установил связь с передовыми наблюдательными пунктами.
Чем обеспечил своевременное открытие огня дивизиону.
Смог бы так я?
Большой вопрос.
Хотя в мирной жизни прадед работал начальником АХО завода «Калибр».
Светлая память, с Праздником!
❤26🤡11👍4👏2🕊1🥱1
StepOne | Степан Минин
Внедрение конкретной реализации в стандартном контейнере Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций: public interface IDependency {} public class DependencyImplOne : IDependency {} public class DependencyImplTwo : IDependency…
StructureMap. Настройка конструктора
Контейнер StructureMap позволяет решить задачу, используя настройку конструктора сервиса-потребителя.
Подход похож на то, что предлагает Autofac, но связывание происходит по имени параметра конструктора в потребителе контракта.
Например, у нас есть сервис для отправки сообщений
Какие-то ещё контейнеры уже не вижу смысла рассматривать, поскольку их подходы буду похожи на то, о чём я уже рассказал. Также, через какое-то время по совету подписчика сделаю бенчмарк, а пока переключусь на другую тему.
Контейнер StructureMap позволяет решить задачу, используя настройку конструктора сервиса-потребителя.
Подход похож на то, что предлагает Autofac, но связывание происходит по имени параметра конструктора в потребителе контракта.
Например, у нас есть сервис для отправки сообщений
IMessageService, который реализуют соответственно SmsService и EmailService. И есть некоторые сценарии, в которых нужно использовать разные имплементации, тогда конфигурация будет выглядеть примерно следующим образом:var container = new Container(x => {
x.For<FooScenario>().Use<FooScenario>()
.Ctor<IMessageService>("messageService")
.Is<SmsService>();
x.For<BarScenario>().Use<BarScenario>()
.Ctor<IMessageService>("messageService")
.Is<EmailService>();
});
// ...
public class FooScenario
{
public FooScenario(IMessageService messageService) // sms
}
// ...
public class BarScenario
{
public BarScenario(IMessageService messageService) // email
}
Какие-то ещё контейнеры уже не вижу смысла рассматривать, поскольку их подходы буду похожи на то, о чём я уже рассказал. Также, через какое-то время по совету подписчика сделаю бенчмарк, а пока переключусь на другую тему.
👍3❤2👏2🔥1🤩1👌1🕊1💯1
Анекдот, классический как книги дяди Боба:
Заходит однажды тестировщик в бар.
Забегает в бар.
Пролезает в бар.
Танцуя, проникает в бар.
Крадется в бар.
Врывается в бар.
Прыгает в бар.
Заказывает:
кружку пива,
2 кружки пива,
0 кружек пива,
999999999 кружек пива,
ящерицу в стакане,
–1 кружку пива,
qwerty кружек пива.
Первый реальный клиент заходит в бар и спрашивает, где туалет. Бар вспыхивает пламенем, все погибают.
Заходит однажды тестировщик в бар.
Забегает в бар.
Пролезает в бар.
Танцуя, проникает в бар.
Крадется в бар.
Врывается в бар.
Прыгает в бар.
Заказывает:
кружку пива,
2 кружки пива,
0 кружек пива,
999999999 кружек пива,
ящерицу в стакане,
–1 кружку пива,
qwerty кружек пива.
Первый реальный клиент заходит в бар и спрашивает, где туалет. Бар вспыхивает пламенем, все погибают.
😁30👍3🤩2🔥1
StepOne | Степан Минин
Многоликая регистрация в стандартном контейнере Допустим, у нас есть некоторый класс, который реализует более одного интерфейса: public interface IBar {} public interface IFoo {} public class FooBar : IFoo, IBar {} Наша задача зарегистировать экземпляр…
Пока не получается отойти от темы Dependency Injection на все 100%, как того хотелось бы.
Такое случается, когда погружаешься в тему глубоко и потребляешь много контента из разных источников.
Однако, пока я разбирался с контейнером StructureMap, обнаружил забавный факт.
Оказалось, что у него есть API для решения другой задачи, ранее обозначенной на канале:
Такое случается, когда погружаешься в тему глубоко и потребляешь много контента из разных источников.
Однако, пока я разбирался с контейнером StructureMap, обнаружил забавный факт.
Оказалось, что у него есть API для решения другой задачи, ранее обозначенной на канале:
var container = new Container(x =>
{
x.ForConcreteType<FooBar>().Configure.Singleton();
x.Forward<FooBar, IFoo>();
x.Forward<FooBar, IBar>();
});👍5🤔3👏1🤯1
Если вы хотите получить более глубокие знания в области внедрения зависимостей в .NET, то рекомендую прочитать книгу
Dependency Injection in .NET, Mark Seemann
В ней представлены ключевые паттерны DI на чистом C#, объяснение принципа работы контейнеров и раскрывается вопрос интеграции со стандартными технологиями Microsoft.
Dependency Injection in .NET, Mark Seemann
В ней представлены ключевые паттерны DI на чистом C#, объяснение принципа работы контейнеров и раскрывается вопрос интеграции со стандартными технологиями Microsoft.
👍13🔥4❤2👌1
В настоящий момент работаю над докладом для одной известной технической конференции.
Решил вспомнить одно из своих первых публичных выступлений, которое произошло в рамках Нобелевской недели на семинаре SIYSS 2018 в Стокгольме и поделиться им с вами.
https://youtu.be/f5KeOR-XmVw
Решил вспомнить одно из своих первых публичных выступлений, которое произошло в рамках Нобелевской недели на семинаре SIYSS 2018 в Стокгольме и поделиться им с вами.
https://youtu.be/f5KeOR-XmVw
YouTube
SIYSS 2018, Block 3, 6 Stepan Minin
Stockholm International Youth Science Seminar gather 25 young scientists from all over the world in a seminar in Stockholm at the same week as the Nobel week.
At the main event, The SIYSS Seminar, the young scientists presents their science projects for…
At the main event, The SIYSS Seminar, the young scientists presents their science projects for…
🔥13❤2
System vs Newtonsoft
Уже известный факт: коробочный сериализатор платформы .NET обзавёлся поддержкой полиморфной сериализации и десериализации.
Но насколько он быстрее по сравнению с Newtonsoft? Я задался этим вопросом и провёл бенчмарк. Сравнил работу с одним экземпляром и списком из 30000 различных объектов, каждый из которых являлся экземпляром некоторого производного класса.
Конфигурация сериализаторов следующая:
▪️camelCase
▪️pretty форматирование
▪️включение метаинформации о типе (поскольку в System её отключить нельзя, то в Newtonsoft нужно включить)
▪️конвертация
Уже известный факт: коробочный сериализатор платформы .NET обзавёлся поддержкой полиморфной сериализации и десериализации.
Но насколько он быстрее по сравнению с Newtonsoft? Я задался этим вопросом и провёл бенчмарк. Сравнил работу с одним экземпляром и списком из 30000 различных объектов, каждый из которых являлся экземпляром некоторого производного класса.
Конфигурация сериализаторов следующая:
▪️camelCase
▪️pretty форматирование
▪️включение метаинформации о типе (поскольку в System её отключить нельзя, то в Newtonsoft нужно включить)
▪️конвертация
enum в string
Результат на фото: платформенное решение быстрее стороннего в ~4 раза в сериализации и в ~3.5 раза в десериализации.👍17🤯5❤2🔥2
Какую самую главную ошибку совершают новички в ООП?
Начав изучать ООП, многие знакомятся с его тремя столпами: инкапсуляция, наследование и полиморфизм. Но удаётся ли правильно понять все из них?
Если выполнить поиск определения инкапсуляции в Google, то можно получить примерно следующее:
«Инкапсуляция в программировании — это принцип, согласно которому внутреннее устройство сущностей нужно объединять в специальной «оболочке» и скрывать от вмешательств извне.»
А теперь вспомним, что самыми популярными объектно-ориентированными языками программирования являются Java и C#, где модификаторы доступа (
На самом же деле, корректнее привести следующее определение:
«Инкапсуляция – это объединение в рамках одной структуры функций и данных, с которыми эти функции работают.»
То есть, в случае объектно-ориентированного программирования, создав некоторый объект, мы связали его данные с определёнными методами на всё время его жизни.
А в случае, например, обычных функций мы просто описали некий алгоритм, который описывает последовательность действий никак не связанных с некоторым состоянием.
Вот простой пример, чтобы понять разницу:
Начав изучать ООП, многие знакомятся с его тремя столпами: инкапсуляция, наследование и полиморфизм. Но удаётся ли правильно понять все из них?
Если выполнить поиск определения инкапсуляции в Google, то можно получить примерно следующее:
«Инкапсуляция в программировании — это принцип, согласно которому внутреннее устройство сущностей нужно объединять в специальной «оболочке» и скрывать от вмешательств извне.»
А теперь вспомним, что самыми популярными объектно-ориентированными языками программирования являются Java и C#, где модификаторы доступа (
private, public, protected, etc.) это одни из самых используемых ключевых слов. И получается, что начинающие программисты путают сокрытие с инкапсуляцией.На самом же деле, корректнее привести следующее определение:
«Инкапсуляция – это объединение в рамках одной структуры функций и данных, с которыми эти функции работают.»
То есть, в случае объектно-ориентированного программирования, создав некоторый объект, мы связали его данные с определёнными методами на всё время его жизни.
А в случае, например, обычных функций мы просто описали некий алгоритм, который описывает последовательность действий никак не связанных с некоторым состоянием.
Вот простой пример, чтобы понять разницу:
class Doubler
{
private readonly int value;
public Doubler(int value) => this.value = value;
public int Double() => this.value * 2;
}
//…
public int Double(int value) => value * 2;👍8🤯3🥴2🔥1😱1💯1
Почему важно развивать алгоритмическое мышление для того чтобы научиться программировать?
Для начала вспомним, что такое алгоритм.
Алгоритм - это формально описанная последовательность действий, которую необходимо выполнить для получения требуемого результата.
Соответственно, для любого алгоритма характерны следующие особенности:
▪️конечность
▪️определенность
▪️ввод и вывод
▪️эффективность
А что из себя представляет программирование? Это процесс создания инструкций, которые указывают компьютеру в деталях как выполнить определённую задачу.
Получается, что навык алгоритмизации даёт логическую основу для умения решать задачи пошагово и эффективно.
В то время, как программирование это лишь инструмент описания алгоритмов на языке понятном исполнителю, то есть, машине.
Для начала вспомним, что такое алгоритм.
Алгоритм - это формально описанная последовательность действий, которую необходимо выполнить для получения требуемого результата.
Соответственно, для любого алгоритма характерны следующие особенности:
▪️конечность
▪️определенность
▪️ввод и вывод
▪️эффективность
А что из себя представляет программирование? Это процесс создания инструкций, которые указывают компьютеру в деталях как выполнить определённую задачу.
Получается, что навык алгоритмизации даёт логическую основу для умения решать задачи пошагово и эффективно.
В то время, как программирование это лишь инструмент описания алгоритмов на языке понятном исполнителю, то есть, машине.
👍11❤🔥9🔥2🥴2🤯1😱1
Что делает оператор
Недавно был сильно удивлён, когда узнал, что многие backend разработчики middle уровня в крупных компаниях не знают, что делает ключевое слово
Конечно, верхнеуровневая концепция в рамках ООП понятна. Создаём объект, заносим какие-то параметры, значения присваиваются и получается связка некоторых данных под именем одного типа.
Однако, отсутствует низкоуровневое понимание процесса.
То есть, что делать, если в языке нет этого слова
Здесь нам поможет обращение к истокам, а именно языку программирования Си.
На его примере очень полезно изучать концепцию динамической памяти и указателей.
Правда делать надо это осторожно, иначе не избежать часов с valgrind.
Так вот память, требуемая для создания объекта выделяется динамически.
Что это значит?
Компилятор во время своей работы не может определить в какой области памяти будут лежать данные, понадобится ли память для них вообще, а в некоторых случаях и сколько потребуется.
Всю эту информацию можно получить только во время выполнения программы.
Соответственно, в Си для этого были добавлены:
▪️ключевое слово
▪️функции выделения памяти (аллокации):
▪️функция освобождения памяти:
Пользуясь этими конструкциями можно описать примитивное поведение оператора
Например, у нас есть структура точки
Если на чём-то вроде Java мы напишем:
То есть, мы посчитали, сколько нам надо памяти, выделили её и вернули указатель на адрес, по которому лежит созданный объект.
А уже через него можно заниматься инициализацией, обновлением, и так далее.
new?Недавно был сильно удивлён, когда узнал, что многие backend разработчики middle уровня в крупных компаниях не знают, что делает ключевое слово
new.Конечно, верхнеуровневая концепция в рамках ООП понятна. Создаём объект, заносим какие-то параметры, значения присваиваются и получается связка некоторых данных под именем одного типа.
Однако, отсутствует низкоуровневое понимание процесса.
То есть, что делать, если в языке нет этого слова
new?Здесь нам поможет обращение к истокам, а именно языку программирования Си.
На его примере очень полезно изучать концепцию динамической памяти и указателей.
Правда делать надо это осторожно, иначе не избежать часов с valgrind.
Так вот память, требуемая для создания объекта выделяется динамически.
Что это значит?
Компилятор во время своей работы не может определить в какой области памяти будут лежать данные, понадобится ли память для них вообще, а в некоторых случаях и сколько потребуется.
Всю эту информацию можно получить только во время выполнения программы.
Соответственно, в Си для этого были добавлены:
▪️ключевое слово
sizeof, определяющее количество байтов, необходимое для хранения типа▪️функции выделения памяти (аллокации):
malloc, calloc, realloc▪️функция освобождения памяти:
freeПользуясь этими конструкциями можно описать примитивное поведение оператора
new.Например, у нас есть структура точки
Point:
struct Point {
float x, y;
};
Если на чём-то вроде Java мы напишем:
var p = new Point(), то на Си это будет выглядеть так:
struct Point *p = (struct Point*)malloc(sizeof(struct Point));
// обязательно потом высвобождаем память, ведь GC у нас нет!
free(p);
То есть, мы посчитали, сколько нам надо памяти, выделили её и вернули указатель на адрес, по которому лежит созданный объект.
А уже через него можно заниматься инициализацией, обновлением, и так далее.
🔥8👍5❤2🤔1🤯1