Полное руководство по языку программирования С# 14 и платформе .NET 10 / Сборка мусора, управление памятью и указатели

Указатели

Начальный ⏱ 4 мин чтения 👁 2 🕓 обновлено 11.08.2026

Если вы программировали на С/С++, то, возможно, вы знакомы с таким понятием как указатели. Указатели позволяют получить доступ к определенной ячейке памяти и произвести определенные манипуляции со значением, хранящимся в этой ячейке.

В языке C# указатели редко используются, однако в некоторых случаях можно прибегать к ним для оптимизации приложений. Код, применяющий указатели, еще называют небезопасным (unsafe) кодом. Однако это не значит, что он представляет какую-то опасность. Просто при работе с ним все действия по использованию памяти, в том числе по ее очистке, ложится целиком на нас, а не на среду CLR. И с точки зрения CLR такой код не безопасен, так как среда не может проверить данный код, поэтому повышается вероятность различного рода ошибок.

Чтобы использовать небезопасный код в C#, надо первым делом указать проекту, что он будет работать с небезопасным кодом. Для этого надо установить в настройках проекта соответствующий флаг с помощью опции:

<AllowUnsafeBlocks>true</AllowUnsafeBlocks>

Так, откроем файл настроек проекта (файл с расширением .csproj) и добавим эту опцию:


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>  <!-- нужная опция -->

  </PropertyGroup>

</Project>

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

Ключевое слово unsafe

Блок кода или метод, в котором используются указатели, помечается ключевым словом unsafe:


// блок кода, использующий указатели
unsafe 
{
	
}

Метод, использующий указатели:


unsafe void Test()
{

}

Также с помощью unsafe можно объявлять структуры и классы:


unsafe struct State
{ 

}

unsafe class Person
{

}

Операции * и &

Ключевой при работе с указателями является операция *, которую еще называют операцией разыменовывания. Операция разыменовывания позволяет получить или установить значение по адресу, на который указывает указатель. Для получения адреса переменной применяется операция &:


unsafe
{
    int* x; // определение указателя
    int y = 10; // определяем переменную

    x = &y; // указатель x теперь указывает на адрес переменной y
    Console.WriteLine(*x); // 10

    y = y + 20;     // меняем значение
    Console.WriteLine(*x);// 30

    *x = 50;
    Console.WriteLine(y); // переменная y=50
}

При объявлении указателя указываем тип int* x; - в данном случае объявляется указатель на целое число. Но кроме типа int можно использовать и другие: sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal или bool. Также можно объявлять указатели на типы enum, структуры и другие указатели.

Выражение x = &y; позволяет нам получить адрес переменной y и установить на него указатель x. До этого указатель x не на что не указывал.

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

Для получения значения, которое хранится в области памяти, на которую указывает указатель x, используется выражение *x.

Получение адреса

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


int* x; // определение указателя
int y = 10; // определяем переменную

x = &y; // указатель x теперь указывает на адрес переменной y

// получим адрес переменной y
ulong addr = (ulong)x;
Console.WriteLine($"Адрес переменной y: {addr}");

Для получения адреса используется преобразование в тип uint, long или ulong. Так как значение адреса - это целое число, а на 32-разрядных системах диапазон адресов 0 до 4 000 000 000, а адрес можно получить в переменную uint/int. Соответственно на 64-разрядных системах диапазон доступных адресов гораздо больше, поэтому в данном случае лучше использовать ulong, чтобы избежать ошибки переполнения.

Указатель на другой указатель

Объявление и использование указателя на указатель:


unsafe
{
    int* x; // определение указателя
    int y = 10; // определяем переменную

    x = &y; // указатель x теперь указывает на адрес переменной y
    int** z = &x; // указатель z теперь указывает на адрес, указателя x
    **z = **z + 40; // изменение указателя z повлечет изменение переменной y
    Console.WriteLine(y); // переменная y=50
    Console.WriteLine(**z); // переменная **z=50
}

Проверь себя

📋 Тест по теме «Указатели» Тест по теме

Практические задания

Лёгкое Ручная проверка Заполните пропуск в коде (1)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

<_____>true</AllowUnsafeBlocks>
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (2)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

<Project _____="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>  <!-- нужная опция -->

  </PropertyGroup>

</Project>
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (3)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

// блок кода, использующий указатели
_____ 
{
	
}
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (4)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

unsafe void _____()
{

}
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (5)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

unsafe struct State
{ 

}

unsafe class _____
{

}
Войдите, чтобы отправить решение
Среднее Ручная проверка Восстановите код по памяти (1)
+20 XP

В этом фрагменте кода урока пропущены два ключевых элемента. Впишите оба пропущенных значения через запятую в порядке появления (например: x, 5).

<_____>true</_____>
Войдите, чтобы отправить решение
Среднее Ручная проверка Восстановите код по памяти (2)
+20 XP

В этом фрагменте кода урока пропущены два ключевых элемента. Впишите оба пропущенных значения через запятую в порядке появления (например: x, 5).

<_____ Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <_____>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>  <!-- нужная опция -->

  </PropertyGroup>

</Project>
Войдите, чтобы отправить решение
Среднее Ручная проверка Расставьте строки кода в правильном порядке
+20 XP

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

unsafe
}
{
// блок кода, использующий указатели
Войдите, чтобы отправить решение
Сложное Ручная проверка Объясните и модифицируйте пример из урока «Указатели»
+30 XP

Опишите своими словами, что делает приведённый пример кода из урока «Указатели», и предложите одно осмысленное изменение (например, другое входное значение или дополнительное условие). Приведите итоговый код.

<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
Войдите, чтобы отправить решение
Сложное Ручная проверка Найдите потенциальную проблему в коде урока «Указатели»
+30 XP

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

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>  <!-- нужная опция -->

  </PropertyGroup>

</Project>
Войдите, чтобы отправить решение
Мини-проект Ручная проверка Мини-проект по теме «Указатели»
+50 XP

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

Войдите, чтобы отправить решение
Домашнее задание Ручная проверка Домашнее задание по теме «Указатели»
+25 XP

Напишите собственную небольшую программу, применяющую материал темы «Указатели». Используйте не менее одной конструкции, показанной в примерах урока. Прикрепите код решения и краткое описание того, что он делает.

Войдите, чтобы отправить решение

Обсуждение (0)

Войдите, чтобы оставить комментарий.