Структурное прогр С++

Основные понятия
Программа на языке С++ представляет собой совокупность функций. Обязательно присутствует хотя бы одна функция main() или WinMain(), которая являются точкой входа в программу. С нее обычно начинается выполнение программы. Пользователь может сам определять функции или использовать более тысячи библиотечных функций.
Определение функции состоит из заголовка и блока выполняемых функцией операторов.
Заголовок включает тип возвращаемого функцией значения, имя функции и в круглых скобках - список параметров функции разделенных запятыми. Блок представляет собой совокупность объявлений локальных переменных, операций, операторов и вызовов других функций, заключенную в фигурные скобки. Для возврата результата функции используется зарезервированное слово return с последующим выражением, которое подсчитывается и его результат ставится в соответствие вызову функции.
Каждая программа включает в себя директивы препроцессора, начинающиеся с символа #. Препроцессор представляет собой программу, обрабатывающую текст программы пользователя до компиляции. Управление препроцессором осуществляется из программы пользователя при помощи специальных команд – директив. Чаще всего используются директивы #define и #include.
Директива #define позволяет задать имя для некоторого фрагмента текста, такое обозначение называется макроопределением или макросом. Формат записи: #define NAME Текст замены. Препроцессор просматривает текст программы и заменяет NAME текстом замены. Например: #define COUNT 100 в тексте программы все имена COUNT будут заменяться на 100. Традиционно имена макросов записываются заглавными буквами.
Директива #include “имя файла” позволяет включить в текст программы пользователя содержимое указанного файла. Если имя файла находится в кавычках, он должен находиться в текущем директории или необходимо указать путь к нему. Для файлов хранящих заголовки библиотечных функций отведен специальный каталог с именем INCLUDE, в этом случае имя файла помещают в угловые скобки: #include . Для расширений включаемых файлов обычно используются: .h .hpp, но можно включать и файлы с другими расширениями например .с или .срр.
Идентификаторы
Для обозначения переменных, констант, функций и т.д. пользователь может использовать символьные имена – идентификаторы. Они должны начинаться с латинской буквы и могут содержать до 32 символов.
Идентификаторы не должны включать в себя пробелы. В случае необходимости пробел заменяют знаком подчеркивания. Заглавные и строчные буквы считаются разными.
Пример идентификаторов: Doxod_2002, x1, Summ.
Пример простейшей программы
#include //Директива препроцессора для ввода-вывода
float SrBall(float x,float y,float z) //Заголовок функции SrBall с 3-мя вещ. параметрами и вещ. результатом
{ //Тело функции SrBall
float sum,sb; // Объявление локальных переменных sum и sb
sum=x+y+z;
sb=sum/3;
return sb; }
void main() //Заголовок функции main–точка входа в программу
{ float m,f,i; //Тело функции main
cout<<"Программа подсчитывает ср. балл по трем предметам"<<'\n';
cout<<"Введите ваши оценки”<<'\n';// Подсказка
cin>>m; cin>>f; cin>>i;//Ввод данных
cout<<"Первый предмет "< cout<<"Третий - "< cout<<"Средний балл "<}
Все переменные должны быть объявлены до их использования в программе.
Объявление переменных:
Тип Идентификатор; или
Тип Идентификатор1, Идентификатор2, Идентификатор3; для трех однотипных переменных. Точка с запятой заканчивает объявление.
Пример: float x; double y, z ; int i, j, k;
Стандартные типы данных
Тип
Длина
Диапазон

unsigned char
8 бит
0 до 255

char
8 бит
-128 до 127

short int
16 бит
-32,768 до 32,767

unsigned int
32 бит
0 до 4,294,967,295

int
32 бит
-2,147,483,648 до 2,147,483,647

unsigned long
32 бит
0 до 4,294,967,295

long
32 бит
-2,147,483,648 до 2,147,483,647

float
32 бит
3.4 x 10-38 до 3.4 x 10+38

double
64 бит
1.7 x 10-308 до 1.7 x 10+308

long double
80 бит
3.4 x 10-4932 до 1.1 x 10+4932


