Скачать презентацию Методы программирования Хуторова Ольга Германовна Лекция 4 Скачать презентацию Методы программирования Хуторова Ольга Германовна Лекция 4

MP_L4.ppt

  • Количество слайдов: 36

Методы программирования Хуторова Ольга Германовна Лекция 4 Методы программирования Хуторова Ольга Германовна Лекция 4

Темы лекции n С++ q Структурное программирование. Модульность Функции q Указатели q Темы лекции n С++ q Структурное программирование. Модульность Функции q Указатели q

Модульность n n n Модульный подход делает разработку программ более управляемой. Повторное использование программных Модульность n n n Модульный подход делает разработку программ более управляемой. Повторное использование программных кодов, т. е. использование существующих функций как стандартных блоков для создания новых программ. Повторное использование — основной фактор развития объектно ориентированного программирования. При продуманном присвоении имен функций и хорошем их описании программа может быть создана быстрее из стандартизированных функций, соответствующих определенным задачам. Желание избежать в программе повторения каких то фрагментов. Код, оформленный в виде функции, может быть выполнен в разных местах программы простым вызовом этой функции.

Модульность n n Код, используемый более одного раза, должен быть помещен в функцию Функция Модульность n n Код, используемый более одного раза, должен быть помещен в функцию Функция выполняет только одну задачу Функция должна иметь лишь одну точку входа и одну точку выхода Минимальный размер

Применение принципа модульности n n n Структурное проектирование Объектно ориентированное программирование Функциональное программирование Применение принципа модульности n n n Структурное проектирование Объектно ориентированное программирование Функциональное программирование

Функция - это именованная часть программы, к которой можно обращаться из других частей программы Функция - это именованная часть программы, к которой можно обращаться из других частей программы столько раз, сколько потребуется #include using namespace std; void ring() {cout << "a"; } void main() { ring(); }

