Программирование >>  Обработка исключительных ситуаций 

1 ... 113 114 115 [ 116 ] 117 118 119 ... 142


Небезопасный код 351

4. Выделение области памяти в стеке и присваивание ее адреса указателю: int* s = stackalloc int [10];

Здесь операция stackalloc выполняет выделение памяти под 10 величин типа int (массив из 10 элементов) и записывает адрес начала этой области памяти в переменную s, которая может трактоваться как имя массива.

ПРИМЕЧАНИ Е-

Специальных операций для выделения области динамической памяти (хипа) в С# не предусмотрено. В случае необходимости можно использовать, например, системную функцию НеарАПос (пример см. в спецификации языка).

Операции с указателями

Все операции с указателями выполняются в небезопасном контексте. Они перечислены в табл. 15.1.

Таблица 15.1. Операции с указателями

Операция Описание

Разадресация - получение значения, которое находится по адресу, хранящемуся в указателе

> Доступ к элементу структуры через указатель

[] Доступ к элементу массива через указатель

& Получение адреса переменной

++. -- Увеличение и уменьшение значения указателя на один адресуемый

элемент

+, - Сложение с целой величиной и вычитание указателей

==, ! = ,<>,< = ,>= Сравнение адресов, хранящихся в указателях. Выполняется как сравнение беззнаковых целых величин

stackalloc Выделение памяти в стеке под переменную, на которую ссылается

указатель

Рассмотрим примеры применения операций. Если в указатель занесен адрес объекта, получить доступ к этому объекту можно с помощью операций разадреса-ции и доступа к элементу.

Операция разадресации, или разыменования, предназначена для доступа к величине, адрес которой хранится в указателе. Эту операцию можно использовать как для получения, так и для изменения значения величины, например:

int а = 5; целая переменная

int* р = &а; инициализация указателя адресом а

Console.WriteLineC *р ): операция разадресации, результат: 5

Console.WriteLineC + + (*р) ) ; результат: б

int[] b = new int[] {10, 20, 30, 50}; массив



352 Глава 15. Дополнительные средства С#

fixed ( int* t = b ) инициализация указателя адресом начала массива

int* z = t; иницализация указателя значением другого указателя

for (int i = 0; i < b.Length; ++i )

t[i] += 5; доступ к элементу массива (увеличение на 5) *z += 5; доступ с помощью разадресации (увеличение еще на 5)

++z; инкремент указателя

Console.WriteLineC &t[5] - t ); операция вычитания указателей

Оператор fixed фиксирует объект, адрес которого заносится в указатель, для того чтобы его не перемещал сборщик мусора и, таким образом, указатель остался корректным. Фиксация происходит на время выполнения блока, который записан после круглых скобок.

В приведенном примере доступ к элементам массива выполняется двумя способами: путем индексации указателя t и путем разадресации указателя z, значение которого инкрементируется при каждом проходе цикла для перехода к следующему элементу массива.

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

Арифметические операции с указателями (сложение с целым, вычитание, инкремент и декремент) автоматически учитывают размер типа величин, адресуемых указателями. Эти операции применимы только к указателям одного типа и имеют смысл в основном при работе со структурами данных, элементы которых раз-м$щены в памяти последовательно, например, с массивами.

Инкремент перемещает указатель к следующему элементу массива, декремент - к предыдущему. Фактически значение указателя изменяется на величину sizeof (тип), где sizeof - операция получения размера величины указанного типа (в байтах) . Эта операция применяется только в небезопасном контексте, с ее помощью можно получать размеры не только стандартных, но и пользовательских типов данных. Для структуры результат может быть больше суммы длин составляющих ее полей из-за выравнивания элементов.

Если указатель на определенный тип увеличивается или уменьшается на константу, его значение изменяется на величину этой константы, умноженную на размер объекта данного типа, например:

short* р; ...

р++; значение р увеличивается на 2

long* q;

q++; значение q увеличивается на 4



Небезопасный код 353

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

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

*р++ =10;

Поскольку инкремент постфиксный, он выполняется после выполнения операции присваивания. Таким образом, сначала по адресу, записанному в указателе р, будет записано значение 10, а затем указатель увеличится на количество байтов, соответствующее его типу. То же самое можно записать подробнее:

*р = 10; Р+ + ;

Выражение (*р)++, напротив, инкрементирует значение, на которое ссылается указатель.

В следующем примере каждый байт беззнакового целого числа х выводится на консоль с помощью указателя t:

uint х = 0xAB10234F;

byte* t = (byte*)&x;

for ( int i = 0; i < 4: ++i )

Console.Write( {0:X} *t++ ); результат: 4F 23 10 AB

Как видите, первоначально указатель t был установлен на младший байт переменной х. Листинг 15.1 иллюстрирует доступ к полю класса и элементу структуры:

Листинг 15.1. Доступ к полю класса и элементу структуры с помощью указателей using System;

namespace ConsoleApplicationl

class A

{ public int value -. 20; } struct В

{ public int a; }

class Program

unsafe static void MainO

A n = new AO ;

fixed ( int* pn = &n.value ) + + (*pn);

Console.WriteLineC n = + n.value ); результат: 21

В b;

продолжение x

В* pb = &b;



1 ... 113 114 115 [ 116 ] 117 118 119 ... 142

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика