Урок 7.1.6. Адресная арифметика

7.1.6. Адресная арифметика

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

1. Присваивание. Указателю можно присвоить значение адреса. Любое число, присвоенное указателю, трактуется как адрес памяти:

int *u,*adr;
int N;
u = &N;               // указателю присвоен адрес переменной N 
adr = (int *)0х00FD;  // указателю присвоен 16-теричный адрес,  
                      // не рекомендуется так делать

2. Взятие адреса. Так как указатель является переменной, то для получения адреса памяти, где расположен указатель, можно использовать операцию взятия адреса &:

int *a,*b;
 
a = &b;  // указателю a присвоен адрес указателя b

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

int *uk;
int n;
int m = 5;
uk = &m;      // uk присвоен адрес переменной m     
n = *uk;      // переменная n примет значение 5 
*uk = -13;    // переменная m примет значение -13

4. Преобразование типа. Указатель на объект одного типа может быть преобразован в указатель на другой тип. При этом следует учитывать, что объект, адресуемый преобразованным указателем, будет интерпретироваться по-другому. Операция преобразования типа указателя применяется в виде (<тип> *)<указатель> :

int i, *ptr;
i = 0x8e41;
ptr = &i;
printf("%d\n", *ptr); // печатается значение int:-29119 (0x8e41)
printf("%d\n", *((char *)ptr)); // ptr преобразован к типу сhar, 
                                // извлекается 1 байт и его двоичный код
                                // печатается в виде десятичного числа,  
                                // печатается: 65 */

Преобразование типа указателя чаще всего применяется для приведения указателя на неопределенный тип данных void к типу объекта, доступ к которому будет осуществляться через этот указатель.

5. Определение размера. Для определения размера указателя можно использовать операцию размер в виде sizeof(<указатель>). Размер памяти, отводимой компилятором под указатель, зависит от модели памяти. Для близких указателей операция sizeof дает значение 2, для дальних 4.

6. Сравнение. Сравнение двух указателей любой из операций отношения имеет смысл только в том случае, если оба указателя адресуют общий для них объект, например, строку или массив.

7. Индексация. Указатель может индексироваться применением к нему операции индексации, обозначаемой в Си квадратными скобками [ ]. Индексация указателя имеет вид <указатель>[<индекс>], где <индекс> записывается целочисленным выражением.

Возвращаемым значением операции индексации является данное, находящееся по адресу, смещенному в б?льшую или меньшую сторону относительно адреса, содержащегося в указателе в момент применения операции. Этот адрес определяется так: (адрес в указателе) + (значение <индекс>) * sizeof(<тип>), где <тип> – это тип указателя.

Из этого адреса извлекается или в этот адрес посылается, в зависимости от контекста применения операции, данное, тип которого интерпретируется в соответствии с типом указателя. Рассмотрим следующий пример:

int *uk1;
int b,k;
uk1 = &b; // в uk1 адрес переменной b 
k = 3;
b = uk1[k];  // переменной b присваивается значение int, 
             // взятое из адреса на 6 большего, чем 
             // адрес переменной b;  в uk1 адрес не изменился
uk1[k] = -14;  // в адрес на 6 больший, чем адрес переменной b, 
               // записывается -14

Операция индексации не изменяет значение указателя, к которому она применялась.

8. Увеличение/уменьшение. Если к указателю применяется операция увеличения ++ или уменьшения --, то значение указателя увеличивается или уменьшается на размер объекта, который он адресует:

long b;       // b – переменная типа int длиной 4 байта 
long *ptr;    // ptr – указатель на объект int длиной 4 байта
ptr = &b;      // в ptr адрес переменной b 
ptr++;        // в ptr адрес увеличился на 4 
ptr--;        // в ptr адрес уменьшился на 4

9. Сложение. Одним из операндов операции сложения может быть указатель, а другим операндом обязательно должно быть выражение целого типа. Операция сложения вырабатывает адрес, который определяется следующим образом:  (адрес в указателе) + (значение int_выражения)*sizeof(<тип>), где <тип> это тип данных, на которые ссылается указатель.

double d;
int n;
double *uk;
uk = &d;    // в uk адрес переменной d 
n = 3;
uk = uk+n;   // в результате выполнения операции сложения, 
             // а затем операции присваивания, в uk новый 
             // адрес на 24 больше, чем предыдущий 
uk=n+uk;     // в uk адрес увеличился еще на 24

10. Вычитание. Левым операндом операции вычитания должен быть указатель, а правым должно быть выражение целого типа. Операция вычитания вырабатывает адрес, который определяется так: (адрес в указателе) - (значение int_выражения)*sizeof(<тип>).

К указателям можно применять только описанные операции и операции, которые выражаются через них, например, разрешается к указателю применить операцию uk += n; , так как ее можно выразить через uk = uk+n; . Следующие операции недопустимы с указателями:

  • сложение двух указателей;
  • вычитание двух указателей на различные объекты;
  • сложение указателей с числом с плавающей точкой;
  • вычитание из указателей числа с плавающей точкой;
  • умножение указателей;
  • деление указателей;
  • поразрядные операции и операции сдвига;

 

рассказать друзьям и получить подарок

Оставить комментарий

Ваш email не будет опубликован. Обязательные поля отмечены *

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Translate Переводчик

Подписка на новости

SmartResponder.ru
Ваш e-mail: *
Ваше имя: *

Хостинг для Wordpress сайтов