Определение функции заголовок_функции { Инструкции // тело функции } ______________________ Заголовок функции: тип имя Определение функции заголовок_функции { Инструкции // тело функции } ______________________ Заголовок функции: тип имя (список_объявлений_параметров) Спецификация типа, стоящая перед именем функции, является возвращаемым типом. Он определяет тип значения, возвращаемого функцией (если оно вообще воз вращается). Имя-функции — это любой правильно написанный идентификатор. Тип-возвращаемого-значения — это тип данных результата, возвращаемого из функции оператору ее вызова. Тип возвращаемого значения void указывает, что функция не возвращает никакого значения. Компилятор предполагает тип int для неопределенного типа возвращаемого значения. Если возвращаемого значения нет, то перед именем функции ставят ключевое слово void. Если тип возвращаемого значения отличается от объявленного, то происходит неявное преобразование в объявленный тип, при невозможности данного преобразования компиляция будет прервана с сообщением об ошибке. Объявления и операторы внутри фигурных скобок образуют тело функции. Тело функции рассматривается как блок. Переменные могут быть объявлены в любом блоке, а блоки могут быть вложенными. При любых обстоятельствах функция не может быть описана внутри другой функции.

Список-параметров n n n Список разделенных запятыми объявлений тех параметров, которые получает функция при Список-параметров n n n Список разделенных запятыми объявлений тех параметров, которые получает функция при ее вызове. Если функция не получает никаких значений, список-параметров задается как void или (). Тип должен быть указан явно для каждого параметра в списке параметров. При объявлении имена параметров можно не писать, учитываются только типы. При определении имена переменных, которые не используются (на случай использования в будущем или для совместимости), можно не писать. extern func(int); //объявление void f(){ func(10); } void func(int val){ std: : cerr << val << 'n'; } //определение int main() { f(); return 0; } n Аргументами функции могут быть константы, переменные или выражения. cout « sqrt(c + d*f) n Все переменные объявляются в описаниях функций локальными переменными — они известны только для функции, в которой они описаны. Большинство функций имеют список параметров, который обеспечивает значения для связующей информации между функциями. Параметры тоже являются локальными переменными.

Аргумент по умолчанию Int pow_2(float x, int p=2) Аргумент по умолчанию Int pow_2(float x, int p=2)

Локальные и глобальные переменные n n Внутри функции могут быть объявлены локальные переменные. Переменные, Локальные и глобальные переменные n n Внутри функции могут быть объявлены локальные переменные. Переменные, определенные вне тела любой функции называются глобальными и они определены всюду начиная с места определения и до конца файла. Локальные переменные создаются каждый раз при входе в функцию и уничтожаются при выходе из нее. В различных функциях можно определять переменные с одним и тем же именем. Это будут различные переменные. Также можно объявлять в функциях переменные, имена которых совпадают с именами глобальных переменных. Тогда будет создана новая локальная переменная, а изменить значение глобальной переменной с таким именем будет невозможно. #include using namespace std; int i; // i глобальная переменная void f 1() { int i; // Определена локальная i i=5; // Изменяется значение локальной переменной cout<

Возврат управления n n Если функция не должна возвращать результат, управление возвращается или просто Возврат управления n n Если функция не должна возвращать результат, управление возвращается или просто при достижении правой фигурной скобки, завершающей функцию, или при выполнении оператора return; Инструкция return используется для двух целей. Когда она выполняется, управле ние программой немедленно передается обратно в вызывающее окружение. Кроме того, если за ключевым словом return следует какое либо выражение, то его значение также передается в вызывающее окружение. Инструкция return имеет одну из двух форм: return; return выражение; Пример return; return 3; return (a + b); Скобки в выражении return не обязательны; некоторые программисты ставят их Для удобочитаемости. void func(){. . . } void func(){ return 0; } //ошибка int func(){ return 10; }

Прототипы (объявления) функций n Прототип функции (function prototype) — это объявление функции, но не Прототипы (объявления) функций n Прототип функции (function prototype) — это объявление функции, но не ее определение, функция может быть объявлена до того, как она определена. Определение функции может идти позже в этом же файле, браться из библиотеки или из указанного пользователем файла. тип имя(список_объявлений_аргументов) ; n Прототип функции, заголовок функции и вызовы функции должны быть согласованы между собой по количеству, типу и порядку следования аргументов и параметров и по типу возвращаемых результатов.

Встраиваемые функции. inline Функция может определяться как встроенная (inline). Тело данных функций, по возможности, Встраиваемые функции. inline Функция может определяться как встроенная (inline). Тело данных функций, по возможности, встраивается в место вызова, этим может достигаться определенное увеличение скорости работы программы. Такая функция должна быть определена с ключевым словом inline, причем определение должно находиться в области видимости того места, откуда ее вызывают. Как правило, inline функции определяют в заголовочных (*. h) файлах. inline void fast_inc(int &val){ val++; } int main() { int i = 0; fast_inc(i); return 0; }

Функция main () n n Функция main () служит в качестве точки входа в Функция main () n n Функция main () служит в качестве точки входа в программу. Она подчиняется правилам C++ для объявления функций. В программах, содержащих много функций, main должна быть построена как группа вызовов функций, которые и выполняют основную часть работы.

Стандартные функции и библиотеки n n Каждая стандартная библиотека имеет соответствующий заголовочный файл, содержащий Стандартные функции и библиотеки n n Каждая стандартная библиотека имеет соответствующий заголовочный файл, содержащий прототипы всех функций библиотеки и объявления различных типов данных и констант, которые используются этими функциям. Программист может сам создавать требующиеся ему заголовочные файлы. Заголовочные файлы, определяемые программистом, также должны иметь расширение. h. Заголовочные файлы, определяемые программистом, могут быть включены с помощью директивы препроцессора #include. Например, заголовочный файл square. h может быть включен в нашу программу директивой #include "square. h"

Стандартные функции и библиотеки Заголовочный файл стандартной библиотеки Объяснение <math. h> Содержит прототипы математических Стандартные функции и библиотеки Заголовочный файл стандартной библиотеки Объяснение Содержит прототипы математических библиотечных функций. Содержит прототипы стандартных библиотечных функций ввода вывода и используемую ими информацию. Содержит прототипы функций, преобразующих числа в текст и текст в числа, ведающих выделением памяти, генерирующих случайные числа и осуществляющих другие полезные операции. Содержит прототипы функций, обрабатывающих строки. Содержит прототипы функций и типы для работы с временем и датами.

Наиболее употребительные математические библиотечные функции Функция Описание sqrt(x) корень квадратный из х ехр(х) экспоненциальная Наиболее употребительные математические библиотечные функции Функция Описание sqrt(x) корень квадратный из х ехр(х) экспоненциальная функция ех log(x) логарифм натуральный х (по основанию е) Iog 10(x) логарифм десятичный х (по основанию 10) fabs(x) абсолютное значение х ceil(x) округление х до наименьшего целого, не меньшего чем х floor(x) округление х до наибольшего целого, не большего чем х pow(x, y) х в степени у fmod(x, y) остаток от х/у, как число с плавающей точкой sin(x) синус х (х в радианах) cos(x) косинус х (х в радианах) tan(x) тангенс х (х в радианах)

Генерация случайных чисел, равномерно распределенных от -1 до 6 #include <iostream> #include <iomanip> #include Генерация случайных чисел, равномерно распределенных от -1 до 6 #include #include #include using namespace std; int main() { for (int i = 1; i <= 20; i++) { cout <<" "<< 1 + rand()%6; if (i % 5 == 0) cout << endl; } }

передача параметров через глобальные переменные n Данный способ нельзя рекомендовать к повсеместному использованию, т. передача параметров через глобальные переменные n Данный способ нельзя рекомендовать к повсеместному использованию, т. к. глобальные переменные могут находиться в достаточно "обширной" области видимости, и соответственно, могут изменяться многими конструкциями программы. Программа становится не просто некрасивой, а потенциально уязвимой возможными ошибками. Если возникает необходимость пользоваться глобальными переменными, то лучше объявлять такие переменные как static, это ограничит область видимости этих переменных до зоны данного файла (эта рекомендация, естественно, для случая, когда подобные переменные не нужны в других файлах). static int gvalue; . . . void inc_value() { gvalue++; } int main() { inc_value(); return 0; }

передача по значению n Когда аргумент передается вызовом по значению, создается копия аргумента и передача по значению n Когда аргумент передается вызовом по значению, создается копия аргумента и она передается вызываемой функции. Изменения копии не влияют на значение оригинала в операторе вызова. Это предотвращает случайный побочный эффект, который так сильно мешает развитию корректного и надежного программного обеспечения. Один из недостатков вызова по значению состоит в том, что если передается большой элемент данных, создание копии этих данных может привести к значительным потерям времени выполнения. int inc_value(int v) { return ++v; } int main() { int i=0; int rez = inc_value(i); //rez теперь равен 1 //i как и прежде равен 0 return 0; }

передача по ссылке При этом способе функция получает реальный переданный объект, поэтому все, что передача по ссылке При этом способе функция получает реальный переданный объект, поэтому все, что функция делает, она делает над реальным объектом. Данный способ позволяет изменять значения несколько параметров. При несоответствии объявленного типа переданному, будет выдано сообщение об ошибке. Вызов по ссылке хорош в смысле производительности, потому что он исключает накладные расходы на копирование больших объемов данных, но вызов по ссылке может ослабить защищенность, потому что вызываемая функция может испортить передаваемые в нее данные. void inc_value(int &v) { v++; } int main() { int i=0; inc_value(i); //i теперь равен 1 char c = 0; inc_value(c); //ошибка inc_value(10); //ошибка. . . return 0; }

передача по константной ссылке Данный способ нужно применять в случае необходимости передать большой объект передача по константной ссылке Данный способ нужно применять в случае необходимости передать большой объект в функцию и, обеспечить при этом сохранность состояния переданного объекта. Т. е. передача объекта в режиме только для чтения. При соответствии объявленного типа переданному передается непосредственно реальный объект, иначе, при наличии соответствующего конструктора, создается временный объект, который и передается в функцию. При использовании неявного преобразования следует быть осторожным, т. к. выбор компилятором копирующего конструктора иногда отличается от того, который Вы ожидаете увидеть. void process_value(const int &v) {. . . } int main() { int i=0; process_value(i); process_value(10); //нормально char c = 0; process_value(c); //нормально. . . return 0; }

передача указателя В этом случае передается адрес реального объекта, поэтому при изменении через указатель передача указателя В этом случае передается адрес реального объекта, поэтому при изменении через указатель буду производиться над реальным объектом. В зависимости от логики программы, в функцию может быть передан нулевой указатель. Преобразование к указателю на нужный тип производится либо явно либо неявно для случаев преобразования потомков к базовому типу. void inc_value(int *pval) { if(pval) ++(*pval); } int main() { int i=0; inc_value(&i); //i теперь равен 1 return 0; }

передача указателя на константный объект Во всем аналогично способу передачи обычного указателя, единственное нельзя передача указателя на константный объект Во всем аналогично способу передачи обычного указателя, единственное нельзя изменять объект, на который указывает переданный указатель. int inc_value(const int *pval) { //++(*pval); //ошибка, разрешено только для чтения return *pval+1; } int main() { int i=0; i = inc_value(&i); //i теперь равен 1 return 0; }

Указатели Адресация в С++. n Ссылочный параметр — это псевдоним соответствующего аргумента. Чтобы показать, Указатели Адресация в С++. n Ссылочный параметр — это псевдоним соответствующего аргумента. Чтобы показать, что параметр функции передан по ссылке, после типа параметра в прототипе функции ставится символ амперсанда (&); такое же обозначение используется в списке типов параметров в заголовке функции. Например, объявление int &count n в заголовке функции может читаться как «count является ссылкой на int» . В вызове функции достаточно указать имя переменной и она будет передана по ссылке. Тогда упоминание в теле вызываемой функции переменной по имени ее параметра в действительности является обращением к исходной переменной в вызывающей функции и эта исходная переменная может быть изменена непосредственно вызываемой функцией. Когда вы используете указатель с предшествующим символом *, вы извлекаете значение, хранящееся по данному адресу. void main( void ) { int i. Num 1; i. Num 1 = 2; cout << "Address of i. Num 1 is: "; cout << *i. Num 1 << endl; }

Адресация в С++. Указатели void main(void) { int i. Num 1; int i. Num Адресация в С++. Указатели void main(void) { int i. Num 1; int i. Num 2; int i. Result; int* p. Num 1; int* p. Num 2; i. Num 1 = 2; i. Num 2 = 3; p. Num 1 = &i. Num 1; p. Num 2 = &i. Num 2; i. Result = *p. Num 1 + *p. Num 2; cout << "The result is: "; cout << i. Result << endl; }

Комментарии для функции void the_function( void ) { // далее настоящая функция. code_goes_here(); } Комментарии для функции void the_function( void ) { // далее настоящая функция. code_goes_here(); }

Константные аргументы функций void f(const int* p) { *p = 17; // Нельзя int Константные аргументы функций void f(const int* p) { *p = 17; // Нельзя int i = 29; p = &i; // Можно, но зачем? } // Где то в программе int i = 17; f(&i); // Порядок, фактический аргумент не обязан быть константой void f(const int& p) { p = 17; // Нельзя int i = 29; p = i; // Можно (на грани фола) } // Где то глубоко в программе int i = 17; f(i); // Порядок n Обратите внимание — аргумент, указанный при вызове функции, не обязан быть константным. Этот вопрос целиком остается на усмотрение стороны получателя. Передача по ссылке осуществляется по тем же правилам, что и передача по адресу.

Неконстантные аргументы функций Если формальный аргумент функции объявлен неконстантным, то и фактический аргумент, используемый Неконстантные аргументы функций Если формальный аргумент функции объявлен неконстантным, то и фактический аргумент, используемый при вызове, тоже должен быть неконстантным. void f(int*); int i = 17; const int* p = &i; const int j = 29; f(&i); // Можно, потому что i – не константа f(p); // Нельзя f(&j); // Тоже нельзя, потому что j – константа Это еще одно средство, с помощью которого компилятор соблюдает принцип «единожды константный всегда остается константным» . Даже если функция f на самом деле не изменяет значения своего формального параметра, это ни на что не влияет.

Рекурсия float pow(float x, int n) { if (n <0) error( Рекурсия float pow(float x, int n) { if (n <0) error("извините, отрицательный показатель для pow()"); switch (n) { case 0: return 1; case 1: return x; default: return x*pow(x, n 1); } }

Типичные ошибки программирования n n n n При использовании функций математической библиотеки забывают включать Типичные ошибки программирования n n n n При использовании функций математической библиотеки забывают включать ее заголовочный файл, что приводит к ошибке компиляции. Стандартный заголовочный файл должен быть включен для любой стандартной библиотечной функции, исполь зуемой в программе. Возвращение какого то значения из функции, для которой тип возвращаемого значения объявлен как void, вызывает синтаксическую ошибку. Несмотря на то, что пропущенный тип возвращаемого значения по умолчанию int, всегда задавайте тип возвращаемого значения явным образом. Исключением является функция main, для которой тип возвращаемого значения обычно не указывается. Тип должен быть указан явно для каждого параметра в списке параметров. Объявление параметров функции, имеющих одинаковый тип, в виде float x, у вместо float x, float у. Объявление параметра float x, у вызовет ошибку компиляции, так как типы надо указывать для каждого параметра в списке. Точка с запятой после правой круглой скобки, закрывающей список параметров в описании функции, является синтаксической ошибкой. Повторное определение параметра функции как локальной переменной этой функции является синтаксической ошибкой.

Хороший стиль программирования n n n Внимательно изучайте широкий набор функций в стандартной библиотеке Хороший стиль программирования n n n Внимательно изучайте широкий набор функций в стандартной библиотеке ANSI С и классов в различных библиотеках классов. Избегайте повторного изобретения колеса. Если возможно, используйте стандартную библиотеку ANSI С вместо того, чтобы писать новые функции. Это сокращает затраты времени на создание программы. Использование стандартной библиотеки ANSI С увеличивает мобильность программы.

Мнемонические имена int Simplex_min () float root_dihot () Runge_Cutta_diff () При этом общепринятые аббревиатуры Мнемонические имена int Simplex_min () float root_dihot () Runge_Cutta_diff () При этом общепринятые аббревиатуры являются очевидными исключениями. n i j — обобщенные счетчики циклов; n max — максимум (обычно в качестве префикса или суффикса); n min — минимум (обычно в качестве префикса или суффикса);

Не пользуйтесь именами из стандарта ANSI Cи (_? ? ? ) и именами Microsoft Не пользуйтесь именами из стандарта ANSI Cи (_? ? ? ) и именами Microsoft n n Все имена функций Microsoft используют соглашения в стиле Паскаля о Смеси. Заглавных. ИСтрочных. Букв(), и они всегда начинаются с заглавной буквы. Не. Используйте. Стиль. Microsoft(). Функции члены в классах MFC используют то же самое соглашение. Все имена классов Microsoft начинаются с заглавной "С" с последующей заглавной буквой (например, CString, CWnd, CDialog и т. д. ).

Делайте локальные переменные статическими в рекурсивных функциях, если их значения не участвуют в рекурсивном Делайте локальные переменные статическими в рекурсивных функциях, если их значения не участвуют в рекурсивном вызове n n n n n n n Так как мы занялись темой рекурсии, то вот правило, которое используется для того, чтобы еще сильнее сократить использование стека. Локальная переменная может быть объявлена статической (тем самым она минует стек), если ее значение не должно сохраняться после рекурсивного вызова. Вот один пример: f() { static int i; //. . . for( i = 10; i >= 0; ) //. . . f(); for( i = 10; i >= 0; ) // переменная i вновь инициализиру– // ется после рекурсивного вызова, // поэтому она может быть статичес– } // кой. Вот другой: int f() { static int depth = 0; static int depth_max = 0; ++depth; depth_max = max( depth, depth_max ); if( depth > 10 ) return 1; // уровень рекурсии слишком глубок. f(); depth; return depth_max; } В этом последнем случае переменная depth используется для передачи информации — глубины рекурсии — от одного экземпляра подпрограммы другому, рекурсивному экземпляру этой же самой подпрограммы. Переменная depth_max хранит след достигнутой максимальной глубины рекурсии. depth вовсе не будет работать, если она должна будет сохранять свое значение после вызовов — весь смысл в том, что каждый рекурсивный вызов модифицирует эту переменную.

Список литературы n n Х. Дейтел, П. Дейтел Как программировать на С++ Бьярн Страустрап, Список литературы n n Х. Дейтел, П. Дейтел Как программировать на С++ Бьярн Страустрап, Введение в язык С++