Программирование C++. Пензенский государственный университет введение в программирование на языке с лабораторный практикум пенза 2010 г 2
Скачать 1.47 Mb.
|
С++ Заголовочный файл Пояснение using std::endl; using std::cout; int main() { for ( int i=0; i<=20; ++i) cout<<( 1 + rand()%6 )< // генерация чисел в диапазоне от 1 до 6: // rand() генерирует целое число в диапазоне // от 0 доне менее 32767) system( "pause" ); return 0; Пример Определение текущего времени using std::endl; using std::cout; int main() { time_t system_time = time(NULL); // здесь NULL – нулевой параметр time: " < system( "pause" ); return 0; } Результат работы 28 Перегрузка и шаблоны функций Перегрузка функций обычно используется для создания нескольких функций с одинаковым именем, предназначенных для выполнения сходных задач, нос разными типами данных. При вызове перегруженной функции компилятор С определяет соответствующую функцию путем анализа количества, типов и порядка следования параметров в вызове. Пример Перегрузка функций расчета квадрата переменной using std::endl; using std::cout; int square( int x){ return x * x;} double square( double y){ return y * y;} int main() { Квадрат целого числа 7 = " < < system( "pause" ); return 0; При вызове square(7) будет обращение к функции int square( int x) и вывод значения Во втором вызове обращение к функции double square( double y) и вывод значения Шаблон функции используется, если операции обработки данных перегруженных функций идентичны. Тогда вместо нескольких перегруженных функций можно применить единственный шаблон функции. Пример Шаблон функции расчета квадрата переменной using std::endl; using std::cout; template < typename T> определение шаблона функции T square(T value){ return value * value;} с параметром типа T int main() { Квадрат целого числа 7 = " < < system( "pause" ); return 0; Когда компилятор обнаруживает вызов функции square в исходном тексте программы, тип данных переданный в функцию подставляется вместо типа T в определение шаблона, и компилятор создает функциию square для переданного типа данных. После этого заново созданная функция компилируется. Таким образом шаблон, в действительности, является средством генерации кода Задания для самостоятельной работы 2.7.1 Разработка простых и рекурсивных функций Напишите функцию, которая осуществляет обработку информации по одному из условий, заданных ниже. Главная программа ( main ) осуществляет ввод исходных данных, передает их в функцию и выводит результаты, полученные из функции. 1) Дано натуральное число N. Определить a. Количество цифр 7 в этом числе b. Произведение цифр заданного натурального числа c. Определить число, получаемое выписыванием в обратном порядке цифр заданного натурального числа d. Является ли заданное натуральное число палиндромом, те. таким, десятичная запись которого читается одинаково слева направо и справа налево e. Сколько чисел натурального ряда необходимо перемножить, чтобы их произведение превысило заданное натуральное число f. Является ли число простым. Идея алгоритма заключается в том, что необходимо делить число на все целые числа k меньше его ( k можно ограничить диапазоном изменения от 2 до N .). Если N не делится нацело на возможные значения k, то N – простое число. 2) Найти наибольший общий делитель для двух натуральных чисел m и n ( m 0, n 0, Алгоритм приведен наследующей схеме программы 3) Функция вычисляет квадратный корень вещественного аргумента x с заданной точностью eps по итерационной формуле 1 1 1 n n n y x y y , где 1 n y , n y – предыдущее и последующее приближения корня соответственно. Процесс вычислений прекращается, когда приближения станут отличаться друг от друга по абсолютной величине менее чем на величину eps 30 4) Функция вычисляет sin(x) вещественного аргумента x по формуле sin(x) = ! 1 2 1 ! 5 ! 3 1 2 5 3 n x x x x n n с точностью 0.001 5) Функция вычисляет e x вещественного аргумента x по формуле ! ! 3 ! 2 1 3 2 n x x x x n x e с точностью Напишите функцию, которая осуществляет рекурсивную обработку информации по одному из условий, заданных ниже 6) y = 10 ) 2 ( i i 7) y = 8) y = 9) Определить наибольший общий делитель по алгоритму Евклида (схема алгоритма из примера 2.7.1.2) для двух чисел Аи В (А 0, В 0, А > В. 10) Найти n (n>2) первых чисел Фибоначчи 0, 1, 1, 2, 3, 5,… . Обозначим число как результат функции номер. Тогда последоваельность чисел Фибоначчи можно рекурсивно определить так f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2). 11 1 9 1 7 1 5 1 3 1 1 1 99 96 9 6 3 31 3. СТРУКТУРЫ ДАННЫХ. МАССИВЫ, СТРОКИ, УКАЗАТЕЛИ И СТРУКТУРЫ Массивы Многие алгоритмы обработки данных связаны с выполнением однообразных действий над группой величин одного типа. В этом случае целесообразно работать с этими данными как с массивом. Массив – это структура данных, состоящая из фиксированного числа элементов, имеющих одинаковое имя, одинаковый тип и расположенных в памяти последовательно. Операция выбора элемента массива называется индексацией синтаксически она записывается как имя массива, за которым в квадратных скобках следует значение индекса (номера) выбираемого элемента. Массив – это структура данных спр о изв о л ьн ы м доступом, то есть время доступа к значению элемента массива не зависит от номера элемента. Описание массива имеет следующий формат тип имя_массива[размер_массива]; В С++ п ер вы й элемент любого массива это нулевой элемент Таким образом индекс первого элемента – 0, второго – 1, третьего – 2 итак далее. Рассмотрим инициализацию массива, вводи вывод значений его элементов на примере программы, которая вычисляет сумму значений элементов массива. Пример Одномерный массив using std::endl; using std::cout; int main() { const int ArraySize=5; // размер массива a[ArraySize] = {12, 3, 42, 5, 34}; // инициализация массива // a[0]=12, a[1]=3, a[2]=43, // a[3]=5, a[4]=34 начальные значения можно ввести и с клавиатуры /* for (int i=0; i cin>>a[i]; */ for ( int i=0; i cout< int total=0; сумма значений элементов массива for ( int i=0; i total+=a[i]; cout << Сумма элементов массива " < system( "pause" ); return 0; } 32 Пример Сортировка массива методом пузырька using std::endl; using std::cout; int main() { const int ArraySize=5 // размер массива int a[ArraySize] = {12, 3, 42, 5, 34}; // инициализация массива int i, j, temp; сортировка элементов массива (i=0; i for (j=ArraySize-1; j>i; j--) место одно значение if (a[j] temp=a[j], a[j]=a[j-1], перестановка элементов вывод значений элементов массива (i=0; i cout< 3, 5, 12, 34, 42 system( "pause" ); return 0; } Пример Двумерный массив using std::endl; using std::cout; int main() { const int ArraySize1=3, // размер массива(количество строк таблицы) ArraySize2=2; // размер массива(количество столбцов) // инициализация массива int a[ArraySize1][ArraySize2] ={ {12, 3}, // a[0][0]=12, a[0][1]=3, {42, 5}, // a[1][0]=42, a[1][1]=5, {10, 34} // a[2][0]=10, a[2][1]=34 }; начальные значения можно ввести и с клавиатуры /* for(int i=0; i for(int j=0; j cin>>a[i][j]; */ for ( int i=0; i for ( int j=0; j cout< " " ; cout< } сумма значений элементов массива int total=0; for ( int i=0; i for ( int j=0; j total+=a[i][j]; cout << Сумма элементов массива " < system( "pause" ); return 0; } 33 Строки – массивы символов Массивы могут использоваться для хранения не только числовых данных , но и для хранения символьной информации – символов и строк. Символьный массив, представляющий строку, должен быть достаточно большим для того, чтобы вместить все символы строки и специальный завершающий символ – '\0'. Инициализировать массив символов можно символьной константой. Например char string1[]= Размер массива определяется компилятором по длине строки инициализации. Для данного массива (размер длина строки "hello" ) + завершающий символ) = Символьному массиву можно задать в качестве начального значения сисок отдельных символьных констант, указанных в списке инициализации. Например, предыдущее объявление эквивалентно следующему char string1[]= { 'h', 'e', 'l', 'l', 'o', 'Так как строка является символьным массивом, можно получить доступ к отдельным символам, как к элементам массива. Например, string1[0] – символа символ Пример Строки как массивы символов using std::cin; using std::cout; using std::endl; int main() { char массив из 20 символов //19 для хранения символов строки и 1 завершающий string2 [] = строка символов" ; //массив из 16 символов //15 исходных и 1 завершающий cin>> string1; //cin читает символы с клавиатуры до тех пор, пока не встретится символ разделитель символы строки string1:" < for ( int i=0; string1[i] != '\0' ; ++i) пока не встретился cout< ' ' ; символ конца строки, вывод символов строки через пробел строка вывод символов строки string2 system( "pause" ); return 0; } Для обработки строк можно использовать функции стандартной библиотеки заголовочный фалйл , например strlen – длина строки strcpy, strncpy – копирование символов одной строки в другую strcmp, strncmp – сравнение срок strstr – выделение подстроки strtok – выделение лексем (подстрок, ограниченных определенным символом) 34 Пример 3_2_2. Использование функции strlen() #include #include using std::cout; int main() { функция strlen – длина строки char * str = "12321" ; int k=1; for ( int i=0; i < static_cast < int >(strlen(str)/2); ++i) { if ( str[i] != str[strlen(str) - i - 1] ){ // -1 обязательно, иначе выход заграницу массива k=0; break ; } } k ? cout<< "true\n" : cout<< "false\n" ; в данном случае – "true" system( "pause" ); return 0; } Указатели и ccылки Все обращения в программе к переменной по ее имени заменяются компилятором на адрес пямяти, где хранится значение переменной. Программист может определить собственные переменные для хранения адресов областей памяти. Такие переменные называются указателями. Указатель – это производный тип, который предназначен для хранения адреса. Значение указателя – адрес памяти. Значение указателя сообщает о том, где размещен какой-либо объектно не сообщает о том, какое значение имеет этот объект. Операция разыменования или разадресации , применяемая к указателю, позволяет получить доступ к значению, адрес которого хранится в указателе. Объявление указателя тип *имя_указателя; // тип тип данных, адрес которых хранит указатель имя_указателя – имя_переменной Например: int x = 5; // x целая переменая int *ptr_x; // ptr_x указатель на целую переменную void *ptr_v; // ptr_v обобщенный указатель Переменной ptr_x присваивается адрес переменной Операция & применима только к переменной это операция // взятия адреса Операция * – это операция разыменования, которая // возвращает значение, находящееся по адресу, записанному в // указателе. В данном примере y получит значение 5. // Данное определение y эквивалентно int y = x ptr_x = static_cast // указателя к типизированному указателю // ptr_x получит значение ptr_ v 35 Указатель на константу и константный указатель. Указатель может быть константой или переменной, а также указывать на константу или на переменную. Если const стоит слева от звездочки, то это указатель на неизменяемые данные, если справа, то сам указатель константа. Например int x; // x целая переменая const int cx=1; // cx целая константа * ptr_x; // ptr_ x указатель на целую переменную const int* ptr_cx; // указатель на целую константу int* const сука за тел ь - константана целую переменную const int* const сptr_cx=&сx; //cptr_cx указатель- константана целую константу Не константный указатель на константу (в примере ptr_cx ) "охраняет" значение данных, размещенных поэтому указателю. Указатель изменить можно, данные нельзя. Константный указатель напер ем е н н ую (в примере cptr_x ) "охраняет" область памяти, выделенную для размещения данных – указатель изменить нельзя. При этом значения данных поэтому указателю можно изменять входе выполнения программы. Арифметические операции с указателями позволяют изменить как значение самого указателя, таки данных, которые «храняться по указателю. Например int * ptr; // ptr указатель на целую переменную *ptr++ = 10; // Последовательность действий по адресу, записанному в ptr, будет записано значение 10; значение ptr будет увеличено наколи чес т во байт соответствующее его типу. // эквивалентно *ptr = 10; ptr++; (*ptr)++; // значение по адресу ptr будет увеличено на 1 Ссылка – это синоним имени, указанного при инициализации ссылки. Ссылка – это указатель, который всегда разыменовывается. Объявление ссылки тип &имя_ссылки; // тип тип данных, на которую указывает ссылка имя_ссылки – имя_переменной Например: int i; int& rfc = i; // rfc – с ы л кана целую переменную i Р аз ли чай те указатели и ссылки. Указатели и ссылки позволяют неявно ссылаться на другие объекты. Как же тогда решить, когда применять указатели, а когда ссылки Во- первых, запомните, что не существуетнулевых ссылок.Ссылка всегдадо л ж на ссылаться на какой-то объект. Если переменная обеспечивает доступ к объекту, которого может и не быть, то следует использовать указатель. При небходимости ему можно присвоить нулевое знаение. Это подразумевает, что в программе значение указателя следует проверять нар а вен ст вон ул ю , а значение ссылки нет. Другое важное различие между указателем и ссылкой заключается в том, что указателю можно присваивать различные значения для доступа к разным объектам. Ссылка же всегда указывает на один и тот же объект, заданный при ее инициализации. |