С самоучитель. Уроки по с ravesli com 2 предисловие
Скачать 2.56 Mb.
|
std::cin, std::cout, << и >> Новички часто путают std::cin, std::cout, << и >>. Вот простые способы запомнить их различия: std::cin и std::cout всегда находятся в левой стороне стейтмента; std::cout используется для вывода значения (cOUT = вывод); std::cin используется для получения значения (cIN = ввод); оператор вывода << используется с std::cout и показывает направление, в котором данные движутся от r-value в консоль. std::cout << 7; (значение 7 перемещается в консоль); ravesli.com 69 оператор ввода >> используется с std::cin и показывает направление, в котором данные движутся из консоли в переменную. std::cin >> a; (значение из консоли перемещается в переменную a). ravesli.com 70 Урок №12. Функции и оператор возврата return Вы уже знаете, что каждая программа должна иметь функцию main() (с которой она и начинает своё выполнение). Тем не менее, большинство программ используют и много других функций. Функции Функция – это последовательность стейтментов для выполнения определённого задания. Часто ваши программы будут прерывать выполнение одних функций ради выполнения других. Вы делаете аналогичные вещи в реальной жизни постоянно. Например, вы читаете книгу и вспомнили, что должны были сделать телефонный звонок. Вы оставляете закладку в своей книге, берёте телефон и набираете номер. После того, как вы уже поговорили, вы возвращаетесь к чтению: к той странице, на которой остановились. Программы в C++ работают похожим образом. Иногда, когда программа выполняет код, она может столкнуться с вызовом функции. Вызов функции – это выражение, которое указывает процессору прервать выполнение текущей функции и приступить к выполнению другой функции. Процессор "оставляет закладку" в текущей точке выполнения, а затем выполняет вызываемую функцию. Когда выполнение вызываемой функции завершено, процессор возвращается к "закладке" и возобновляет выполнение прерванной функции. Функция, в которой находится вызов – называется caller, а функция, которую вызывают – вызываемая функция. Например: #include // для std::cout и std::endl // Объявление функции doPrint(), которую мы будем вызывать void doPrint () { std :: cout << "In doPrint()" << std :: endl ; } ravesli.com 71 // Объявление функции main() int main () { std :: cout << "Starting main()" << std :: endl ; doPrint (); // прерываем выполнение main() вызовом функции doPrint(). main() в этом случае является caller-ом std :: cout << "Ending main()" << std :: endl ; return 0 ; } Результат выполнения программы выше: Starting main() In doPrint() Ending main() Эта программа начинает выполнение с первой строчки функции main(), где выводится на экран следующая строчка: Starting main(). Вторая строчка функции main() вызывает функцию doPrint(). На этом этапе выполнение стейтментов в функции main() приостанавливается и процессор переходит к выполнению стейтментов внутри функции doPrint(). Первая (и единственная) строчка в doPrint() выводит текст In doPrint() . Когда процессор завершает выполнение doPrint(), он возвращается обратно в main() к той точке, на которой остановился. Следовательно, следующем стейтментом является вывод строки Ending main(). Обратите внимание, для вызова функции нужно указать её имя и список параметров в круглых скобках (). В примере выше параметры не используются, поэтому круглые скобки пусты. Мы поговорим детальнее о параметрах функций в следующем уроке. Правило: Не забывайте указывать круглые скобки () при вызове функций. ravesli.com 72 Возвращаемые значения Когда функция main() завершает своё выполнение, она возвращает целочисленное значение обратно в операционную систему, используя оператор return. Функции, которые мы пишем, также могут возвращать значения. Для этого нужно указать тип возвращаемого значения (или ещё "тип возврата"). Он указывается при объявлении функции, перед её именем. Обратите внимание, тип возврата не указывает, какое именно значение будет возвращаться. Он указывает только тип этого значения. Затем внутри вызываемой функции мы используем оператор return, чтобы указать возвращаемое значение – какое именно значение будет возвращаться обратно в caller. Рассмотрим простую функцию, которая возвращает целочисленное значение: #include // int означает, что функция возвращает целочисленное значение обратно в caller int return7 () { // Эта функция возвращает целочисленное значение, поэтому мы должны использовать оператор return return 7 ; // возвращаем число 7 обратно в caller } int main () { std :: cout << return7 () << std :: endl ; // выведется 7 std :: cout << return7 () + 3 << std :: endl ; // выведется 10 return7 (); // возвращаемое значение 7 игнорируется, так как main() ничего с ним не делает return 0 ; } ravesli.com 73 Результат выполнения программы выше: 7 10 Первый вызов функции return7() возвращает 7 обратно в caller, которое затем передается в std::cout для вывода. Второй вызов функции return7() опять возвращает 7 обратно в caller. Выражение 7 + 3 производит результат 10, который затем выводится на экран. Третий вызов функции return7() опять возвращает 7 обратно в caller. Однако main() ничего с ним не делает, поэтому ничего и не происходит (возвращаемое значение игнорируется). Примечание: Возвращаемые значения не выводятся на экран, если их не передать объекту std::cout. В последнем вызове функции return7() значение не отправляется в std::cout, поэтому ничего и не происходит. Тип возврата void Функции могут и не возвращать значения. Чтобы сообщить компилятору, что функция не возвращает значение – нужно использовать тип возврата void . Взглянем ещё раз на функцию doPrint() из примера выше: void doPrint () // void - это тип возврата { std :: cout << "In doPrint()" << std :: endl ; // эта функция не возвращает никакого значения, поэтому оператор return здесь не нужен } Эта функция имеет тип возврата void, который означает, что функция не возвращает значения. Поскольку значение не возвращается, то и оператор return не требуется. ravesli.com 74 Вот ещё один пример использования функции типа void: #include // void означает, что функция не возвращает значения void returnNothing () { std :: cout << "Hi!" << std :: endl ; // эта функция не возвращает никакого значения, поэтому оператор return здесь не нужен } int main () { returnNothing (); // функция returnNothing() вызывается, но обратно в main() ничего не возвращается std :: cout << returnNothing (); // ошибка: эта строчка не скомпилируется. Вам нужно будет её закомментировать return 0 ; } В первом вызове функции returnNothing() выводится Hi!, но ничего не возвращается обратно в caller. Точка выполнения возвращается обратно в main(), где программа продолжает своё выполнение. Второй вызов функции returnNothing() даже не скомпилируется. Функция returnNothing() имеет тип возврата void, который означает, что эта функция не возвращает значения. Однако main() пытается отправить это значение (которое не возвращается) в std::cout для вывода. std::cout не может обработать этот случай, так как значения не вывод не предоставлено. Следовательно, компилятор выдаст ошибку. Вам нужно будет закомментировать эту строку, чтобы компиляция прошла успешно. Возврат в main() Теперь у вас есть понимание того, как работает функция main(). Когда программа выполняется, операционная система делает вызов функции main() и начинается её выполнение. Стейтменты в main() выполняются последовательно. В конце функция main() возвращает целочисленное ravesli.com 75 значение (обычно 0) обратно в операционную систему. Поэтому main() объявляется как int main(). Почему нужно возвращать значения обратно в операционную систему? Дело в том, что возвращаемое значение функции main() является кодом состояния, который сообщает операционной системе о том, успешно ли было выполнение программы или нет. Обычно, возвращаемое значение 0 (нуль) означает что, всё прошло успешно, тогда как любое другое значение означает неудачу/ошибку. Обратите внимание, по стандартам C++ функция main() должна возвращать целочисленное значение. Однако, если вы не укажете return в конце функции main(), то компилятор возвратит 0 автоматически, если никаких ошибок не будет. Но рекомендуется указывать return в конце main() и использовать тип возврата int для функции main(). Детальнее о возвращаемых значениях Во-первых, если тип возврата функции не void, то она должна возвращать значение указанного типа (использовать оператор return). Единственно исключение – функция main(), которая возвращает 0, если не предоставлено другое значение. Во-вторых, когда процессор встречает в функции оператор return, он немедленно выполняет возврат значения обратно в caller и точка выполнения также переходит в caller. Любой код, который находится за return- ом в функции – игнорируется. Функция может возвращать только одно значение через return обратно в caller. Это может быть либо число (например, 7), либо значение переменной, либо выражение (которое производит результат), либо определённое значение из набора возможных значений. ravesli.com 76 Но есть способы обойти правило возврата одного значения, возвращая сразу несколько значений, но об этом детальнее мы поговорим в соответствующем уроке. Наконец, автор функции решает, что означает её возвращаемое значение. Некоторые функции используют возвращаемые значения в качестве кодов состояния для указания результата выполнения функции (успешно ли выполнение или нет). Другие функции возвращают определённое значение из набора возможных значений, ещё другие функции вообще ничего не возвращают. Повторное использование функций Одну и ту же функцию можно вызывать несколько раз, даже в разных программах, что очень полезно: #include // getValueFromUser получает значение от пользователя, а затем возвращает его обратно в caller int getValueFromUser () { std :: cout << "Enter an integer: " ; int x ; std :: cin >> x ; return x ; } int main () { int a = getValueFromUser (); // первый вызов функции getValueFromUser int b = getValueFromUser (); // второй вызов функции getValueFromUser std :: cout << a << " + " << b << " = " << a + b << std :: endl ; return 0 ; } Результат выполнения программы выше: Enter an integer: 4 Enter an integer: 9 4 + 9 = 13 ravesli.com 77 Здесь main() прерывается 2 раза. Обратите внимание, в обоих случаях, полученное пользовательское значение сохраняется в переменной x, а затем передаётся обратно в main() с помощью return, где присваивается переменной a или b! Также main() не является единственной функцией, которая может вызывать другие функции. Любая функция может вызывать любую другую функцию! #include () { std :: cout << "O" << std :: endl ; } void printK () { std :: cout << "K" << std :: endl ; } // Функция printOK() вызывает как printO(), так и printK() void printOK () { printO (); printK (); } // Объявление main() int main () { std :: cout << "Starting main()" << std :: endl ; printOK (); std :: cout << "Ending main()" << std :: endl ; return 0 ; } Результат выполнения программы выше: Starting main() O K Ending main() ravesli.com 78 Вложенные функции В С++ одни функции не могут быть объявлены внутри других функций (т.е. быть вложенными). Следующий код вызовет ошибку: #include () { int boo () // эта функция находится внутри функции main(), что запрещено { std :: cout << "boo!" ; return 0 ; } boo (); return 0 ; } Правильно вот так: #include () // теперь уже не в main() { std :: cout << "boo!" ; return 0 ; } int main () { boo (); return 0 ; } Тест Какие из следующих программ не скомпилируются (и почему), а какие скомпилируются (и какой у них результат)? Программа №1: #include () { return 5 ; } ravesli.com 79 int return8 () { return 8 ; } int main () { std :: cout << return5 () + return8 () << std :: endl ; return 0 ; } Программа №2: #include () { return 5 ; int return8 () { return 8 ; } } int main () { std :: cout << return5 () + return8 () << std :: endl ; return 0 ; } Программа №3: #include () { return 5 ; } int return8 () { return 8 ; } int main () { return5 (); return8 (); return 0 ; ravesli.com 80 } Программа №4: #include () { std :: cout << "O" << std :: endl ; } int main () { std :: cout << printO () << std :: endl ; return 0 ; } Программа №5: #include () { return 6 ; return 8 ; } int main () { std :: cout << getNumbers () << std :: endl ; std :: cout << getNumbers () << std :: endl ; return 0 ; } Программа №6: #include 6 () { return 6 ; } int main () { std :: cout << return 6 () << std :: endl ; return 0 ; } ravesli.com 81 Программа №7: #include () { return 6 ; } int main () { std :: cout << return6 << std :: endl ; return 0 ; } ravesli.com 82 Урок №13. Параметры и аргументы функций В предыдущем уроке мы говорили, что функция может возвращать значение обратно в caller, используя оператор return. Параметры и аргументы функций Во многих случаях нам нужно будет передавать данные в вызываемую функцию, чтобы она могла с ними как-то взаимодействовать. Например, если мы хотим написать функцию умножения двух чисел, то нам нужно каким-то образом сообщить функции, какие это будут числа. В противном случае, как она узнает, что на что умножать? Здесь нам на помощь приходят параметры и аргументы. Параметр функции — это переменная, которая используется в функции и значение которой предоставляет caller (вызывающий объект). Параметры указываются при объявлении функции в круглых скобках. Если их много, то они перечисляются через запятую. Например: // Эта функция не имеет параметров void doPrint () { std :: cout << "In doPrint()" << std :: endl ; } // Эта функция имеет один параметр типа int: a void printValue ( int a ) { std :: cout << a << std :: endl ; } // Эта функция имеет два параметра типа int: a и b int add ( int a , int b ) { return a + b ; } Параметры каждой функции действительны только внутри этой функции. Поэтому, если printValue() и add() имеют параметр с именем a, то это не означает, что произойдёт конфликт имён. Эти параметры считаются отдельными и никак не взаимодействуют друг с другом. ravesli.com 83 Аргумент — это значение, которое передаётся из caller-а в функцию и которое указывается в скобках при вызове функции в caller-е: printValue ( 7 ); // 7 – это аргумент функции printValue() add ( 4 , 5 ); // 4 и 5 – это аргументы функции add() Обратите внимание, аргументы также перечисляются через запятую. Количество аргументов должно совпадать с количеством параметров, иначе компилятор выдаст сообщение об ошибке. Как работают параметры и аргументы функций? При вызове функции, все её параметры создаются как локальные переменные, а значение каждого из аргументов копируется в соответствующий параметр (локальную переменную). Этот процесс называется передачей по значению. Например: #include // Эта функция имеет два параметра типа int: a и b // Значения переменных a и b определяет caller void printValues ( int a , int b ) { std :: cout << a << std :: endl ; std :: cout << b << std :: endl ; } int main () { printValues ( 8 , 9 ); // здесь два аргумента: 8 и 9 return 0 ; } При вызове функции printValues() аргументы 8 и 9 копируются в параметры a и b. Параметру a присваивается значение 8, а параметру b — значение 9. Результат: 8 9 |