|
|||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Упражнение. Что делает следующий фрагмент кода?Что делает следующий фрагмент кода? В чем состоит логическая ошибка? int *pi = new int(10);int *pia = new int[10];while (*pi < 10) { pia[*pi] = *pi; *pi = *pi + 1; }delete pi;delete[] pia;
Указатель – это объект, содержащий адрес другого объекта и позволяющий косвенно манипулировать этим объектом. Обычно указатели используются для работы с динамически созданными объектами, для построения связанных структур данных, таких, как связанные списки и иерархические деревья, и для передачи в функции больших объектов – массивов и объектов классов – в качестве параметров.
Вот несколько примеров: int *ip1, *ip2;complex<double> *cp;string *pstring;vector<int> *pvec;double *dp;Указатель обозначается звездочкой перед именем. В примере ниже lp – указатель на объект типа long, а lp2 – объект типа long: long *lp, lp2;В следующем случае fp интерпретируется как объект типа float, а fp2 – указатель на него: float fp, *fp2;Оператор разыменования (*) может отделяться пробелами от имени и даже непосредственно примыкать к ключевому слову типа. Поэтому приведенные определения синтаксически правильны и совершенно эквивалентны: string *ps;string* ps;Однако рекомендуется использовать первый вариант написания: второй способен ввести в заблуждение, если добавить к нему определение еще одной переменной через запятую: //внимание: ps2 не указатель на строку!string* ps, ps2;Можно предположить, что и ps, и ps2 являются указателями, хотя указатель – только первый из них.
Если значение указателя равно 0, значит, он не содержит никакого адреса объекта. Ниже приводятся примеры определения и использования указателей на int pi и pi2: //pi инициализирован нулевым адресомint *pi = 0;// pi2 инициализирован адресом ival int *pi2 = &ival; // правильно: pi и pi2 содержат адрес ival pi = pi2; // pi2 содержит нулевой адрес pi2 = 0; Указателю не может быть присвоена величина, не являющаяся адресом: // ошибка: pi не может принимать значение intpi = ivalТочно так же нельзя присвоить указателю одного типа значение, являющееся адресом объекта другого типа. Если определены следующие переменные: double dval;double *ps = &dval;то оба выражения присваивания, приведенные ниже, вызовут ошибку компиляции: // ошибки компиляции// недопустимое присваивание типов данных: int* <== double*pi = pdpi = &dval;Дело не в том, что переменная pi не может содержать адреса объекта dval – адреса объектов разных типов имеют одну и ту же длину. Такие операции смешения адресов запрещены сознательно, потому что интерпретация объектов компилятором зависит от типа указателя на них. Тип объекта, на который указывает void*, неизвестен, и мы не можем манипулировать этим объектом. Все, что мы можем сделать с таким указателем, – присвоить его значение другому указателю или сравнить с какой-либо адресной величиной.
Для того чтобы обратиться к объекту, имея его адрес, нужно применить операцию разыменования, или косвенную адресацию, обозначаемую звездочкой (*). Имея следующие определения переменных: int ival = 1024;, ival2 = 2048;int *pi = &ival;мы можем читать и сохранять значение ival, применяя операцию разыменования к указателю pi: // косвенное присваивание переменной ival значения ival2*pi = ival2;// косвенное использование переменной ival как rvalue и lvalue *pi = abs(*pi); // ival = abs(ival); *pi = *pi + 1; // ival = ival + 1; Когда мы применяем операцию взятия адреса (&) к объекту типа int, то получаем результат типа int* cout << "Значение ival\n" << "явное значение: " << ival << "\n" << "косвенная адресация: " << *pi << "\n" << "дважды косвенная адресация: " << **ppi << "\n" << endl; Указатели могут быть использованы в арифметических выражениях. Обратите внимание на следующий пример, где два выражения производят совершенно различные действия: int i, j, k;int *pi = &i;// i = i + 2*pi = *pi + 2;// увеличение адреса, содержащегося в pi, на 2 pi = pi + 2; К указателю можно прибавлять целое значение, можно также вычитать из него. Прибавление к указателю 1 увеличивает содержащееся в нем значение на размер области памяти, отводимой объекту соответствующего типа. Если тип char занимает 1 байт, int – 4 и double – 8, то прибавление 2 к указателям на char, int и double увеличит их значение соответственно на 2, 8 и 16. Как это можно интерпретировать? Если объекты одного типа расположены в памяти друг за другом, то увеличение указателя на 1 приведет к тому, что он будет указывать на следующий объект. Поэтому арифметические действия с указателями чаще всего применяются при обработке массивов; в любых других случаях они вряд ли оправданы. Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.005 сек.) |