Программирование на Objective-C 2.0
Шрифт:
Напишем программу, которая определяет, является ли целое значение, которое вводит пользователь, четным или нечетным, и выводит соответствующее значение на терминал (см. программу 6.3). // Программа, определяющая, является ли число четным или нечетным #import <Foundation/Foundation.h> int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; int number_to_test, remainder; NSLog (@"Enter your number to be tested:"); scanf ("%i", &number_to_test); remainder = number_to_test % 2; if ( remainder == 0 ) NSLog (@"The number is even."); if ( remainder != 0 ) NSLog (@"The number is odd."); [pool drain]; return 0; }
Вывод программы 6.3 Enter your number to be tested: (Введите ваше число для проверки) 2455 The number is odd. (Число является нечетным)
Вывод программы 6.3 (повторный запуск) Enter your number to be tested: 1210 The number is even. (Число является четным)
После ввода числа вычисляется остаток отделения на 2. Первый оператор if проверяет, равно ли нулю значение этого остатка. Если да, то выводится сообщение «The number is even.» (Число является четным).
Второй оператор if проверяет значение этого остатка на неравенство нулю. Если да, то выводится сообщение, что число является нечетным.
Если выполняется первый оператор if, то второй оператор не должен выполняться, и наоборот. При написании программ концепция «иначе» («else») требуется настолько часто, что почти во всех современных языках программирования введена специальная конструкция для этой ситуации. В Objective-C это конструкция if-else, которая имеет следующий формат. if (выражение) программный оператор 1 else программный оператор 2
На
Оператор if-else можно вставить в предыдущую программу, заменив два оператора if на один оператор if-else. Эта новая конструкция в некоторой степени упрощает программу и делает ее более удобной для чтения. // Программа, определяющая, является ли число четным или нечетным (Версия 2) #import <Foundation/Foundation.h> int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; int number_to_test, remainder; NSLog (@"Enter your number to be tested:"); scanf ("%i", &number_to_test); remainder = number_to_test % 2; if ( remainder == 0 ) NSLog (@"The number is even."); else NSLog (@"The number is odd."); [pool drain]; return 0; }
Вывод программы 6.4 Enter your number to be tested: (Введите ваше число для проверки) 1234 The number is even. (Число является нечетным)
Вывод программы 6.4 (повторный запуск) Enter your number to be tested: 6551 The number is odd. (Число является четным)
He забывайте, что двойной знак равенства (==) - это проверка на равенство, а одинарный знак равенства — это оператор присваивания. Если случайно использовать оператор присваивания внутри оператора if, то может возникнуть множество проблем. Составные операции сравнения
До сих пор в операторах if использовались простые операции сравнения между двумя числами. В программе 6.1 сравнивалось значение числа с нулем, а в программе 6.2 выполнялось сравнение с нулем знаменателя дроби. Иногда необходимы более сложные проверки. Предположим, что нужно вычислить количество экзаменационных оценок в диапазоне от 70 по 79. В данном случае нужно сравнить значение оценки не с одним пределом, а с двумя (70 и 79), чтобы проверить, попадает ли она в указанный диапазон. В Objective-C имеется механизм для составных операторов сравнения этого типа. Составная операция сравнения (compound relational test) — это несколько операций сравнения, объединенных логическим оператором AND или 0R. Эти операторы представлены парой символов && или || (два вертикальных штриха). Н апример, следующий оператор увеличивает значение переменной grades_70_to_79 (оценки от 70 по 79), только если значение grade (оценка) больше или равно 70 и меньше или равно 79). if ( grade >= 70 && grade <= 79 ) ++grades_70_to_79; А следующий оператор вызывает выполнение оператора NSLog, если index меньше 0 или больше 99. if ( index < 0 || index > 99 ) NSLog (@"Error - index out of range"); (Ошибка - индекс вне диапазона) Составные операторы можно использовать в Objective-C для формирования очень сложных выражений. Не злоупотребляйте этим. Более простые выражения всегда проще читать и отлаживать.При формировании составных выражений сравнения можно неограниченно использовать круглые скобки, чтобы повысить удобство чтения выражений и избежать осложнений из-за ошибочных предположений о старшинстве операторов в выражении. (Оператор && имеет более низкий приоритет, чем любой арифметический оператор или оператор отношения, но более высокий приоритет, чем оператор ||.) Пробелы также повышают удобочитаемость выражения. Дополнительные пробелы вокруг операторов && и || визуально отделяют эти операторы от выражений, которые они связывают. Чтобы показать использование составных операций сравнения на конкретном примере, мы напишем программу, которая проверяет, является ли определенный год високосным, если он делится на 4 без остатка. Год, который делится на 100, не является високосным годом, если он не делится также на 400. Необходимо продумать, как проверять эти условия. Во-первых, можно сосчитать остатки (remainder) отделения года на 4, 100 и 400 и присвоить эти значения соответствующим переменным, например, rem_4, remJOO и rem_400. Затем можно проверить эти переменные, чтобы выяснить, отвечают ли эти остатки критериям високосного года. Можно сказать, что год является високосным, если он делится без остатка на 4 и не делится на 100, либо он делится без остатка на 400. На всякий случай убедитесь, что это определение эквивалентно предыдущему определению. Теперь, когда мы переформулировали определение, его реализация в виде программного оператора становится достаточно простой. if ( (rem_4 == 0 && remJOO != 0) || rem_400 == 0 ) NSLog (@"lt’s a leap year."); ("Это високосный год") Круглые скобки вокруг следующего подвыражения не обязательны. rem_4 == 0 && remJOO != О Оно будет оцениваться в таком порядке в любом случае, поскольку оператор && имеет более высокий приоритет, чем ||. В этом примере подходит и следующая проверка. if ( rem_4 == 0 && ( remJOO != О || remJOO == 0 )) Можно добавить перед этим оператором if несколько операторов объявления переменных и ввод пользователем значения года с терминала. Это программа 6.5, которая определяет, является ли год високосным. Программа 6.5 // Эта программа определяет, является ли год високосным import
int main (int argc, char argv[]) { NSAutoreleasePool pool = [[NSAutoreleasePool alloc] init]; int year, rem_4, remJOO, remJOO; NSLog (@"Enter the year to be tested:"); scant ("%i", &year); rem J = year % 4; remJOO = year % 100; remJOO = year % 400; if ( (rem 4 == 0 && remJOO != 0) || remJOO == 0 ) NSLog ((ant’s a leap year."); else NSLog (@"Nope, it’s not a leap year."); [pool drain]; return 0; } Вывод программы 6.5 Enter the year to be tested: (Введите год для проверки) 1955 Nope, it’s not a leap year. (Нет, это не високосный год) Вывод программы 6.5 (повторный запуск) Enter the year to be tested: 2000 It’s a leap year. (Это високосный год) Вывод программы 6.5 (повторный запуск) Enter the year to be tested: 1800 Nope, it’s not a leap year. (Нет, это не високосный год) В приведенных примерах вводится 1955-й год, который не является високосным, поскольку он не делится нацело на 4, 2000-й год, который является високосным, поскольку он делится нацело на 400, и 1800-й год, который не является високосным, поскольку он делится нацело на 100, но не на 400. В качестве последнего варианта следует проверить год, который делится нацело на 4, но не на 100. Выполните эту проверку самостоятельно. Objective-C дает программисту очень высокий уровень гибкости при формировании выражений. Например, в приведенной выше программе вместо вычисления промежуточных результатов rem_4, remJOO и rem_400 можно было бы сделать все непосредственно в операторе if: if (( year % 4 == 0 && year % 100 != О ) || year % 400 == 0 ) Использование пробелов для разделения отдельных операторов делает это выражение более удобным для чтения. Если игнорировать эти возможности и удалить необязательный набор круглых скобок, то получится следующее выражение: if(year%4==0&&year%100!=0)||year%400==0) Это выражение действует точно так же, как предыдущее выражение, однако дополнительные пробелы очень упрощают восприятие составных выражений. Вложенные операторы if
При рассмотрении общего формата оператора if мы указывали, что если результатом оценки выражения в круглых скобках является значение TRUE, то выполняется следующий оператор. Этим программным оператором может быть еще один оператор if, как в следующих строках. if ( [chessGame isOver] == NO ) ([игра в шахматы окончена] == НЕТ) if ( [chessGame whoseTurn] == YOU )([... чей ход] == ВАШ) [chessGame yourMove]; ([... ваш ход]) Если значение, возвращаемое после отправки сообщения isOver объекту chessGame, равно N0, то выполняется следующий оператор; в свою очередь, этот оператор является еще одним оператором if. Этот оператор if сравнивает значение, возвращаемое методом whoseTurn, со значением YOU. Если эти два значения равны, то объекту chessGame отправляется сообщение yourMove. Таким образом, сообщение yourMove отправляется только в том случае, если игра не окончена,
и это ваш ход. Эти операторы можно было бы записать с помощью составной операции сравнения: if ( [chessGame isOver] == N0 && [chessGame whoseTurn] == YOU ) [chessGame yourMove]; Обычно с вложенными операторами if используют предложение else, как показано ниже. if ( [chessGame isOver] == N0 ) ([игра в шахматы окончена] == НЕТ) if ( [chessGame whoseTurn] == YOU )([... чей ход] == ВАШ) [chessGame yourMove]; ([... ваш ход]) else [chessGame my Move]; ([... мой ход]) Сначала все выполняется, как и раньше, но если игра не окончена и ход не ваш, то выполняется предложение else. В результате сообщение myMove отправляется объекту chessGame. Если игра окончена, то пропускается весь следующий оператор if вместе с присоединенным к нему предложением else. Предложение else связано с оператором if, который проверяет значение, возвращаемое методом whoseTurn, а не с оператором if, который проверяет, окончена ли игра (chessGame isOver). Общее правило состоит в том, что предложение else всегда связывается с последним оператором if, не содержащим else. Можно продвинуться еще на один шаг и добавить предложение else к внешнему оператору if. Это предложение else выполняется, если игра окончена. if ( [chessGame isOver] == NO ) ([игра в шахматы окончена] == НЕТ) if ( [chessGame whoseTurn] == YOU )([... чей ход] == ВАШ) [chessGame yourMove]; ([... ваш ход]) else [chessGame myMove]; ([...мой ход]) else [chessGame finish]; (... конец) Конечно, система может интерпретировать этот оператор и по-другому. Например, если в предыдущем примере удалить первое предложение else, то оператор не будет интерпретироваться в соответствии с показанными отступами. if ( [chessGame isOver] == NO ) if ( [chessGame whoseTurn] == YOU ) [chessGame yourMove]; else [chessGame finish]; Вместо этого оператор будет интерпретироваться следующим образом: if ( [chessGame isOver] == NO ) if ( [chessGame whoseTurn] == YOU ) [chessGame yourMove]; else [chessGame finish]; Предложение else связывается с последним оператором if, не включающим else. Можно использовать фигурные скобки, чтобы связать else с внешним if, а не с внутренним. Фигурные скобки замыкают оператор if, который находится внутри них. Нужная последовательность задается с помощью следующего оператора. if ( [chessGame isOver] == NO ) { if ( [chessGame whoseTurn] == YOU ) [chessGame yourMove]; } else [chessGame finish]; Конструкция else ifВы уже видели, как действует оператор else при проверке двух возможных условий. Однако решения, которые приходится реализовать в программировании, не всегда ограничиваются выбором между двумя вариантами. Рассмотрим программу, которая выводит -1, если пользователь вводит отрицательное число; О, если число равно нулю; и 1, если число больше нуля. (Это реализация функции sign.) Очевидно, что в этом случае нужны три проверки: для отрицательных чисел, чисел, равных нулю, и положительных чисел. Простая конструкция if-else в данном случае не подходит. Конечно, мы могли бы прибегнуть здесь к трем отдельным операторам if, но это решение не всегда можно реализовать, особенно если проверки не являются взаимоисключающими. Чтобы справиться с этой ситуацией, можно добавить оператор if к предложению else. Мы уже говорили, что после предложения else может следовать любой допустимый программный оператор Objective-C, так почему не использовать еще один if? if (выражение 1 ) программный оператор 1 else if (выражение 2) программный оператор 2 else программный оператор 3 В результате оператор if расширяется — вместо логического решения с двумя значениями мы получаем логическое решение с тремя значениями. Вы можете продолжить добавление операторов if к предложениям else в том же стиле, чтобы получить логическое решение с п значениями. Эта конструкция так часто используется, что обычно ее называют конструкцией else if и форматируют так. if (выражение 1 ) программный оператор 1 else if (выражение 2 ) программный оператор 2 else программный оператор 3 Это способ делает чтение оператора более удобным. В следующей программе показано использование конструкции else if с реализацией описанной выше функции sign. Программа 6.6 // Реализация функции sign import
int main (int argc, char argv[]) { NSAutoreleasePool pool = [[NSAutoreleasePool alloc] init]; int number, sign; NSLog (@"Please type in a number:"); scant ("%i", &number); if ( number < 0 ) sign = -1; else if ( number == 0 ) sign = 0; else // Положительное число sign = 1; NSLog (@"Sign = %i", sign); [pool drain]; return 0; } Вывод программы 6.6 Please type in a number: (Введите число) 1121 Sign = 1 Вывод программы 6.6 (повторный запуск) Please type in a number: -158 Sign = -1 Вывод программы 6.6 (повторный запуск) Please type in a number: О Sign = О Если введенное число меньше нуля, переменной sign присваивается значение -1; если число равно нулю, sign присваивается значение 0; в противном случае число больше нуля, поэтому sign присваивается значение 1. В следующей программе символ, введенный с терминала, анализируется и классифицируется как алфавитный символ (a-z или A-Z), как цифровой символ (0-9) или как специальный символ (все остальные символы). Для чтения одного символа с терминала при вызове scant используются символы форматирования %с. Программа 6.7 // Эта программа классифицирует символ, // введенный с клавиатуры import
int main (int argc, char argv[]) { NSAutoreleasePool pool = [[NSAutoreleasePool alloc] init]; char c; NSLog (@"Enter a single character:"); scant ("%c", &c); it ( (c >= ’a' && c <= 'z') || (c >= ’A' && c <= 7')) NSLog (@"lt’s an alphabetic character."); else it ( c >= ’O’ && c <= ’9’ ) NSLog ((gilt's a digit."); else NSLog (@"lt’s a special character."); [pool drain]; return 0; } Вывод программы 6.7 Enter a single character: (Введите один символ) & It’s a special character. (Это специальный символ) Вывод программы 6.7 (повторный запуск) Enter a single character: 8 It’s a digit. (Это цифра) Вывод программы 6.7 (повторный запуск) Enter a single character: В It’s an alphabetic character. (Это алфавитный символ) В первой проверке после чтения символа мы определяем, является ли этот символ алфавитным (в переменной с типа char). Сначала проверяется, попадает ли этот символ в диапазон строчных букв: ( с >= 'а' && с <= 'z ') Это выражение имеет значение TRUE, если с находится в диапазоне символов от ’а’ до У (с — строчная латинская буква). Вторая проверка выполняется с помощью следующего выражения: ( с >= ’А’ && с <= “Z" ) Это выражение имеет значение TRUE, если с находится в диапазоне символов от 'А' до 'Т (с — прописная латинская буква). Эти проверки подходят для символов в кодировке ASCII. Если переменная с содержит алфавитный символ, проверка проходит успешно и выводится сообщение «It’s an alphabetic character» (Это алфавитный символ). В противном случае выполняется предложение else if. Оно определяет, является ли данный символ цифрой. Отметим, что выполняется сравнение с символами от '0' до ’9’, а нес цифрами от 0 до 9. Дело в том, что с терминала читается символ, а запись символов от '0' до '9' в компьютере отличается от чисел 0-9. В кодировке ASCII символ ’0' представляется во внутренней записи числом 48, символ Т — числом 49, и т.д. Если с — символ цифры, то выводится фраза «It’s a digit» (Это цифра). В противном случае (если с не является алфавитным символом или символом цифры) выполняется последнее предложение else, и на терминале выводится фраза «It’s a special character» (Это специальный символ). Затем выполнение программы завершается. Хотя в данном случае scant используется для чтения только одного символа, вы все равно должны нажать клавишу Enter после ввода символа, чтобы результат ввода был передан в программу. Обычно при чтении данных с терминала программа «не видит» введенных данных, пока не нажата клавиша Enter. В следующем примере напишем программу, которая позволяет ввести простое выражение в следующей форме: число оператор число Программа выполнит оценку выражения и выведет результаты на терминал. Операторы, которые нужно распознавать, — это обычные оператор сложения, вычитания, умножения и деления. Мы будем использовать класс Calculator из программы 4.6 главы 4. Каждое выражение будет передаваться этому калькулятору для вычислений. В следующей программе используется довольно большой оператор if с несколькими предложениями else if, определяющими, какая операция должна быть выполнена. Примечание. Чтобы избежать проблем с внутреннм представлением, лучше использовать процедуры из стандартной библиотеки islower и isupper. Для этого включите в программу строку #import . Программа 6.8 // Программа вычисления простых выражений в форме // число оператор число // Реализация класса Calculator import