Указатели(Pointer) позволяют эффективно представлять сложные структуры данных, изменять значения, передаваемые в виде аргументов функциям и методам, а также проще и эффективнее работать с массивами.

В конце этой статьи мы расскажем, насколько они важны для реализации объектов в языке Objective-C.

Чтобы понять, как действуют указатели, вы должны сначала ознакомиться с понятием косвенного обращения(indirection). Мы часто встречаемся с этим понятием в повседневной жизни.

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

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

Понятие косвенного подхода можно применять и к указателями в Objective-C. Указатель(Pointer) — это средство косвенного доступа к значению определенного элемента данных. Рассмотрим, как действуют указатели. Определим переменную с именем count:

С помощью следующего объявления мы можем определить другую переменную с именем intPtr для косвенного доступа к значению переменной count.

Звездочка показывает, что переменная intPtr является указателем на тип int. Это означает, что программа будет использовать intPtr для косвенного доступа к значению одной или нескольких целых переменных.

Мы уже использовали в предыдущих программах оператор & при обращении к scanf. Этот унарный оператор, который называют адресным(address) оператором, создает указатель на переменную в Objective-C.

Например, если x — переменная определенного типа, то выражение &x является указателем(Pointer) на эту переменную. Если нужно, вы можете присвоить выражение &x любой переменной-указателю, объявленной как указатель на тип, которой имеет переменная x.

Оператор:

задает косвенную связь между intPtr и count. Адресный оператор & присваивает переменной intPtr не значение переменной count, а указатель на переменную count.

На рис.1 показана связь между intPtr и count. Линия со стрелкой показывает, что intPtr содержит не само значение count, а указатель на переменную count.

Указатели(Pointer) в Objective-CРис.1. Указатель на переменную целого типа

Чтобы указать содержимое count с помощью переменной-указателя intPtr, используется оператор косвенного обращения <звездочкой>(*). Если переменная x была определена с типом int, то оператор:

присвоит переменной x значение, которое указывается путем косвенного обращения через intPtr. Поскольку выше мы задали, что intPtr указывает на переменную count, результатом этого оператора будет присваивание переменной x значения, содержащегося в переменной count(10).

В программе 1.5 показано использование двух основных операторов для указателей: адресного оператора (&) и оператора косвенного обращения (*).

Программа 1.5:

Вывод программы 1.5:

Переменные count и x объявляются обычным образом как целые переменные. В следующей строке переменная intPtr объявляется как <указатель на тип int>. Эти две строки можно было бы объединить в одну:

После этого к переменной count применяется адресный оператор (&), результатом которого является создание указателя на эту переменную, который затем присваивается переменной intPtr.

Выполнение строки:

происходит следующим образом. Оператор косвенного обращения (*) сообщает системе Objective-C, что переменная intPtr содержит указатель на другой элемент данных. Этот указатель используется для доступа к нужному элементу данных, тип которого задан при объявлении переменной-указателя.

При объявлении переменной мы сообщили компилятору, что переменная intPtr указывает на целые элементы данных, поэтому компилятор <понимает>, что значение, указываемое выражением *intPtr, является целым. Кроме того, в предыдущей строке мы задали, что intPtr указывает на целую переменную count, поэтому это выражение представляет косвенный доступ к значению count.

В программе 1.6 иллюстрируются некоторые интересные свойства переменных-указателей. В ней используется указатель на символ.

Программа 1.6:

Вывод программы 1.6:

Символьная переменная «c» определяется и инициализируется со значением ‘Q‘. В следующей строке этой программы определяется переменная charPtr как <указатель на тип char>. Это означает, что любое значение, сохраняемое внутри этой переменной, следует интерпретировать как косвенное обращение(указатель) к символу.

Этой переменной можно присвоить начальное значение обычным образом. В этой программе переменной charPtr присваивается указатель на переменную «c«, и для этого к переменной «c» применяется адресный оператор &.

Эта инициализация приведет к появлению ошибки компилятора, если определить «c» после этого оператора, поскольку любая переменная должна быть объявлена раньше ссылки на эту переменную в любом выражении.

Объявление переменной charPtr и присваивание ее начального значения можно было бы представить в двух отдельных строках:

Но не:

как можно было бы предположить из объявления в одной строке.

Значение указателя в Objective-C не существует, пока мы не зададим, на какой элемент данных он указывает.

В строке первого вызова NSLog выводится содержимое переменной «c» и содержимое этой переменной, указанное с помощью charPtr. Поскольку мы задали, что charPtr указывает на переменную «c«, выводится и содержимое «c«, что подтверждается первой строкой вывода программы.

В следующей строке программы символьной переменной «c» присваивается символ ‘/’. Поскольку charPtr по-прежнему указывает на «c», в следующем вызове NSLog для значения *charPtr на терминал выводится новое значение переменной «c».

Это важно. Если значение charPtr не изменяется, то выражение *charPtr всегда означает доступ к значению «c». Таким образом, если изменяется значение переменной «c», то изменяется и значение выражения *charPtr.

Мы говорили, что если значение charPtr не изменено, то выражение *charPtr всегда является ссылкой на значение «c». Поэтому в выражении:

переменной «c» присваивается символ <левая круглая скобка>. Более формально символ ‘(‘ присваивается переменной, на которую указывает charPtr. Мы знаем, что это переменная «c», поскольку в начале программы мы присвоили charPtr указатель на «c».

Эти концепции являются ключом к пониманию действия указателей. Продумайте их снова, если что-то осталось неясным или вы что-то не поняли.