Программирование на Objective-C 2.0
Шрифт:
Объявление переменной charPtr и присваивание ее начального значения можно было бы представить в двух отдельных строках char *charPtr; charPtr = &с;
(Но не char *charPtr; *charPtr = &с;
как можно было бы предположить из объявления в одной строке.)
Значение указателя в Objective-C не существует, пока мы не зададим, на какой элемент данных он указывает.
В строке первого вызова NSLog выводится содержимое переменной с и со-держимое этой переменной, указанное с помощью charPtr. Поскольку мы задали, что charPtr указывает на переменную с, выводится и содержимое с, что под-тверждается первой строкой вывода программы.
В
Мы говорили, что если значение charPtr не изменено, то выражение *charPtr всегда является ссылкой на значение с. Поэтому в выражении *charPtr = '(';
переменной с присваивается символ «левая круглая скобка». Более формально символ '(' присваивается переменной, на которую указывает charPtr. Мы знаем, что это переменная с, поскольку в начале профаммы мы присвоили charPtr указатель на с.
Эти концепции являются ключом к пониманию действия указателей. Про-думайте их снова, если что-то осталось неясным. Указатели и структуры
Мы определил указатель для базовых типов данных, таких как int или char. Можно определить указатель и на структуру. Выше в этой главе мы определили структуру dale. struct date { int month; int day; int year; };
Мы определили переменные типа struct date, например, struct date todaysDate;
Мы можем также определить переменную-указатель на переменную типа struct date: struct date *datePtr;
Переменная datePtr может, например, указывать на переменную todaysDate с помощью оператора присваивания datePtr = StodaysDate;
После этот присваивания можно осуществлять косвенный доступ к любому из компонентов структуры date: (*datePtr).day = 21;
С помощью указателя datePtr в этом операторе задается значение дня струк-туры date, равное 21. Здесь нужны круглые скобки, поскольку оператор «точка» для компонента структуры имеет более высокий приоритет, чем оператор кос-венного обращения *.
Чтобы проверить значение месяца (month), хранящееся в структуре date, на которую указывает datePtr, можно использовать оператор if ((*datePtr).month == 12 )
Указатели на структуры используются настолько часто, что для них в языке имеется специальный оператор. Оператор указателя структуры -> (знаки «минус» и «больше») позволяет записывать выражения (*х).у
в более понятном виде: х->у
Таким образом, предыдущий оператор if можно записать в виде if (datePtr->month == 12)
Перепишем программу 13.6, где впервые показали использование структур, с применением указателей структур (программа 13.10). // Программа, показывающая использование указателей структур #import <Foundation/Foundation.h> int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; struct date { int month; int day; int year; }; struct date today, *datePtr; datePtr = &today; datePtr->month = 9; datePtr->day = 25; datePtr->year = 2009; NSLog (@"Today's date is %i/%i/%.2i.", datePtr->month, datePtr->day, datePtr->year % 100); (pool drain]; return 0; }
Вывод
программы 13.10 Today's date is 9/25/09. (Текущая дата - 25.9.09) Указатели, методы и функцииВы можете передавать указатель как аргумент методу или функции. Метод или функция может возвращать результат в виде указателя. Кстати, именно это про-исходит с методами alloc и init: они возвращают указатели. Более подробно мы обсудим этот вопрос в конце главы. А теперь рассмотрим программу 13.11. // Указатели как аргументы, передаваемые функциям #import <Foundation/Foundation.h> void exchange (int *pint1, int *pint2) { int temp; temp = *pint1; *pint1 = *pint2; *pint2 = temp; } int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; void exchange (int *pint1, int *pint2); int И = -5, i2 = 66, *p1 = &i1, *p2 = &i2; NSLog (@"i1 = %i, i2 = %i", i1, i2); exchange (p1, p2); NSLog (@"i1 = %i, i2 = %i", i1, i2); exchange (&i1, &i2); NSLog (@"i1 = %i, i2 = %i", i1, i2); [pool drain]; return 0; }
Вывод программы 13.11 i1 =-5, i2 = 66 i1 = 66, i2 = -5 i1 = -5, i2 = 66
Функция exchange выполняет обмен значений двух целых переменных, на которые указывают два ее аргумента. Внутри функции локальная целая переменная temp сохраняет одно из целых значений во время выполнения обмена. Ей присваивается целое значение, на которое указывает pintl. Затем целое значение, на которое указывает pint2, копируется в целую переменную, на которую указывает pintl. После этого значение temp сохраняется в целой переменной, на которую указывает pint2, и обмен значениями завершается.
В процедуре main определяются целые переменные И и i2 со значениями -5 и 66 соответственно. Затем определяются два указателя на тип int (pi и р2), которые указывают соответственно на И и 12. Программа выводит значения И и i2 и вызывает функцию exchange, передавая в качестве аргументов эти указатели (р1 и р2). Функция exchange выполняет обмен значения, содержащегося в целой пе-ременной, на которую указывает pi, со значением, содержащимся в целой пе-ременной, на которую указывает р2. Поскольку р1 указывает на il и р2 на i2, функция exchange обменивает местами значения И и i2. Вывод с помошью второго вызова NSLog показывает, что обмен выполняется правильно.
Второй вызов exchange выглядит несколько интересней. На этот раз аргумен-ты, передаваемые функции, являются указателями на И и i2, которые создаются непосредственно при обращении в результате применения к этим переменным адресного оператора &. Поскольку выражение &И представляет указатель на целую переменную И, это согласуется с типом первого аргумента для функции (указатель на целое значение). То же самое относится ко второму аргументу. Вывод этой программы показывает, что функция exchange правильно выполнила свою работу и обменяла значения И и i2.
Внимательно изучите программу 13.11. Она показывает ключевые концепции работы с указателями в Objective-C. Указатели и массивы
Если имеется массив с именем values, содержащий 100 целых элементов, то с помощью следующей строки можно определить указатель с именем valuesPtr, который можно использовать для доступа к целым элементам, содержащимся в этом массиве. int *valuesPtr;
Определяя указатель, который будет использоваться для указания элементов массива, мы не определяем его как «указатель на массив». Он определяется как указатель на тип элементов, содержащихся в массиве.