|
Программирование >> Обработка исключительных ситуаций
Небезопасный код 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;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |