Текст опубликован в личном блоге и его автор не имеет отношения к администрации сайта
int var1, *ptr;
приводит к появлению переменной varl и указателя-пере-менной ptr.
int var1, *ptr1 = (int *) 200, *ptr2 = &var1;
Здесь описаны две переменные-указателя ptrl и ptr2; ptrl получает начальное значение 200, а ptr2 в качестве начального значения - адрес, по которому в памяти хранится varl. При инициализации указателя ptrl константой выполняется явное приведение к типу "указатель на целое". Это избавляет от предупреждения о немобильности инициализации.
*ptrl=*ptr2+4;
можно интерпретировать так: взять содержимое памяти по адресу, равному значению указателя ptr2, прибавить к этому содержимому 4, а результат поместить по адресу, равному значению указателя ptrl. Число байтов, извлекаемых из памяти и участвующих в операции, определяется компилятором исходя из типа, на который указатель "указывает". В то же время будет ошибкой запись типа
*234=var1;
так как в левой части оператора присваивания записывается адрес константы. Но константа в Си не имеет адреса в памяти.
var1=&0xff00;
2) нельзя определить адрес значения, получаемого при выполнении арифметического выражения, включающего знаки +, -, /, * и т. п. Например, некорректным является выражение
int var1, *ptr;
pt=&( var1 *3);
3) нельзя определить адрес переменной, описанной как register. Например, будет ошибкой попытка определить адрес varl:
unsigned register var1;
unsigned int * ptr;
ptr=&var1;[code]Сам указатель-переменная тоже имеет адрес. Поэтому, например, корректным будет такой фрагмент:[code]int var1, *ptr1,*ptr2=&var1;
ptr1=(int*)&ptr2;
Здесь описываются два указателя-переменные и ptr2 инициализируется значением адреса переменной varl. Затем ptrl присваивается значение адреса, по которому в памяти располагается ptr2.
unsigned long block = OxffeeddccL;
void* ptr=█
char ch;
unsigned two bytes;
long int four bytes;
ch = * (char*) ptr;
two_bytes = *( unsigned*) ptr;
fowbytes = * (long int *) ptr;
Указатель-переменная ptr инициализируется значением адреса первого байта переменной block. При выполнении присваивания компилятору необходимо знать размер объекта справа от знака =. Эту информацию сообщают компилятору операции приведения типа void * к типу (char *), (unsigned *), (long int *). В первой операции присваивания операнд слева – это первый байт переменной block. Поэтому переменная ch становится равной 0хСС. (Напомним, что младший байт всегда располагается в памяти по меньшему адресу.) Во второй операции = операнд слева – это младшее слово переменной block и, следовательно, переменная two_bytes станет равна 0xDDCC. После третьей операции присваивания four_bytes станет равной 0xFFEEDDCC.
аrrау==&аrrау[0],
((array + i) == &аггау [i]).
Использование указателей дает несколько более короткий код программы и в ряде случаев позволяет обойтись без дополнительных переменных, используемых в качестве индексов.
matrix[0]= =&matrix[0][0],
matrix[1]= =&matrix[1][0],
matrix[2]= =&matrix[2][0].
Как и для одномерных массивов, доступ к элементам двухмерного массива может осуществляться по индексу или с помощью механизма указателей. В последнем случае "точкой отсчета" может быть как самый первый элемент массива, так и первый элемент каждой из строк, т. е. могут использоваться как указатель-константа, задаваемый именем массива, так и указатели на строки массива. Например, для двухмерного массива m правомерны следующие способы индексации для доступа к ij-му элементу массива:
m[i][j],
*(m[i]+j)),
*(*(т + i) +j)).
Элементы массива могут иметь любой тип, в том числе и быть указателями-переменными. Наиболее часто массивы указателей используются для компактного расположения в памяти строк текста, структурных переменных и других "протяженных" объектов данных. Особенно удобны массивы указателей при динамическом управлении памятью.
char * messages[20];
Каждый элемент массива messages имеет тип char *. Число байтов памяти, занимаемых элементом, зависит от модели памяти (2 или 4 байта). Приведем пример описания массива указателей с его инициализацией:
char * messages[ ] = {"Не открыт файл",
"Ошибка ввода",
"Диск",
"Тайм-аут",};
Компилятор резервирует место для четырех указателей. Они получают начальное значение, равное адресу начала в памяти соответствующих строковых литералов. Существует принципиальное различие в расположении в памяти массива указателей и, на первый взгляд, подобного ему двухмерного массива типа char, например, такого:
char array [ ][16] = { "Не открыт файл",
"Ошибка ввода",
"Диск",
"Тайм-аут", };
Преимущества использования массивов указателей в том, что появляется возможность манипулировать не самими объектами, а только их адресами, что дает значительный выигрыш в скорости выполнения программы. Объекты, с которыми работает программа, могут располагаться в выделяемой динамически области памяти.
int data = 5; / * переменная типа int */
int * ptr= &data; / * указатель на переменную типа int */
int ** ptr_ptr = &ptr; /* указатель на указатель */
int*** ptr_ptr_ptr=&ptr_ptr; /* указатель на указатель */
Для доступа к переменной data теперь может использоваться операция взятия содержимого по адресу. Например, все приведенные ниже выражения присваивают переменной data значение 10:
data =10;
*ptr =10;
** ptr_ptr = 10;
*** ptr_ptr_ptr= 10;
Для доступа к памяти через указатели на указатели можно использовать и индексы. Например, эквивалентны следующие ссылки на переменную data:
ptr[0] и *ptr,
ptr_ptr[0][0] и **ptr_ptr,
ptr_ptr_ptr[0][0][0] и ***ptr_ptr_ptr.