Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
16
Добавлен:
17.04.2015
Размер:
62.9 Кб
Скачать

13. Константы и ссылки/указатели

Константы очень интересно сочетаются с указателями и ссылками. По крайней мере, это интересно выглядит. Посмотрите сами:

const int *foo

или

int const *foo

Указатель на const int. Значение указателя изменить можно (так, чтобы он указывал на что-нибудь другое), а вот значение переменной, на которую он указывает, менять нельзя.

int *const foo = &x

Константный (неизменный) указатель на int. Значение указателя менять нельзя (прям как будто это ссылка, а не указатель). Значение того, на что он указывает, менять можно. Заметьте, что константный указатель обязательно инициализировать, как и любую другую константу.

const int *const foo = &x

Смесь двух предыдущих пунктов. Ничего нельзя изменить: ни значение указателя, ни значение того, на что он указывает. Опять же, инициализация обязательна.

У ссылок разнообразия значительно меньше, ибо «указательная» часть ссылки и так всегда константна. Значит, бывает только:

const int &foo = x

Ссылка на int, который мы (с помощью этой ссылки) не сможем изменить.

Для константных ссылок можно:

const int& i = 1; // равносильно

int __tmp = 1;

const int& i = __tmp;

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

int &foo = x;

int *const bar = &x;

Фактически, после этого foo и bar отличаются только синтаксически (везде нужно писать *bar, но просто foo), и если мы везде заменим foo на *bar или наоборот, ничего не изменится.

Операции взятия адреса объекта и разыменования указателя - взаимно обратны.

TYPE objx;

TYPE *ptrx = &objx; /* инициализируем адресом objx */

*(&objx) = objx;

&(*ptrx) = ptrx;

Вот пример того, как можно заменить условный оператор условным выражением (это удастся не всегда):

if(c) a = 1;

else b = 1;

Предупреждение: такой стиль не способствует понятности программы и даже компактности ее кода.

#include <stdio.h>

int main(int ac, char *av[]){

int a, b, c;

a = b = c = 0;

if(av[1]) c = atoi(av[1]);

*(c ? &a : &b) = 1; /* !!! */

printf("cond=%d a=%d b=%d\n", c, a, b);

return 0;

}

Каким образом инициализируются по умолчанию внешние и статические массивы? Инициализируются ли по умолчанию автоматические массивы? Каким образом можно присваивать значения элементам массива, относящегося к любому классу памяти?

Указатель может быть константой, то есть его значение не может быть изменено во время работы программы.

// Указатель константа

#include<stdio.h>

#include<stdlib.h>

#include<math.h>

int main()

{

int i=5,k;

const int *pi=&i;

k=*pi;

printf("i= %i pi= %u k= %i\n",i,pi,k);

system("pause");

return 0;

}

//i=5 pi=26867883 k=5

// Задание инициация разадресация вывод переменных

#include<stdio.h>

#include<stdlib.h>

#include<math.h>

int main()

{

int i1,i2;

int *pi1,*pi2;

pi1=&i1;

i1=5;

i2=*pi1;

pi2=&i2;

printf("Содержимое i1=%i Адрес i1=%u Содержимое i2=%i Адрес i2=%u\n",i1,pi1,i2,pi2);

char c1,c2;

char *pc1,*pc2;

pc1=&c1;

c1='s';

pc2=&c2;

c2=*pc1;

printf("Содержимое c1=%c Адрес c1=%u Содержимое c2=%c Адрес c2=%u\n",c1,pc1,c2,pc2);

float f1,f2;

float *pf1,*pf2;

pf1=&f1;

f1=5.65;

pf2=&f2;

f2=*pf1;

printf("Содержимое f1=%f Адрес c1=%u Содержимое f2=%f Адрес f2=%u\n",f1,pf1,f2,pf2);

system("pause");

return 0;

}

//i1= 5 pi1=2686788 i2= 5 pi2=2686784

//c1= s pc1=2686775 c2=s pc2=2686774

//f1=5.65 pf1=2686760 f2=5.65 pf2=2686756

// Применение указателей в программе

#include<stdio.h>

#include<stdlib.h>

#include<math.h>

#define pi 3.1415

int main()

{

int a,b,c,*pa=&a,*pb=&b,*pc=&c;

float d,*pd=&d;

printf("Ввести числа а и b\n");

scanf("%i%i",&a,&b);

c=*pa+*pb;

d=cos(pi*(*pa)/180);

printf(" %i + %i = %i \n",*pa,*pb,*pc);

printf("cos( %i )= %f \n",*pa,*pd);

system("pause");

return 0;

}

//18 5

// 21

// 0.95

15. Порядок выполнения операций над указателями.

С помощью комбинаций звездочек, круглых и квадратных скобок можно описывать составные типы и указатели на составные типы, например, в операторе

int *(*р[10])();

объявляется массив из 10 указателей на функции без параметров, возвращающих указатели наint.

По умолчанию квадратные и круглые скобки имеют одинаковый при-оритет, больший, чем звездочка, и рассматриваются слева направо. Для изменения порядка рассмотрения используются круглые скобки.

При интерпретации сложных описаний необходимо придерживаться правила «изнутри наружу»:

1) если справа от имени имеются квадратные скобки, это массив, если скобки круглые — это функция;

2) если слева есть звездочка,это указатель на проинтерпретированную ранее конструкцию;

3) если справа встречается закрывающая круглая скобка, необходимо применить приведенные выше правила внутри скобок, а затем переходить наружу;

4) в последнюю очередь интерпретируется спецификатор типа.

Для приведенного выше описания порядок интерпретации указан цифрами:

int *(*р[10])():