Чтение онлайн

ЖАНРЫ

Программирование на Objective-C 2.0
Шрифт:

Если имеется массив tracts с объектами класса Fraction, то с помощью следующего оператора можно определить указатель на элементы массива tracts: Fraction **fractsPtr;

Такое же объявление используется для определения любого объекта класса Fraction.

Чтобы valuesRr указывал на первый элемент массива values, достаточно напи-сать строку valuesPtr = values;

В данном случае адресный оператор & не используется, поскольку компилятор Objective-C интерпретирует появление имени массива без индекса как указатель на первый элемент этого массива. Таким образом, мы получаем указатель на первый элемент массива values.

Эквивалентный способ создать указатель на начало массива values — приме-нить адресный оператор &

к первому элементу этого массива: valuesPtr = &values[0];

Чтобы вывести содержащийся в массиве tracts объект класса Fraction, на кото-рый указывает fractsPtr, нужно написать оператор [*fractsPtr print];

Реальные возможности применения указателей к массивам начинают дей-ствовать при необходимости перебора элементов массива. Если указатель valuesPtr определен, как описано выше, и указывает на первый элемент массива values, то для доступа к первому элементу массива values (то есть values[0]) можно использовать выражение *valuesPtr

Для доступа к values[3] с помощью переменной valuesPtr можно добавить 3 к valuesPtr и затем применить оператор косвенного доступа. *(valuesPtr + 3)

Таким образом, доступ к значению, содержащемуся в values[i], дает выраже-ние *(valuesPtr + i)

Например, чтобы присвоить элементу values[10] значение 27, можно написать следующее выражение values[10] = 27;

Или, используя valuesPtr, можно написать *(valuesPtr + 10) = 27;

Чтобы valuesPtr указывал на второй элемент массива values, нужно применить адресный оператор & к values[1] и присвоить результат переменной valuesPtr: valuesPtr = &values[1];

Если valuesPtr указывает на values[0], и нужно сделать так, чтобы он указывал на values[1], достаточно добавить 1 к значению valuesPtr: valuesPtr += 1;

Это вполне допустимое выражение в Objective-C, его можно использовать для указателей на любой тип данных.

В общем случае, если а — массив элементов типа х, рх — указатель на х, i и п — целые константы, то в выражении рх = а;

рх указывает на первый элемент а, и выражение *{рх + i)

дает доступ к значению, содержащемуся в a[i]. Кроме того, в выражении рх += п;

рх указывает на п следующих элементов в массиве, независимо от их типа данных.

Предположим, что fractsPtr указывает на дробь (fraction), содержащуюся в массиве дробей. Ее нужно сложить с дробью, содержащейся в следующем элс- менте этого массива, и прис воить результат объекту result класса Fraction. Для этого можно написать: result = [*fractsPtr add: *(fractsPtr +1)];

Операторы приращения (++) и уменьшения (—) особенно удобны при работе с указателями. Применение к указателю оператора (++) дает такой же результат, как прибавление к указателю 1, а оператор уменьшения (—) действует также, как вычитание 1 из указателя. Таким образом, если textPtr определен как указатель на тип char и указывает на начало массива элементов типа char с именем text, то в результате оператора ++textPtr;

textPtr будет указывать на следующий си мвол в массиве text, то есть на text[1 ]. Аналогичным образом, в результате оператора --textPtr;

textPtr будет указывать на предыдущий символ в массиве text (если, конечно, textPtr не указывал на начало массива text перед выполнением этого оператора).

В Objective-C вполне допустимо сравнение двух переменных-указателей. Это особенно полезно при сравнении двух указателей на элементы одного массива. Так можно убедиться, что указатель valuesPtr не указывает дальше конца массива, содержащего 100 элементов. Для этого нужно сравнить этот указатель с ука-зателем на последний элемент массива. Например, выражение valuesPtr > &values[99]

будет иметь значение TRUE (ненулевое значение), если valuesPtr указывает даль-ше последнего элемента массива values, и будет иметь значение FALSE (нулевое значение) в противном случае. В соответствии с предыдущим

описанием мы можем заменить это выражение на его эквивалент valuesPtr > values + 99

values без индекса — это указатель на начало массива values. (Эквивалентно &values[0].)

В программе 13.12 показано использование указателей на массивы. Функция arraySum вычисляет сумму целых элементов, содержащихся в массиве. // Функция для вычисления суммы элементов, содержащихся в массиве целого типа #import <Foundation/Foundation.h> int arraySum (int array[], int n) { int sum = 0, *ptr; int *arrayEnd = array + n; for ( ptr = array; ptr < array End; ++ptr) sum += *ptr; return (sum); } int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; int arraySum (int array[], int n); int values[10] = { 3, 7, -9, 3,6, -1, 7, 9, 1, -5 }; NSLog (@"The sum is %i", arraySum(values, 10)); [pool drain]; return 0; }

Вывод программы 13.12 The sum is 21 (Сумма равна 21)

Внутри функции arraySum определен указатель arrayEnd на тип int, который указывает «ячейку» непосредственно вслед за последним элементом массива. За-тем для последовательного перебора элементов массива используется цикл for. При входе в цикл ptr указывает на начало массива. На каждом шаге цикла к сумме прибавляется элемент массива, на который указывает ptr. Затем в цикле for значение ptr наращивается, чтобы указывать на следующий элемент массива. Когда ptr указывает «ячейку» после конца массива, происходит выход из цикла for, и значение sum возвращается вызывающей процедуре. Это массив или это указатель?

Чтобы передать массив функции, нужно просто передать имя этого массива, как при вызове функции arraySum. Но мы говорили, что для создания указателя на массив достаточно задать имя этого массива. Из этого следует, что при вызове функции arraySum функции передается указатель на массив values. Именно это и происходит, поэтому мы можем изменять элементы массива внутри функции.

Но если функции перелается указатель на массив, то почему формальный параметр внутри функции не объявлен как указатель? Иначе говоря, почему при объявлении array в функции arraySum не используется следующее объявление: int *array;

Не следует ли все обращения к массиву вну три функции выполнять с помо-щью переменных-указателей?

Чтобы ответить на эти вопросы, мы должны сначала вернуться к тому, что уже говорили об указателях и массивах. Если valuesPtr указывает на тип элемента, содержащегося в массиве с именем values, то выражение (valuesPtr + i) эквива-лентно выражению valuesfi] в предположении, что valuesPtr сначала указывал на начало массива values. Из этого следует, что мы можем использовать выражение (values + i) для обращения к i-му элементу массива values. В общем случае, если х — массив любого типа, то выражение x[i] всегда можно записать в эквивалентной форме *{х + i).

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

Если использовать индексы для доступа к элементам массива, то соответ-ствующий формальный параметр нужно объявить как массив. Если использовать аргумент как указатель на массив, то его нужно объявить как указатель. Указатели на символьные строки

Чаще всего указатель на массив используется как указатель на символьную стро-ку. Чтобы показать, насколько просты в работе указатели на символьные строки, напишем функцию с именем copyString для копирования одной строки в другую. Используя обычные методы написания такой функции с помощью индексирования массивов, можно составить следующий код: void copyString (char to[], char from[]) { int i; for (i = 0; fromp] != '\0'; ++i) to[i] = from[i]; to[i] = '\0'; }

Поделиться с друзьями: