Указатели и массивы. Пример. Адресные операции
Указатели (или ссылки) используются для представления и обработки адресных данных. В языке С существует сильная взаимосвязь между указателями и массивами, и обычно их рассматривают в едином контексте.
Указатели
Указатели (ссылки) являются в языке типизированными. Они всегда ссылаются на объекты предопределенного типа, за исключением, когда явно указан в декларации тип void.
Пример
int *p; /*указатель на объекты типа int*/
double *pp; /*указатель на объект типа double*/
void *pnt; /*указатель на объект любого типа*/
Далее в программе может быть выполнено:
pnt = pp;
Но тогда обращение к pnt в программе должно быть такое:
…(double*)pnt …
или
pnt = p;
и обращение
…(int*)pnt…
То, что в скобках – это оператор приведения типа. В последнем случае void* к типу int*.
К указателям применима в выражениях операция *, которая дает значение объекта, на который ссылается указатель.
Пример
int x = 1;
int y, *px = &x; /* px указывает на переменную x */
……….
y = *px+1; /* y присваивается значение 2*/
*px = *px + y; /* x получает значение 3 */
К значению, на которое ссылался указатель px, добавилась 1, и результат был присвоен переменной y.
Двойственной к операции «*» является операция «&», вычисляющая адрес переменной.
Пример
int i;
float x;
char name [80];
scanf(“%d%f%s”, &i, &x, name);
Если во входном потоке содержатся символы: 10 0.3е-2 petroff, то эти значения будут присвоены соответствующим переменным i, x, name.
Функция scanf() обеспечивает форматируемый ввод. 1-й аргумент всегда строка формата. Возвращает всегда количество вводимых элементов (но не символов). Таким образом, может быть организован контроль по вводу. В примере форматы для ввода целого, вещественного и строки символов.
Параметры функции scanf() должны быть ссылками, т.е. содержать адреса переменных, куда будут вводиться данные. Это обусловлено тем, что простые базовые данные передаются по значению, и чтобы записать в переменную значение, в функцию необходимо передать ее адрес, name – это массив. При указании имени массива в выражении всегда вычисляется его адрес и поэтому для массива операция «&» не требуется.
Адресные операции
& - вычисление адреса переменной,
* - доступ к значению переменной через ее адрес, или доступ к некоторой ячейке памяти через адресное выражение.
Пример
double *dp, *func();
dp – указатель, принимающий адрес на (переменные или ячейки, хранящие) тип double,
func() – функция, выдающая указатель на (переменную или ячейку, хранящую) тип double.
Пример
int y, var = 1, *ptr = (int*)200, *ptr1 = &var;
ptr – инициализируется начальным значением 200;
ptr1 – инициализируется адресом переменной var.
…………………………………….
y = *ptr1+1;
……………………………………..
// *ptr1 – извлекается значение по адресу, который содержится в ptr1.
Таким образом, если у будет равно 2.
Пример
Если теперь выполнить:
(*ptr1) = 2;
то переменной var будет присвоено значение 2. Здесь скобки можно и неуказывать, так как приоритет * выше, чем у =.
Пример
*ptr1++; /*увеличение значения указателя на 2 байта*/
Теперь ptr1 будет ссылаться на ячейку, расположенную «за переменной» var.
Возможно, теперь ptr1 ссылается на защищенную область памяти.
Пример
(*ptr1)++; /* увеличение на 1 значения переменной var,
если считать, что предыдущий пример не принимаем во внимание */
Родовой указатель
Таким указателем считается указатель типа void*. Когда void – указатель используется в выражениях, надо явно указать компилятору, к какому конкретно типу приводится этот указатель, что позволит правильно сформировать операции доступа к ячейкам памяти через этот указатель.
Пример
unsigned long block = 0xffecddccL;
void *ptr = █
char ch;
unsigned two_bytes;
long int four_bytes;
ch = *(char*)ptr;
two_bytes = *(unsigned*) ptr;
four_bytes = *(long int*) ptr;
В результате в ch пересылается младший байт переменной block, то есть ch = 0xcc. В переменную two_bytes – 2 байта, - 0xddcc. В переменную four_bytes – 4 байта, - 0xffeeddcc.
Одно из назначений указателей – это возможность воздействия на переменные, расположенные вне тела функции.
Пример
Обмен значениями между двумя переменными. Это характерный пример побочного эффекта:
void swap(int *px, int *py)
{ int tmp;
temp =*px;
*px = *py;
*py = temp;
}
Дата добавления: 2016-05-26; просмотров: 1616;