Лекция 7

advertisement
Лекция 7
1. Модули
Иногда программный код оказывается слишком большим и сложным, чтобы хранить
его в одном файле. В таком коде сложно ориентироваться и при возникновении ошибок их
будет трудно искать и исправлять. К тому же, после исправления отдельных ошибок будет
необходимо перекомпилировать заново всю программу, что при больших объемах может
занять достаточно много времени.
В таких случаях удобнее разбить программу на несколько исходных файлов, которые
обычно называют модулями. Каждый из этих модулей можно компилировать отдельно, а
затем объединить их в процессе построения конечной программы.
Процесс объединения отдельно скомпилированных модулей называется
связыванием (компоновкой).
Чтобы создать отдельные модули программы, необходимо в окне Solution Explorer с
помощью контекстного меню для пункта Source File создать отдельные файлы проекта.
Все они будут иметь расширение .cpp и будут компилироваться отдельно (пункт меню
Build, Compile или Ctrl-F7). Основная программа при этом может содержать только
главную функцию main и прототипы всех остальных функций, которые содержатся в
других модулях. После успешной компиляции каждого отдельного модуля необходимо
выполнить компоновку проекта с помощью пункта Build, Build Solution или клавиши F7.
Далее можно запускать программу на выполнение обычным способом.
Кроме этого, в одном модуле можно использовать функции других модулей. Для
этого в каждом модуле необходимо описать описывать их прототипы. Удобнее создать
заголовочный файл (пункт «Заголовочные файлы в «Обозревателе решений»), в котором
будут описаны все прототипы функций, а затем включить его с помощью директивы
#include. Заголовочные файлы обычно имеют расширение .h.
Рассмотрим создание модулей на примере.
Пример. Разработать программу, которая определяет тип треугольника по его
сторонам (равносторонний, равнобедренный, прямоугольный, обычный или не
существует), а также вычисляет его площадь и периметр. Программа должна запрашивать
стороны треугольника и выдавать на экран меню в следующем виде:
Выберите номер пункта:
1.Периметр
2.Площадь
3.Тип
4.Выход
Заголовочный файл:
treug.h
void tip(float a, float b, float c);
float perimetr(float a, float b, float c);
float square(float a, float b, float c);
Реализация:
Основной модуль – index.cpp
#include <iostream>
#include <iomanip>
#include “treug.h”
using namespace std;
void main()
{
float x,y,z;
setlocale (LC_ALL,"rus");
cout<<"Введите стороны треугольника"<<endl;
cin>>x>>y>>z;
int punkt=0;
while (punkt!=4)
{
cout<<"Выберите номер пункта:"<<endl;
cout<<"1.Периметр"<<endl;
cout<<"2.Площадь"<<endl;
cout<<"3.Тип"<<endl;
cout<<"4.Выход"<<endl;
cin>>punkt;
switch (punkt)
{
case 1:
cout<<"Периметр="<<setprecision(2)<<fixed<<perimetr(x,y,z)<<endl; break;
case 2:
cout<<"Площадь="<<setprecision(2)<<fixed<<square(x,y,z)<<endl; break;
case 3: tip(x,y,z); break;
case 4: break;
default: cout<<"Неверный ввод"<<endl; break;
}
}
}
Дополнительный модуль – module.cpp
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
void tip(float a, float b, float c)
{
int t;
t=0;
if ((a==b)&&(a==c)&&(c==b))
{
cout<<"Равносторонний"<<endl; t=1;
}
if
((a==b)&&(a==c)&&(c!=b)||(a==b)&&(a!=c)&&(c==b)||(a!=b)&&(a==c)&&(c==b))
{
cout<<"Равнобедренный"<<endl; t=1;
}
if ((a*a+b*b==c*c)||(a*a+c*c==b*b)||(c*c+b*b==a*a))
{
cout<<"Прямоугольный"<<endl; t=1;
}
if ((a+b<=c)||(a+c<=b)||(b+c<=a))
{
cout<<"Не существует"<<endl; t=1;
}
if (t==0)
{
cout<<"Обычный"<<endl;
}
}
float square(float a, float b, float c)
{
float p;
p=(a+b+c)/2;
return (sqrt(p*(p-a)*(p-b)*(p-c)));
}
float perimetr(float a, float b, float c)
{
return (a+b+c);
}
2. Указатели
Указатели широко используются в C++. Именно их наличие сделало этот язык более
удобным для системного программирования. Идея работы с указателями состоит в том,
что пользователь работает с адресом ячейки памяти и имеет возможность динамически
создавать и уничтожать переменные.
Как правило, при обработке оператора объявления переменной
тип имя_переменной;
компилятор автоматически выделяет память под переменную в соответствии с
указанным типом:
Доступ к объявленной переменной осуществляется по ее имени. При этом все
обращения к переменной меняются на адрес ячейки памяти, в которой хранится ее
значение. При завершении программы или функции, в которой была описана переменная,
память автоматически освобождается.
Доступ к значению переменной можно получить иным способом — определить
собственные переменные для хранения адресов ячеек памяти. Такие переменные
называют указателями. С помощью указателей можно обрабатывать массивы, строки и
структуры, динамически создавать новые переменные в процессе выполнения программы
(а не на этапе компиляции), передавать адреса фактических параметров.
Указатель — это переменная, значением которой является адрес памяти, по
которому хранится объект определенного типа (другая переменная). Например, если C это переменная типа char, а P - указатель на C, то, значит, в P находится адрес, по
которому в памяти компьютера хранится значение переменной C.
Как и любая переменная, указатель должен быть объявлен. При объявлении
указателей всегда указывается тип объекта, который будет храниться по данному адресу:
Например:
int *p
Звездочка в описании указателя относится непосредственно к имени, поэтому, чтобы
объявить несколько указателей, ее ставят перед именем каждого из них:
float *x, y, *z;
Операция получения адреса обозначается знаком &. Она возвращает адрес своего
операнда. Например:
float a; //объявлена вещественная переменная a
float *adr_a; //объявлен указатель на тип float
adr_a = &a; //оператор записывает в переменную adr_a
//адрес переменной a
Операция разадресации * возвращает значение переменной, хранящееся в по
заданному адресу, то есть выполняет действие, обратное операции &:
float a,b; //объявленs вещественная переменная a и b
float *adr_a; //объявлен указатель на тип float
adr_a=&a;
b = *adr_a; //оператор записывает в переменную b
//вещественное значение, хранящееся по адресу adr_a
Значение одного указателя можно присвоить другому. Если указатели одного типа,
то для этого применяют обычную операцию присваивания . Рассмотрим ее на примере:
#include <iostream>
using namespace std;
int main()
{
float PI=3.14159, *p1, *p2;
p1=p2=Π
cout<<"По адресу p1="<<p1<<" хранится *p1="<<*p1<<"\n";
cout<<"По адресу p2="<<p2<<" хранится *p2="<<*p2<<"\n";
system ("pause");
return 0;
}
Если указатели ссылаются на различные типы, то при присваивании значения одного
указателя другому, необходимо использовать преобразование типов.
Пример
#include <iostream>
using namespace std;
int main()
{
float PI=3.14159; //объявлена вещественная переменная PI
float *p1; //объявлен указатель на float - p1
double *p2; //объявлен указатель на double - p2
p1=Π //переменной p1 присваивается значние адреса PI
p2=(double *)p1; //указателю на double присваивается значение,
//которое ссылается на тип float
cout<<"По адресу p1="<<p1<<" хранится *p1="<<*p1<<"\n";
cout<<"По адресу p2="<<p2<<" хранится *p2="<<*p2<<"\n";
system ("pause");
return 0;
}
В указателях p1 и p2 хранится один и тот же адрес, но значения, на которые они
ссылаются, оказываются разными. Это связано с тем, что указатель типа *float адресует 4
байта, а указатель *double - 8 байт. После присваивания p2=(double *)p1; при обращении к
*p2 происходит следующее: к переменной, хранящийся по адресу p1, дописывается еще 4
следующих байт из памяти. В результате значение *p2 не совпадает со значением *p1.
Указатели можно использовать также для передачи параметров в функцию. Этот
способ аналогичен способу передачи параметров по ссылке.
Для передачи данных по адресу требуется после типа переменной указать символ
«*» (операция разадресации). Чтобы передать в функцию фактический параметр по
адресу, нужно использовать операцию взятия адреса «&».
Если требуется запретить изменение параметра внутри функции, используют
модификатор const (при попытке изменения значения будет выдаваться ошибка
компилятора). Заголовок функции в общем виде будет выглядеть так:
тип имя_функции (const тип_переменной* имя_переменной, …)
#include <iostream>
using namespace std;
int f1(int i) //данные передаются по значению
{
i++;
return (i);
}
int f2 (int* j) //данные передаются по адресу
{
return((*j)++);
}
int f3 (const int* k) //изменение параметра не предусмотрено
{
return (*k);
}
int main ()
{
int a;
cin>>a;
f1(a);
cout<<"f(a)="<<f1(a)<<"\n"<<"a="<<a<<"\n"; //f(a)=6 a=5
f2(&a);
cout<<"a="<<a<<"\n"; //a=6
f3(&a);
cout<<"a="<<a<<"\n"; //a=6
system ("pause");
return 0;
}
Download