Краткие теоретические сведения. Любую переменную перед использованием в программе необходимо описать, т.е
Любую переменную перед использованием в программе необходимо описать, т.е. выделить для неё некоторый участок памяти. Причем для символьных переменных выделяется 1 байт памяти, для целочисленных – 2 байта, для представления вещественных переменных требуется 4 байта памяти.
char ch=’M’; int date=2008; float summa=0.03;
В данном примере &ch==1A2B, &date==1A2C, &summs==1A2E (& - операция получения адреса переменной). Адреса имеют целочисленные беззнаковые значения, и их можно обрабатывать как целочисленные величины. Для этих целей в языке Си++ введены переменные типа «указатель». Указатель – это переменная, значением которой служит адрес объекта конкретного типа. Значением указателя может быть заведомо не равное никакому адресу значение, принимаемое за нулевой адрес (константа NULL). В С++ различают три вида указателей – указатели на объект, на функцию и на void, отличающиеся свойствами и набором допустимых операций. Указатель не является самостоятельным типом, он всегда связан с каким-либо другим конкретным типом. Указатели необходимо определять и описывать с помощью разделителя «*». При этом необходимо сообщать, на объект какого типа ссылается описываемый указатель. Например:
char *z; /* z – указатель на объект символьного типа */ int *k, *i; /* k, i – указатели на объекты целого типа */ float *f; /* f – указатель на объект вещественного типа */ Разделитель «*» - это унарная операция обращения по адресу. Операндом операции разыменования всегда является указатель. Результат этой операции – тот объект, который адресует указатель-операнд. В языке Си++ допустимы следующие основные операции над указателями: 1) Присваивание. 2) Получение значения того объекта, на который ссылается указатель. 3) Получение адреса самого указателя. 4) Унарные операции изменения значения указателя (++ --). 5) Бинарные операции (+ -). 6) Операции отношения. 1) В операции присваивания слева от знака операции должно находиться имя указателя, а справа – адрес переменной, указатель, уже имеющий значение или константа NULL. char *z; int *i, *k, date=2008; i=&date; k=i; z=NULL; Для того, чтобы присвоить указателю одного типа значение указателя другого типа используют “приведение типов”. char *z; int *k; z=(char *)k; 2) Для того, чтобы получить значение, лежащее в ячейке памяти, на которую ссылается указатель, применяется операция *. float *ukaz, pp=54.678; ukaz=&pp; cout<<“Значение, содержащееся по указателю ukaz=”<< *ukaz;
3) Переменная типа указатель имеет имя, собственный адрес в памяти и значение. Выражение &имя указателя определяет, где в памяти размещен указатель. Содержимое этого участка памяти является значением указателя. float *u1, *u2; cout<<“\n Адреса указателей:\n * u1=”<<&u1<<”\n * u2=”<< &u2;
4) С помощью унарных операций ‘--‘ и ‘++’ числовые значения указателей меняются в зависимости от типа данных, с которыми связаны эти указатели. Если указатель связан с типом char, то при выполнении операций ’++’ и ’--’ его числовое значение меняется на единицу. Если указатель связан с типом int, то операции ++ и – изменяют числовые значения указателей на 2. Указатель, связанный с типом float унарными операциями ++ и – изменяется на 4. Таким образом, при изменении указателя на единицу указатель переходит к началу следующего или предыдущего поля той длины, которая определяется типом.
5) Две переменные типа указатель нельзя суммировать, однако к указателю можно прибавить целую величину. При этом значение указателя зависит от прибавляемой величины и от типа объекта, с которым связан указатель. char *t; int *a; float *b; /* t=1B2, a=AA5, b=C11 */ t=t+3; /* t=1B5 */ a=a+3; /* a= AAB */ b=b+3; /* b=C1D */ Операция вычитания применима не только к указателю и целой величине, но и к двум указателям одного типа. При этом определяется расстояние между размещением в памяти двух объектов. Например: int x[5], *i, *j, k; i=&x[4]; j=&x[0]; k=i-j; /* k=4, а не 8 */ 6) К указателям применяются операции отношения: < <= > >= ==!=. Таким образом, указатели можно использовать в отношениях. Однако, сравнивать указатели допустимо только с другими указателями того же типа или с константой NULL. В соответствии с синтаксисом языка Си++ имя массива без индексов является указателем-константой, т.е. адресом его первого элемента (адрес начала массива). Прибавив к имени массива целую величину, можно получить адрес соответствующего элемента. Таким образом, &z[i] и z+i – это две формы определения адреса одного и того же элемента массива, отстоящего на i позиций от его начала. При этом адрес следующего элемента в массиве будет зависеть от типа элементов массива. Операция индексирования одномерного массива z[i] может быть определена следующей эквивалентной записью *(z+i), обращение к элементам двумерного массива x[i][j] представляется в виде *(x[i]+j) или *(*(x+i)+j). Массив указателей фиксированных размеров вводится одним из следующих определений: тип *имя массива[размер]; тип *имя массива [ ]=инициализатор; тип *имя массива [размер]=инициализатор;
int data[6]; /* обычный массив */ int *pd[6]; /* массив указателей */ int *pi[ ]={ &data[0], &data[4], &data[2] };
|