Шрифт:
Чтобы передать массив функции, нужно просто передать имя этого массива, как при вызове функции 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'; }
Выход из цикла for происходит в тот момент, когда обнаруживается нуль- символ, что и делает последний оператор в этой функции.
Если написать функцию copyString с использованием указателей, то индексная переменная i не нужна. Версия с указателями показана в программе 13.13. #import < Foundation/Foundation.h> void copyString (char *to, char *from) { for (; *from != '\0'; ++from, ++to ) *to = *from; *to = '\0'; } int main (int arge, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; void copyString (char *to, char *from); char string [] = "Копируемая строка"2; char string2[50]; copyString (string2, string 1); NSLog(@"%s", string2); copyString (string2, "Строка-константа"); NSLog(@"%s", string2); [pool drain]; return 0; }
Вывод программы 13.13 Копируемая строка Строка-константа
В функции copyString определены два формальных параметра (to и from) как указатели на символы, а не на массивы символов, как в предыдущей версии copyString. Это показывает, каким образом эти две переменные будут использо-ваться в функции.
Затем происходит вход в цикл for (без начальных условий) для копирования строки, которую указывает параметр from (откуда) в строку, которую указывает параметр to (куда). На каждом шаге цикла выполняется увеличение указателей from и to на I. В результате указатель from указывает на следующий символ для копирования из исходной строки, и указатель to указывает место, в котором будет сохранен этот символ. Когда указатель from указывает на нуль-символ, происходит выход из цикла for. Затем функция помещает нуль-символ в конец скопированной строки.
В процедуре main функция copyString вызывается дважды. В первый раз в строку string2 копируется содержимое строки stringl, во второй раз в строку string2 копируется содержимое константной символьной строки. Константные символьные строки и указатели
Из copyString (string2, "Строка-константа");
следует, что если константная символьная строка передается как аргумент фун-кции, эта символьная строка фактически передается указателю. Это верно не только в данном случае. Обобщая, можно сказать, что если константная сим-вольная строка используется в Objective-C, то на эту символьную строку создается указатель.
Это может вызвать некоторую путаницу, но, как мы отмечали в главе 4, кон-стантные символьные строки называются строками встиле С (С-строками). Они не яатяются объектами. Объект константной символьной строки создается в том случае, если перед строкой поставлен знак например, @"This is okay", и мы не можем использовать один вид вместо другого.
Таким образом, если переменная textPtr объявлена как указатель на символ, char *textPtr;
оператор textPtr = "Символьная строка";
присваивает переменной textPtr указатель на константную символьную строку "Символьная строка". Будьте внимательны, чтобы отличать указатели на символь-ные строки от символьных массивов, поскольку приведенное выше присваивание нс подходит для символьного массива. Например, если определить text как массив символов с помощью следующего оператора char text[80];
то мы не сможем написать такой оператор, как text = "Это неправильно";
Единственный случай, когда Objective-C допускает такой тип присваивания для символьного массива —инициализация массива: char text[80] = "Это правильно";
При такой инициализации массива text не происходит создание указателя на символьную строку "Это правильно" внутри text. Вместо этого происходит запись самих символов с конечным нуль-символом в соответствующие элементы массива text.
Если text — это указатель на тип char, то в случае инициализации text с помо-щью оператора char *text = "Это правильно";