Как видно из таблицы типы данных отличаются по занимаемому объему памяти и допустимому диапазону изменения. Выбор того или иного типа определяется характером величины, которую он описывает. Например, для описания возраста студента подойдет тип unsigned char, а для описания возраста динозавра - unsigned long. Три последних типа кроме диапазона отличаются точностью вычислений. Для float это 7-8 значащих цифр мантиссы, для double 16-17.
Представление констант
Арифметические константы, соответствующие переменным целых типов данных, могут быть представлены в десятичной, восьмеричной и шестнадцатеричной системах счисления. Константы в десятичной системе счисления начинаются с ненулевого символа, например 56 64 32767. Восьмеричные константы начинаются с 0 и могут содержать, в зависимости от значения, несколько цифр в диапазоне от 0 до 7. Например – 011 или 077.
Шестнадцатеричные константы начинаются с символов 0x или 0X с последующими цифрами от 0 до F. Например - 0x898 или 0xFFFE.
Для представления вещественных чисел используются две формы: естественная – 3.1416 и степенная - 0.3146E+1.
Символьные константы
Переменные типа char могут использоваться, как для самых коротких целых данных, так и для хранения кодов отдельных символов. Символическая константа представляется в виде символа заключенного в апострофы (одиночные кавычки).
Пример char c; c=’a’; c=’b’;
Для кодов, не имеющих видимого представления на экране, предусмотрены специальные обозначения:
\n ’-переход к началу новой строки (соответствует нажатию клавиши Enter); \t’-горизонтальная табуляция; \a’-звуковой сигнал; \b’-возврат на один символ; \v’-вертикальная табуляция, \r’- возврат каретки.
Такие обозначения называют Escape-последовательности, они используются также для символов кавычка \”’, апостроф ’\’’ и обратный слэш \\’.
Строковые константы
Строковые константы представляют собой последовательности символов заключенные в кавычки – “ Это строковая константа”.
Ввод – вывод данных
Для организации ввода данных используется стандартный поток ввода cin и операция извлечения из потока <<. Для вывода данных используется стандартный поток cout и операция помещения в поток >>. Использование этих средств возможно после директивы
#include
Пример
#include
void main(void)
{ int i;
cout<<”Введите целое число 4 ”;// Строка “Введите целое число 4 ” появится на экране
cin>>i;// Ввод с клавиатуры
cout<<”Вы ввели число”<// на экране “Вы ввели число 4” и переводится строка }

Математические функции
Заголовки большинства математических функций находятся в файле , который необходимо включить в программу. Функции синуса sin(x), косинуса cos(x) , квадратного корня sqrt(x), тангенса tan(x), арксинуса asin(x) , арккосинуса acos(x), арктангенса atan(x), модуля fabs(x) , экспоненты exp(x), степенная функция pow(x,y), логарифм натуральный log(x) и десятичный log10(x) имеют тип аргумента double и возвращают значение типа double.

Приоритет операций языка С++

Группа


Операции






Ассоциативность

1
()
[]
->
::
.






слева - направо

2
!
~
+
-
++
--
&
*
sizeof
new
delete
справа - налево

3
*
/
%








слева - направо

4
+
-









слева - направо

5
<<
>>









слева - направо

6
<
<=
>
>=







слева - направо

7
==
!=









слева - направо

8
&










слева - направо

9
^










слева - направо

10
|










слева - направо

11
&&










слева - направо

12
||










справа - налево

13
?:










слева - направо

14
=
*=
/=
%=
+=
-=
&=
^=
|= <<=
>>=

справа - налево

15
,










слева - направо


[ ] - операция индексирования; Student[i], X[3][2] – выбор элементов массива.
( ) – операция вызова функции; Пример: sin(х).
. – выбор поля структуры; Пример: Product.Cost.
-> - косвенный выбор поля структуры через указатель;
:: -разрешение контекста (унарная операция), делает доступными глобальные переменные из некоторой функции;
Пример: int i=5;
main(){
int i=3;
cout< cout << ::i; //будет выведенно i=5
++ и -- - операции inc и dec. ++C и С++ постфиксная форма имеет более высокий приоритет;
Пример: i++ эквивалентно i = i + 1.
(тип) например (int)x – операция приведения к типу (в примере – к целочисленному типу);
~ - операция побитового отрицания;
! – логическое не;
- - унарный минус (смена знака);
& - определение адреса (унарная операция);
*p – операция извлечения значения из какого-то адреса;
Пример: int i=3, *Ptr;
Ptr = &i;
// В переменную Ptr записывается адрес переменной i.
*Ptr – это выражение возвращает значение объекта, например, переменной i, на который указывает указатель Ptr.
* (умножение), / (деление), % (остаток от деления);
+ (сложение), - (вычитание);
>>, << - побитовые операции сдвиг влево и сдвиг вправо;
Пример: int i=3;
i=i<<2; //i=0112<<2=011002=1210
i=12;
>=, <=, <> - операции сравнения;
==, != - операции отношений (равенство и неравенство);
& - побитовое “и” (бинарная операция);
^ - побитовое XOR;
| - побитовое “или”;
Пример: пусть а = 1011, b = 0110, тогда a&b будет равно 0010, a^b – 1101, a|b – 1111, a<<3 – 1000, ~a – 0100, b>>1 – 0011.
&& - логическое “и”;
|| - логическое “или”;


?: - сравнение (тернарная операция- с тремя аргументами);
Пример: min = a>b? b: a (если выражение (a>b) истина, то результатом будет b, иначе - a).
= - операция присваивания. Если слева и справа от операции присваивания стоит одна и та же переменная, то запись операции присваивания можно сократить. Полный список комбинированных операций присваивания имеет вид: +=, -=, *=, /=, %=, <<=, >>=, &=, ^=, |=.
Пример: x = y = z = 5; S += a;(эквивалентно S = S + a;).
, - последовательность выполнения выражения. Используется в качестве операции и как разделитель.
Пример: 1) for (x=p1, y=p2, i=2; i int i,n; float x,y,z;
2) int i=1; m[ ] = {i, (i=2,i*i), i}

Операторы управления
Оператор if имеет следующий формат:
if (< выражение >) ( оператор 1);
[ else <оператор 2>:] Если выражение отлично от нуля выполняется оператор1, если равно нулю то выполняется оператор 2.
Например, оператор, вычисляющий y = |x|, будет иметь следующий вид: if (x >= 0) y = x; else y = -x;

Для многоальтернативного выбора используется оператор switch:
switch (выражение целого типа) {case значение 1: оператор 1; break; case значение 2: оператор 2; break; [ default:<операторы>;] }
При совпадении результата выражения после switch со значением после case,
выполняется соответствующий оператор.
Если в конце выбранного варианта поместить оператор break , то управление будет сразу передано в конец оператора switch. Когда некоторому значению выражения не соответствует никакая метка, то управление передаётся оператору с меткой default (прочие). Вариант default может отсутствовать.
switch ( Znak ){
case ’+’: y = a + b; break; case -: y = a - b; break; case ’*’: y = a * b; break;
case /’ : y = a / b; break; default : printf(“Недопустимый знак операции \ n”); }
Циклы
Цикл с предусловием:
while (выражение) Оператор;
Пока выражение после while отлично от нуля выполняется Оператор. После while “;” не ставится. Рассмотрим программу, считывающую с клавиатуры предложение и определяющую его длину:
#inciude
#include
main ()
{char ch; int len = 0;
puts(“\n Наберите предложение, затем нажмите :\n”);
while ((ch = getch())!=’\r’) { putch(ch); len++;}
printf(“\n Ваше предложение имеет длину %d символов. \n”,len); }

Цикл с постусловием
do
<Оператор> ;
while(<выражение>);
Пока выражение после while отлично от нуля выполняется Оператор.
Пример деления двух чисел a и b:
#include
void main()
{ float a,b,FDiv;
char Symbol;
Symbol='y';
do
{cout<<'\n'<<"Введите два числа: ";
cin>>a; cin>>b;
if (b<=0.1E-6) cout<<'\n'<<"Внимание! Деление на ноль!"<<'\n';
else {FDiv=a/b;
cout<<'\n'<<"Результат деления: "<<'\n'< cout<<'\n'<<"Повторить ввод чисел a,b?"<<'\n';
cout<<"('y' - да; остальные - нет)"<<'\n';
cin>>Symbol;}
while (Symbol=='y');}


Цикл с параметром
for (выражение 1; выражение 2; выражение 3) оператор;
Выражение 1 – для инициализации параметра (вычисляется только один раз перед началом выполнения цикла) Выражение 2 – для проверки условия окончания цикла (выполняется перед каждым шагом цикла)
Выражение 3 – для модификации параметра (вычисляется в конце каждого выполнения тела цикла, используется для коррекции значения параметра цикла)
Пример вычисления суммы n целых чисел:
#include
void main()
{ int i, Summa ,n;
cout<<'\n'<<"Сколько целых элементов надо сложить? ";
cin>>n;
Summa=0;
for (i=1;i<=n;i++)
Summa+=i;
cout<<'\n'<<"Сумма: "<
Классы памяти переменных
Каждая переменная принадлежит к определенному классу памяти. Эта принадлежность определяет область видимости и время жизни переменной. Традиционно классов памяти 4 (всего 5). Они определяются спецификаторами auto, register, extern, static, volatile.
Пример: static int x;
По умолчанию класс переменной определяется местом ее объявления. Это, как правило, auto или extern.
Если переменная объявлена вне функции – это внешняя переменная (extern). Если переменная объявлена внутри функции – это автоматическая переменная (auto).
Автоматические переменные.
При традиционном объявлении внутри блока auto писать не надо. Область видимости автоматических переменных: от точки объявления до конца блока, в котором она объявлена, т.е. доступ к ним извне блока невозможен. До входа в блок переменной не существует. Время жизни – время работы функции, в которой она объявлена. При объявлении автоматические переменные не инициализируют нулями.
Регистровые переменные.
Пример: register int z;
Такое объявление не носит директивного характера. Переменная помещается не в оперативную память, а в регистрах микропроцессора. Сейчас применяется редко. Это указание необязательно для компилятора. Обычно этим спецификатором помечают типы short и int и указатели (локальные переменные).
Внешние переменные.
Все переменные, объявляемые вне функций без спецификатора по умолчанию считаются внешними. Это глобальные переменные. Их область видимости – от точки описания до конца файла, где они описаны, во всех модулях. Время жизни – все время работы программы. Память под них выделяется не в стеке. Внешние переменные автоматически инициализируются нулями. Внешние агрегатные переменные во всех компиляторах можно инициализировать в точке объявления. Пример: extern int z = 5;

Распределение памяти
Код
Прог-
раммы

Внешние
и
Статические
данные
Динамически
Распределенная
память

Стек


Массивы
Массив- совокупность данных одного типа.
Тип <имя> [количество элементов]; - обычный одномерный массив. Этот массив выделяется один раз и держит память занятой в зависимости от принадлежности к определенному классу памяти.
void f( )
{ объявление массива}
После выхода из блока место в стеке очищается – это локальный массив.

Тип <имя>[количество элементов][количество элементов]; - двумерный массив. В памяти компьютера двумерный массив располагается последовательно по строкам. Расположение многомерного массива в памяти можно определить по правилу, что быстрее всего изменяется последний индекс. Для доступа к элементу массива используется специальная операция индексирования. Значения индекса начинаются с 0. Последний индекс равен количество элементов минус один. Контроль выхода за границы массива возлагается на программиста.

Пример:
int A[3] ; //объявление массива из 3х элементов целого типа выделяется 3*sizeof(int) байт памяти
A[0]=11; // присваивание первому элементу значения 11
cout<++A[0];//Увеличение первого элемента на 1
cout<
Инициализация.
int A[3] = {6,7,8};
Компилятор выделяет 4*количество элементов, в данном случае 4*3=12 байт. int A1[2] [2] = {{3,4},{5,6}}; Объявление массива типа char: char A[10];
Инициализация массива типа char char s1[6] = {Р’, Г’,’Р’,’Т’,’A’, \0’}; В конце объявления массива типа сhar надо вставить’\ 0’ – символ терминатор, по этому символу определяется конец строки: char s1[ ] = {Р’,’Г’,’Р’,’Т’,’А’,\’0’}. Чаще используется другой вариант инициализации:
char s2[ ] = “РГМУ”,
терминатор в этом случае автоматически добавляет компилятор.
Пример: подсчет среднемесячной температуры
float Srtemp(float mastemp[ ], int kol_day)
{int i; float s=0;
for(i=0;i s+= mastemp[i];
return s/ kol_day;}
Вызов функции для массива температур марта- float Mart[31] , st;
st= Srtemp (Mart,31);
Указатели Указатели – переменные, позволяющие хранить адрес. Объявление указателя тип * имя_указателя;
Компьютер выделяет 4 байта памяти по умолчанию для хранения адреса. Пример: char * s3; //s3 хранит адреса типа Char
char * s3 = “Рязань”; //в данном случае s3 трактуется не только как адрес, а и как символьная строка длиной 7 байт начальный адрес которой записан в s3. Указателям до их использования необходимо задавать начальные (инициализирующие) значения.
Например, int* px=NULL; // NULL зарезервированное значение адреса
int x,*px1; px1=&x; // переменной указателю px присваивается значение адреса переменной x.
<тип > - необходим, чтобы компилятор мог определить на сколько байт осуществляется перемещение при ++ или --.
Связь одномерных массивов с указателями.
Имя массива представляет собой константу – указатель на первый элемент массива. Иначе говоря – адрес первого элемента.
Например, для массива int A[3]; А ==&A[0]. Для извлечения значения по какому либо адресу можно применить операцию разадресации:
*А == А[0].
Для i - го элемента *(А+I) == A[I].

Связь двумерных массивов с указателями.
int B[10][10]; B [0] – адрес первого элемента первой строки.
( B[0] + j)- адрес j – ого элемента первой строки.
*(B[0] + j) – извлекается j – ый элемент первой строки.
*(*(B+i)+j ) – значение j – ого элемента i – ой строки.
Пример:
Определить средний балл за сессию из пяти экзаменов у трех студентов.
#include
#define NSt 3
#define NBal 5
void main()
{ int i,j,SumBal;
int Exams[NSt][NBal];
float SrBal;
//ввод оценок для студентов
for (i=0;i { cout<<’\n’<<”Оценки для студента N"< for (j=0;j cin>>Exams[i][j];}
//вычисление среднего балла для каждого студента
for (i=0;i { SumBal=0;
for (j=0;j SumBal+=Exams[i][j];
SrBal=SumBal/NBal;
cout<<’\n’<<”Средний бал для студента N”< }}

Динамические массивы.
Для того, чтобы использовать функции динамического распределения памяти, нужно включить в программу заголовочный файл #include .
Заказ динамической памяти осуществляется с помощью функции malloc(<необходимое число байт>), которая возвращает указатель на начало заказанной памяти. Если в качестве параметра поставить ноль, функция возвращает указатель на NULL.
Указатель на тип void, возвращаемый функцией, можно преобразовать к любому типу используя операцию (тип*).
Приведем фрагмент программы, позволяющий выделить память под 20 элементов массива целых чисел:
int *p;
· // Указатель на переменную типа int.
p = (int*) malloc(40); // Переменная р содержит адрес первого байта //массива целых чисел, под который выделено //40 байт.
В приведенном примере выделяется 40 байт оперативной памяти, если программа будет транслироваться компилятором, имеющим другой размер типа int, то она будет работать некорректно. Поэтому вместо числового значения размер необходимой памяти лучше записать так: malloc(20*sizeof(int));
Если свободной динамической памяти нет, то malloc возвращает 0.
Функция free(p) освобождает память, т.е. возвращает ее системе.
Для динамического распределения памяти существует также операция new. Выражение a = new int[size]; является динамическим запросом на выделение памяти для массива в size целых элементов. Эта операция возвращает указатель на первый элемент этого массива. Адрес этого элемента присваивается адресной переменной а. Если операция new не может выделить требуемый фрагмент памяти, то возвращает нуль.
Для освобождения памяти используется операция delete[] a.
Для обращения к элементам динамического массива используются те же средства что и у обычного массива – операции индексирования а[i] или разадресации *(a+i) .

Строки

Поддерживаются строки заканчивающиеся нуль символом, т.е. строки практически не ограниченной длины. Для работы с ними есть несколько десятков библиотечных функций. Для использования которых необходимо включить заголовочный файл .

Прототип функции Назначение функции
char *strcat(char *s1, const char *s2)
Слияние строк, возвращает
начало строки s1

char *strcpy(char *s1, const char *s2)
Копирует строку s2 в строку s1

char *strstr(const char *s1, const char *s2)
Ищет первое вхождение в строке s1 подстроки s2. Возвращает указатель на тот элемент s1, с которого начинается подстрока s2

int *strcmp(const char *s1, const char *s2)
Сравнение строк. Возвращает 0, если строки совпадают; >0, если s1>s2; <0,если s1
unsigned strlen(char *s)
Вычисляет длину строки без нуль - символа


Пример:
Осуществить поиск слова в строке и заменить его на другое.

#include
#include
#define NStr 100
#define NWord 10

//Функция поиска и замены
void SearchChange(char *S,char *W,char *WC)
{ char *PosStr=NULL;//указатель на первое вхождение подстроки
char ResStr [120];//измененная строка
while(strstr(S,W)!=0)//пока в строке есть искомое слово
{PosStr=strstr(S,W);//первое вхождение искомого слова
strcpy(ResStr,S);//создание дубликата исходной строки
ResStr[strlen(ResStr)-strlen(PosStr)]='\0';//перенос конца строки до искомого слова
*PosStr=S[strlen(ResStr)+strlen(W)];//остаток строки после искомого слова
strcat(ResStr,WC);//соединение строки и заменяемого слова
strcat(ResStr,PosStr);//соединение строки и остатка
strcpy(S,ResStr); };}

main(){
char String[NStr];
char Word[NWord];
char WordCh[NWord];
cout<<"Введите строку:"< cout<<"Введите слово для поиска и замены:"< cout<<"Введите слово для вставки:"< if (strstr(String,Word)==0) cout<<"Такого слова нет!"< else{
SearchChange(String,Word,WordCh);
cout<<"Новая строка: "<



Функция пользователя.
Существует две категории:
объявление (прототип). Используется, если вызов функции предшествует объявлению. Объявление представляет собой заголовок функции. В этом заголовке должны быть указаны:
Тип возвращаемого функцией значения;
Имя функции (идентификатор);
В круглых скобках типы и имена формальных параметров;
Объявление заканчивается ;’.
определение. Включает в себя заголовок и блок (;’ после блока не ставится). Внутри блока находятся описания локальных переменных и код реализации функции (т.е. действия). Блок заключается в фигурные скобки.
Функция может вызываться в операторе присваивания, в качестве параметров других функций, и самостоятельно (как процедура в Паскале).
Функции в С++ равноправны, любая функция может быть вызвана из любой другой, допускается рекурсивный вызов функций.
Функция main представляет собой точку входа в программу (т.е. ее компилятор запускает первой).
Для возврата результата функции используется зарезервированное слово return с последующим выражением, которое подсчитывается и его результат ставится в соответствие вызову функции.
Передача параметров в функции.
1) по значению:
Параметры, передаваемые по значению, являются входными, т.е. изменить их в функции и возвратить назад в программу нельзя.
Пример: функция сложения чисел.
int Sum(int x, int y)
{int S;
S= x + y;
return(S); }
Вызов такой функции: Sum(x1, y1)
2) по адресу: Например, необходимо возвратить из функции 2 значения. Передаются не значения параметров, а их адреса. Пример: Функция обмена двух переменных. void Obmen (int*x, int *y)
{int temp; temp = *x;
*x = *y;
*y = temp;}
Вызов такой функции: Obmen (&x1,&y1)
3) по ссылке:
void Swap(int &p1, int &p2)
{int temp;
temp = p1;
p1=p2;
p2 = temp;}
Вызов такой функции: Swap(x1,y1)

Параметры по умолчанию

Пусть объявлена некоторая функция float f(float a; float b=5; float c=0){}
Вызов такой функции может быть следующим: f(4,6,8); f(4,6); f(4);
Неправильным будет вызов f(4,,3), поэтому рекомендуется сдвигать параметры, имеющие значения по умолчанию, в заголовке функции вправо.

Встроенные функции.

Вводятся при помощи спецификатора inline и используются для повышения быстродействия. inline float Sum(float a1,float a2) {return a1+a2}
Вызов осуществляется не через стек, а подстановкой кода функции в место ее вызова.
Ограничения: - 5 операторов максимум; - не должно быть операторов цикла; переключателей и goto.
Перегрузка функций
В языке С++ можно определить несколько одноименных функций, отличающихся количеством и типом параметров. Нельзя перегружать функцию, если она отличается только типом возвращаемого значения. Пример перегрузки функции: Определить одноименные функции, которые считают площади круга и треугольника. float S(float r) // площадь круга
{puts(“s круга “);
return 3.14*r*r}
float S(float x, float H)
{puts (“s треугольника”);
return 1\2 * x*H}

Параметры функции main.
int main (int argc, char * argv[ ] ) argv[ ] - массив символьных строк из командной строки DOS
argv[ 0] – полное имя файла с маршрутом к каталогу, где хранится программа. argv[ 1] первый параметр после имени программы в командной строке, argv[ 2] - второй и т.д.
Параметр argc определяет количество параметров в командной строке, не может быть меньше 1

Передача функции в качестве параметра.
Имя функции – адрес начала ее кода в оперативной памяти. Для хранения таких адресов необходимо определить указатель на функцию.
Это можно сделать, определив тип функции и затем объявить указатель на этот тип:
typedef float ft (float) ; ft *ftp;
Возможна другая запись:
typedef float(*ftp)(float) – объявление типа – указателя на функцию возвращающую значение типа float и имеющую 1 параметр типа float. Пример: программа с меню из двух пунктов
typedef void(*mn)( );
mn M_c[2]
void vb1( )
{ puts (“Выбор 1”); getchar ( );}
void vb2 ( )
{ puts (“Выбор 2”); getchar( );}
void b_t ( )
{ M_c [0] = vb1;
M_c [1] = vb2;}
main (void)
{ int c ;
b_t ( );
do { puts (“Выбор 1”);
puts(“выбор 2”);
puts(“Выход “);
cin< if (c >=1 && c<=2)
(*M _c [ c- 1 ]) ( );
else break;}
while (1);}

Шаблоны функций
Шаблоны представляют собой обобщающие определения функций, из которых компилятор может автоматически сделать функцию с заданными параметрами. Шаблоны позволяют пользователю оперировать параметризованными типами. Нет необходимости переписывать функцию при изменении типа параметра.
template < список аргументов>
Тип возвращаемого значения имя функции ( список параметров функции) {тело функции}
Функция обмена.
template void Exchange (T&x , T &y) {T temp;
temp=x; x =y; y = temp; }
Вызываются шаблонные функции, как обычные.
Пример вызова:
float x=3.6, y=7.5;
char c=3, b=5;
Exchange(x,y);
Exchange(c,b);
Шаблоны функций можно специализировать, т. е. для типов данных, которые не подходят к шаблону можно определить специальную функцию с тем же именем. Пример со строками:
В этом случае при вызове функции компилятор пытается:
Найти функцию, параметры которой точно соответствуют параметрам в вызове.
Ищет шаблон, из которого можно сгенерировать функцию с указанным параметрами.
Рассматривает функцию на предмет преобразования типов.

Структуры и объединения
Структура – это объединенное в единое целое множество компонентов. Компоненты структуры могут быть разных типов и все должны иметь различные имена. Структура- аналог записи в Паскале.
struct <имя типа (тэг)>
{ тип поле 1;

тип поле n;} <объявление переменной-структуры>;
// для глобальных переменных
Объявить переменную можно потом, вместе с остальными.
Пример:
struct ShowMan
{ char name[20];
char age;
int hight; };
ShowMan D = {“Децл”,18,150};
ShowMan *PD;
PD = &D;
Обращение к полю структуры: D.name.
При вводе, перед полями, представляющими собой символьные массивы, & не ставится.
(*PD).name равносильно PD->name.

Пример массива записей:
ShowMan cinema[20];
(cinema + i)->name (обращение к i-му элементу массива).
ShowMan *p = new ShowMan; (выделение памяти и преобразование указателя на тип ShowMan).
ShowMan *p = new ShowMan(“Денис Ричи”,100,100);
.
Delete p;

Объединение
Объединение – это тип данных, позволяющий экономить память, т. к. делает возможным хранение разнотипных данных в одной области памяти (в разное время).
Основное свойство объединения состоит в том, что все его элементы размещаются от начала одного и того же участка памяти.

Пример:
#include
union Ud
{ char a[10]; // Размер участка памяти, отводимого для объединения,
float b; // определяется размером самого большого из элементов
double z; };

REGS – используется для обращения к переменным, проецируемым на регистры процессора.
REGS a;
a.x – обращение ко всему регистру;
a.h – обращение к старшему байту;
a.l – обращение к младшему байту.
Недостатком объединений является плохая переносимость из- за обращения к памяти.

Битовые поля
Битовые поля – это тип данных, позволяющий экономить память. Используется для хранения целых значений в малых объемах памяти.

Пример описания структуры:
struct B
{ int a:3; // В данном примере 3 описанных подряд битовых
int b:3; // поля будут помещены в один байт
int d:2; };


Пример работы со структурой :
#include
#include
//Описание структуры «человек»
struct man { char fam[15];//фамилия
char name[10];//имя
int vozr;//возраст
int wes;//вес
int rost;//рост
};
//Функция ввода компонентов структуры «человек»
// x- указатель на структуру «человек», n- кол-во человек
void vvod(man* x, int n)
{int i;
for(i=0;i<=n-1;i++)
{cout<<" Номер студента "< cout<<" Фамилия "; cin>>(x+i)->fam;
cout<<" Имя "; cin>>(x+i)->name;
cout<<" Возраст "; cin>>(x+i)->vozr;
cout<<" Рост "; cin>>(x+i)->rost;
cout<<" Вес "; cin>>(x+i)->wes;
} return ;
}
//Функция вывода компонентов структуры «человек»
// x- указатель на структуру «человек», n- кол-во человек
void vivod(man* x, int n)
{int i;
for(i=0;i<=n-1;i++)
{cout<<" Номер студента "< cout<<" Фамилия "<<(x+i)->fam;
cout<<" Имя "<<(x+i)->name;
cout<<" Возраст "<<(x+i)->vozr;
cout<<" Рост "<<(x+i)->rost;
cout<<" Вес "<<(x+i)->wes<<'\n';
} return ;
}
//Функция вывода компонентов структуры «человек»
// x- указатель на структуру «» человек, i- номер человека
void vivod1(man* x, int i)
{cout<<" Номер студента "< cout<<" Фамилия "<<(x+i)->fam;
cout<<" Имя "<<(x+i)->name;
cout<<" Возраст "<<(x+i)->vozr;
cout<<" Рост "<<(x+i)->rost;
cout<<" Вес "<<(x+i)->wes<<'\n';
return ;
}
//Функция поиска человека по заданной фамилии
// x- указатель на структуру «человек», n- кол-во человек
// st- искомая фамилия
int Findfam(man* x, int n, char* st)
{int i, flag=0;
for(i=0;i<=n-1;i++)
if(strcmp((x+i)->fam,st)==0)// если человек с такой фамилией есть
{ flag=1; return i;} // возвращаем его номер
if (flag==0)
{cout<<"Человека с такой фамилией нет!"<<’\n’; return -1;}
}
//Функция поиска людей ростом выше заданного
// x- указатель на структуру «человек», n- кол-во человек
// trost- сравниваемый рост
void Findlong(man* x, int n, int trost)
{int i, flag=0;
for(i=0;i<=n-1;i++)
if((x+i)->rost>trost) // если есть человек ростом выше заданного
{flag=1; vivod1(x,i); }// производим вывод этого человека
if (flag==0)
cout<<" Людей ростом выше, чем "< return ;
}


void main()
{int i, k, tr;
char tempfam[20];// некоторая фамилия
man* a;// указатель на массив структур
cout<<"Кол-во студентов: "<<’\n’;
cin>>i;
a=new man[i]; // выделение памяти под массив из i структур
if (a!=0)// если есть память
{vvod(a,i); vivod(a,i);//вызов функций ввода и вывода
cout<<"Введите фамилию студента, которого будем искать: "<<’\n’;
cin>>tempfam;
k=Findfam(a,i,tempfam);//номер студента с искомой фамилией
if(k!=-1) vivod1(a,k);
cout<<"Введите рост, c которым будем сравнивать студентов:"<<’\n’;
cin>>tr;
Findlong(a,i,tr);//вызов функции поиска людей по росту
delete a;//освобождение выделенной памяти
} else cout<<”Памяти нет!”
Файлы
Поддерживается два типа файлов текстовые и бинарные. Текстовые файлы можно просмотреть и изменить любым редактором. Информация в бинарных файлах записана в том же виде, что и в оперативной памяти компьютера, т.е. программа чтения такого файла, “знает” последовательность и типы записанных данных. Работа с этим видом файлов происходит немного быстрее, т.к. не надо форматировать данные, однако они хуже переносимы.
Типовые операции с файлами
Объявление – включить заголовочный файл и объявитьFILE* name;
Для открытия файла используется функция
name =fopen( “имя_файла”, “режим” );
Функция возвращает значение 0 , если файл открыть не удалось и ненулевое значение в случае успеха. Первый параметр – имя файла на уровне операционной системы, второй показывает, что делать с файлом (записывать, добавлять или читать информацию). Режимы: "r" открыть файл для чтения , "w" открыть пустой файл для чтения, если файл существует его содержимое уничтожается, "a" открыть файл для добавления в конец файла, если файл не существует, то создается новый файл , "r+" открыть файл для чтения и записи, файл должен существовать,"w+" открыть пустой файл для записи и чтения, если файл существует его содержимое теряется, "a+" открыть файл для чтения и записи в конец файла.
Функции форматного ввода и вывода данных

fprintf(name,“<управляющая строка>”[, <список аргументов>])
fscanf (name,“<управляющая строка>”[, <список аргументов>])
Управляющая строка содержит обычные символы, которые выводятся на экран, спецификации преобразования и управляющие символы константы. Каждая спецификация начинается с символа % и заканчивается символом преобразования. Между ними могут записываться “ - ” ,” . ”,” l ”, указываться размер поля или максимальное число символов или цифр для вывода.
Символы преобразования:
d- аргумент преобразуется в десятичное целое со знаком
u- аргумент преобразуется в десятичное целое без знака
o- аргумент преобразуется в восьмеричное целое без знака
x- аргумент преобразуется в шестнадцатеричное целое без знака
c- значением аргумента является одиночный символ
s- значением аргумента является строка символов
g- значением аргумента является вещественное: либо f, либо e
e- значением аргумента является вещественное типа float или double в форме с плавающей точкой
f- значением аргумента является вещественное типа float или double в форме с фиксированной точкой
p- значением аргумента является указатель
Для произвольного перемещения по файлу и прямого доступа к его компонентам используется функция
fseek(name, long offset, int point),
которая устанавливает указатель текущей позиции в файле на offset байт относительно точки отсчета, определенной значением point ( 0- от начала файла, 1- от текущей позиции, 2- от конца файла). Функция возвращает значение 0, если операция выполнена правильно, и –1, если есть ошибка.
Для закрытия файла используется функция fclose(name).

Пример записи в текстовый файл:
(описание структуры man и функций vvod,vivod приведены в разделе «Структуры и Объединения»)


int writefile(man* x,int n)
{ FILE* fp; int i; char namefile[11];
cout<<" Введите имя файла"<<’n’;
cin>>namefile;
fp=fopen(namefile,"w");
if (fp==0) {cout<<"Файл не открыт!"<<’\n’; getch(); return -1;}
else
for(i=0;i<=n-1;i++)
{fprintf(fp,"%s\n", (x+i)->fam); fprintf(fp,"%s\n",(x+i)->name);
fprintf(fp,"%d\n",(x+i)->vozr); fprintf(fp,"%d\n",(x+i)->rost);
fprintf(fp,"%d\n",(x+i)->wes);}
fclose(fp);return 1;}

Вызов данной функции:
writefile(a,i), где a=new man[i].

Пример чтения из текстового файла:
(описание структуры man и функций vvod,vivod приведены в разделе «Структуры и Объединения»)

int readfile(man* x,int n)
{ FILE* fp; int i; char namefile[11];
cout<<"Кол-во студентов: "<cout<<"Введите имя файла"<<’\n’;
cin>>namefile;
fp=fopen(namefile,"r");
if (fp==0) { cout<<"Файл не открыт!"<<’\n’; getch(); return -1; }
else
for(i=0;i{fscanf(fp,"%s",(x+i)->fam); fscanf(fp,"%s",(x+i)->name);
fscanf(fp,"%d",&(x+i)->vozr); fscanf(fp,"%d",&(x+i)->rost);
fscanf(fp,"%d",&(x+i)->wes);}} fclose(fp); return 1;}

Вызов данной функции:
readfile(a,i), где a=new man[i].


Пример записи в бинарный файл:
int writef(man* x,int n)
{FILE* fp;int i;
char namefile[11];
cout<<"Введите имя файла"<<’\n’;
cin>>namefile;
fp=fopen(namefile,"wb");
if (fp==0) {cout<<"Файл не открыт!"<<’\n’; getch(); return -1;}
else
for(i=0;i<=n-1;i++)
{fwrite((x+i),sizeof(man),1,fp); }
fclose(fp) ;return 1;}

Вызов данной функции:
writef(a,i), где a=new man[i].

Пример чтения из бинарного файла:
int readfilebin(man* x,int n,char* namefile)
{FILE* fp;int i;
fp=fopen(namefile,"rb");
if (fp==0){cout<<"Файл не открыт!"<<’\n’; getch(); return -1; }
else
for(i=0;i {fread((x+i),sizeof(man),1,fp);}
fclose(fp); return 1; }

Вызов данной функции:
readfilebin(a,i,namefile), где a=new man[i].

Определение длины файла:
unsigned long filelen(char* namefile)
{FILE* fp;unsigned long DL;
fp=fopen(namefile,"rb");
if (fp==0) { cout<<"Файл не открыт!"<<’\n’; getch(); return -1;}
else {fseek(fp,0,SEEK_END); DL=ftell(fp); }
fclose(fp) ; return DL; }

Вызов данной функции:
dlfile= filelen(namefile);














13PAGE 15


13PAGE 14215





Приложенные файлы

  • doc 26699076
    Размер файла: 173 kB Загрузок: 0

Добавить комментарий