Programmirovanie (1)
.pdf1.
При выполнении цикла while сначала проверяется условие. Если оно ложно, то цикл не выполняется и управление передается на следующую инструкцию после тела цикла while. Если условие истинно, то выполняется инструкция, после чего условие проверяется снова и снова выполняется инструкция. Так продолжается до тех пор, пока условие будет истинно.
while (условие)
{
блок инструкций
}
Цикл " while " с постусловием отличается от цикла с предусловием тем, что сначала выполняется блок цикла, а потом проверяется условие. Если условие истинно, то цикл будет выполнен еще раз, и так до тех пор, пока условие будет истинно.
do
{
Блок инструкций
}
while (условие);
Поскольку условие проверяется после выполнения тела цикла, то блок цикла с постусловием всегда будет выполнен хотя бы один раз, независимо от истинности условия.
При использовании цикла for необходимо задать три параметра (в круглых скобках через точку с запятой).
Первый параметр – начальное значение переменной, задается в виде присваивания переменной значения.
Второй параметр – условие выхода из цикла. Цикл будет исполняться, пока условие истинно.
Третий параметр – шаг изменения переменной.
for ((начальное значение переменной); (условие); (шаг изменения переменной))
{
блок инструкций
}
Оператор ветвления — оператор, обеспечивающая выполнение определённой команды (набора команд) только при условии истинности некоторого логического выражения.
if (условие)
{
операторы
}
else
{
Операторы
}
Оператор switch предназначен для организации выбора из множества различных вариантов. Формат оператора следующий:
switch ( выражение ) { [объявление]
|
: |
|
[ |
case |
константное-выражение1]: [ список-операторов1] |
[ |
case |
константное-выражение2]: [ список-операторов2] |
|
: |
|
:
[ default: [ список операторов ]]
}
Выражение, следующее за ключевым словом switch в круглых скобках, может быть любым выражением, допустимыми в языке СИ, значение которого должно быть целым. Тело оператора smitch состоит из нескольких операторов, помеченных ключевым словом case с последующим константным-выражением. Все константные выражения в операторе switch должны быть уникальны. Кроме операторов, помеченных ключевым словом case, может быть, но обязательно один, фрагмент помеченный ключевым словом default.
Список операторов может быть пустым, либо содержать один или более операторов. Причем в операторе switch не требуется заключать последовательность операторов в фигурные скобки.
Отметим также, что в операторе switch можно использовать свои локальные переменные, объявления которых находятся перед первым ключевым словом case, однако в объявлениях не должна использоваться инициализация. Оператор break обеспечивает прекращение выполнения самого внутреннего из объединяющих его операторов switch.
2.
Функция - это совокупность объявлений и операторов, обычно предназначенная для решения определенной задачи. Каждая функция должна иметь имя, которое используется для ее объявления, определения и вызова. В любой программе на СИ должна быть функция с именем main (главная функция), именно с этой функции, в каком бы месте программы она не находилась, начинается выполнение программы.
При вызове функции ей при помощи аргументов (формальных параметров) могут быть переданы некоторые значения (фактические параметры), используемые во время выполнения функции. Функция может возвращать некоторое (одно !) значение. Это возвращаемое значение и есть результат выполнения функции, который при выполнении программы подставляется в точку вызова функции, где бы этот вызов ни встретился. Допускается также использовать функции не имеющие аргументов и функции не возвращающие никаких значений. Действие таких функций
может состоять, например, в изменении значений некоторых переменных, выводе на печать некоторых текстов и т.п.. Определение функции задает тип возвращаемого значения, имя функции, типы и число формальных параметров, а также объявления переменных и операторы, называемые телом функции, и определяющие действие функции. для того, чтобы компилятор мог осуществить проверку соответствия типов передаваемых фактических параметров типам формальных параметров до вызова функции нужно поместить объявление (прототип) функции.
Объявление функции имеет такой же вид, что и определение функции, с той лишь разницей, что тело функции отсутствует.
Функция не может возвращать массив или функцию, но может возвращать указатель на любой тип, в том числе и на массив и на функцию. Тип возвращаемого значения, задаваемый в определении функции, должен соответствовать типу в объявлении этой функции.
Функция возвращает значение если ее выполнение заканчивается оператором return, содержащим некоторое выражение
3.
Переменные, в которых сохраняются параметры, передаваемые функции, также являются локальными для этой функции. Эти переменные создаются при вызове функции и в них копируются значения, передаваемые функции в качестве параметров. Эти переменные можно изменять, но все изменения этих переменных будут "забыты" после выхода из функции.
#include<iostream>
using namespace std;
void swap(int a, int b)
{
int t;
t=b; b=a; a=t;
}
int main()
{
int p=3,q=5;
swap(p,q);
cout<<p<<" "<<q<<endl;
return 0;
}
При вызове функции swap создаются новые переменные a и b, им присваиваются значения 3 и 5. Эти переменные никак не связаны с переменными p и q и их изменение не изменяет значения p и q. Такой способ передачи параметров называется передачей параметров по значению.
Чтобы функция могла изменять значения переменных, объявленных в других функциях, необходимо указать, что передаваемый параметр является не просто константной величиной, а переменной, необходимо передавать значения по ссылке. Для этого функцию swap следовало бы объявить следующим образом:
void swap(int & a, int & b)
Амперсанды перед именем переменной означают, что эта переменная является не локальной переменной, а ссылкой на переменную, указанную в качестве параметра при вызове функции. Теперь при вызове swap(p,q) переменные a и b являются синонимами для переменных p и q, и изменение их значений влечет изменение значений p и q.
4.
Массивы предназначены для хранения множества значений одного типа. Объявление int A[n] создает в памяти одномерный массив: набор пронумерованных элементов, идущих в памяти последовательно. Но можно создать и массив массивов следующим образом: int A[n][m]. Данное объявление создает массив из n объектов, каждый из которых в свою очередь является массивом типа int [m]. Можно объявлять не только двумерные массивы, но и массивы с большим количеством измерений. Например, объявление int A[n][m][l] создает трехмерный массив из n*m*l элементов. нумерация индексов начинается с нуля. Поэтому число индексов всегда на единицу меньше числа элементов массива. Имя массива – это указатель на его 0 элемент.
В С++ существует 2 типа строк.
Первый из них - это массив переменных типа char.
Если кто не помнит, то переменная типа char хранит в себе 1 символ. Размер такой строки равняется размеру массива - 1, т.к. последний элемент содержит NULL (пустая переменная без значения), который обозначает символ конца строки. Например: char name[50];
По форме записи данная конструкция ничем не отличается от указателя на символьную переменную: char *S1; где char – тип указателя на символ, S1 – переменная-указатель. Для инициализации указателя требуется указать область памяти, где уже находится или будет находиться строка, при этом для строки должен быть выделен необходимый объем памяти.
Существует ряд способов инициализации указателя на строку:
·инициализация строковым литералом char *S1="Yes";
·присваивание значение другого указателя char *S1=S;
где S – идентификатор массива или указатель на другую строку символов.
Указателю можно присваивать значение другого указателя: S1=S; где S1 – переменная типа указатель; S – строковая константа, идентификатор массива или указатель на другую строку символов.
Второй из вариантов, более удобный - это специальный класс string
Для его работы необходимо в начале программы подключить заголовочный файл string:
#include <string>
В отличии от типа char, string является классом. Для создания строки вам необходимо в начале программы написать using namespace std; Теперь чтоб создать строку достаточно написать:
string s; Для записи в строку можно использовать оператор =. s="Hello";
Часто возникают ситуации, когда заранее не известно, сколько объектов – чисел, строк текста и прочих данных будет хранить программа. В этом случае используется динамическое выделение памяти, когда память занимается и освобождается в процессе исполнения программы. При использовании динамической памяти (ДП) отпадает необходимость заранее распределять память для хранения данных, используемых программой. Управление динамической памятью – это способность определять размер объекта и выделять для его хранения соответствующую область памяти в процессе исполнения программы.
Для создания динамических переменных в языке C++ используются специальные операторы new и delete. Существуют две формы операторов: для одиночной переменной и массива значений.
Оператор new выделяет область памяти для одиночной переменной, размер которой соответствует ее типу, и возвращает указатель того же типа, так что дополнительных преобразований типа указателя не требуется: float * ptr; ptr=new float; В результате выполнения этого фрагмента программы в динамической памяти будет выделена область размером 4 байта для хранения одного значения типа float, и адрес этой области записан в переменную ptr. Для размещения в памяти нескольких значений одного типа (массива) применяется оператор new[]: float * ptrm; ptrm=new float[4]; при этом в квадратных скобках указывается количество элементов, для которых выделяется память. В результате выполнения этого фрагмента программы в динамической памяти будет выделена область размером 16 байт для хранения четырех чисел типа float, и адрес этой области записан в переменную ptrm. Для освобождения динамической памяти, выделенной при помощи new, используется оператор delete. Для одиночной переменной освобождение памяти имеет следующий вид: delete ptr; при этом освобождается область в динамической памяти размером 4 байта. Для освобождения памяти из-под массива, размещенного с помощью оператора new[], следует использовать следующую форму оператора delete: delete[] ptrm; Следует заметить, что недопустимо смешивать формы операторов new и delete: если память выделялась для одиночной переменной (new), то и освобождение должно производиться оператором delete, если в памяти размещался массив (new[]) – для освобождения памяти должен использоваться оператор delete[].
5.
Структура – тип данных, задаваемый пользователем. В общем случае при работе со структурами следует выделить четыре момента:
-объявление и определение типа структуры,
-объявление структурной переменной,
-инициализация структурной переменной,
- использование структурной переменной.
Определение типа структуры представляется в виде
struct ID
{
<тип> <имя 1-го элемента>;
<тип> <имя 2-го элемента>;
…………
<тип> <имя последнего элемента>;
};
Определение типа структуры начинается с ключевого слова struct и содержит список объявлений, заключенных в фигурные скобки. За словом struct следует имя типа, называемое тегом структуры (tag – ярлык, этикетка). Элементы списка объявлений называются членами структуры или полями. Каждый элемент списка имеет уникальное для данного структурного типа имя. Однако следует заметить, что одни и те же имена полей могут быть использованы в различных структурных типах.
Объявление переменной структурного типа имеет следующий вид:
struct ID var1;
при этом в программе создается переменная с именем var1 типа ID. Все переменные, использующие один шаблон (тип) структуры, имеют одинаковый набор полей, однако различные наборы значений, присвоенные этим полям. При объявлении переменной происходит выделение памяти для размещения переменной.
При размещении в памяти структурной переменной можно выполнить ее инициализацию. Неявная инициализация производится для глобальных переменных, переменных класса static. Структурную переменную можно инициализировать явно при объявлении, формируя список инициализации в виде константных выражений.
Формат: struct ID name_1={значение1, … значениеN};
Внутри фигурных скобок указываются значения полей структуры, например,
struct point pt={105,17};
при этом первое значение записывается в первое поле, второе значение – во второе поле и т. д., а сами значения должны иметь тип, совместимый с типом поля.
Над структурами возможны следующие операции:
-присваивание значений одной структурной переменной другой структурной переменной, при этом обе переменные должны иметь один и тот же тип;
-получение адреса переменной с помощью операции &;
- осуществление доступа к членам структуры.
Присваивание значения одной переменной другой выполняется путем копирования значений соответствующих полей, например:
struct point pt={105,15},pt1;
pt1=pt;
В результате выполнения этого присваивания в pt1.x будет записано значение 105, а в pt1.y – число 15. Работа со структурной переменной обычно сводится к работе с отдельными полями структуры. Доступ к полю структуры осуществляется с помощью операции. (точка) посредством конструкции вида: имя_структуры.имя_поля_структуры;
при этом обращение к полю структуры представляет собой переменную того же типа, что и поле, и может применяться везде, где допустимо использование переменных такого типа. в структуре нельзя использовать методы. Класс это расширенная структура
6.
Указатель - это переменная, содержащая адрес некоторого объекта, например, другой переменной. Точнее - адрес первого байта этого объекта. Пусть x - переменная типа int. Обозначим через px указатель. Унарная операция & выдает адрес объекта, так что оператор px = &x; присваивает переменной px адрес переменной x. Говорят, что px "указывает" на x. Операция & применима только к адресным выражениям, так что конструкции вида &(x-1) и &3 незаконны. Унарная операция * называется операцией разадресации или операцией разрешения адреса. Эта операция рассматривает свой операнд как адрес и обращается по этому адресу, чтобы извлечь объект, содержащийся по этому адресу. Следовательно, если y тоже имеет тип int, то y = *px; присваивает y содержимое того, на что указывает px.
Рассмотрим функции управления памятью:
·malloc() – предназначена для выделения непрерывной области памяти заданного размера,
например, void * malloc(size_t size), где size_t – тип результата операции sizeof. size – размер выделяемой памяти в байтах. Функция malloc возвращает указатель без типа. Если выделить память не удалось, функция возвращает значение NULL..
·calloc() – предназначена для выделения памяти под заданное количество объектов, каждый из которых имеет размер size байт, всего n ´ size байт. Возвращает указатель на первый байт выделенной область памяти. Если выделить память не удалось, функция возвращает значение
NULL: void * calloc(size_t n, size_t size);
·free() – предназначена для освобождения памяти, выделенной функциями malloc(),calloc(),realloc(). После выполнения функции освобожденная память может быть выделена вновь под другие данные: void free(void* ptr); где prt – указатель на область памяти, созданной только функциями динамического управления памятью malloc(),calloc()
Уте́чка па́мяти (англ. memory leak) — процесс неконтролируемого уменьшения объёма свободной оперативной памяти (RAM) компьютера, связанный с ошибками в работающих программах, вовремя не освобождающих ненужные уже участки памяти, или с ошибками системных служб контроля памяти. Утечки памяти приводят к тому, что потребление памяти программой
неконтролируемо возрастает, в результате рано или поздно вступают в действие архитектурные ограничения среды исполнения (операционной системы, виртуальной машины, ЭВМ), и тогда новое выделение памяти становится невозможным. В этой ситуации в программе, которая запрашивает память, обычно происходит аварийная остановка. Это может по стечению обстоятельств произойти и совсем с другой программой после того, как программа, подверженная утечкам, потребит всю память ЭВМ.
Некоторые языки программирования (например, Оберон, Java, языки платформы .NET) предоставляют средства, позволяющие автоматически освобождать неиспользуемую память («сборщик мусора», англ. garbage collector). Сборщики мусора решают также и проблему циклических ссылок, но сборка мусора является ресурсоёмкой операцией. За использование подобных средств приходится расплачиваться быстродействием системы. В системе со сборкой мусора обязанность освобождения памяти от объектов, которые больше не используются, возлагается на среду исполнения программы. Программист лишь создаёт динамические объекты и пользуется ими, он может не заботиться об удалении объектов, поскольку это делает за него среда. Для осуществления сборки мусора в состав среды исполнения включается специальный программный модуль, называемый «сборщиком мусора». Этот модуль периодически запускается, определяет, какие из созданных в динамической памяти объектов более не используются, и освобождает занимаемую ими память. Периодичность запуска сборщика мусора определяется особенностями системы. Сборщик может работать в фоновом режиме, запускаясь при неактивности программы (например, когда программа простаивает, ожидая ввода данных пользователем).
7.
Шаг 1. Текст программы, называемый исходный модуль, подвергается препроцессорной обработке. Специальная программа (препроцессор) сканирует исходный текст и выполняет необходимые действия над текстом программы.
Например, встретив в тексте программы директиву #include, она вместо этой директивы записывает текст того файла, который указан в директиве. В нашем примере директивой
#include <iostream> в тест программы будет добавлено содержимое стандартного файла iostream.
Когда препроцессор встречает директиву #define, то он удаляет её из текста программы и далее по тексту выполняет замену, определенную этой директивой. Например, если в тексте есть оператор s = PI * r * r; и использовалась директива #define PI 3.14159265 то после обработки препроцессором получится так: s = 3.14159265 * r * r;
Шаг 2. После препроцессорной обработки получается полный исходный модуль (чистый текст), который поступает в компилятор. Программа-компилятор выполняет преобразование текста программы с языка С++ в объектный модуль, т.е. в текст на машинном языке. Процесс компиляции очень не прост. Как правило, компиляторы многократно (в несколько проходов) обрабатывают текст программы, выполняя те или иные действия.
Шаг 3. Объектный модуль, полученный в результате компиляции, хотя и представляет собой файл в машинных кодах, но совершенно не пригоден для исполнения компьютером. Почему? Чего ещё не хватает? Всякая программа на С++ использует стандартную библиотеку, поставляемую вместе с компилятором. В ней хранится код большого количества стандартных функций, которые мы сами не пишем, а применяем в готовом виде. Например, математические функции, операции вводавывода и многое другое. Поэтому на данном шаге компоновщик (или по-другому, редактор связей, линкер) к объектному модулю добавляет машинный код всех тех стандартных функций, которые использованы в программе, и прописывает их адреса для вызова. Заметьте себе, не вообще всех, а только необходимых. Кроме того, программа может состоять не из одной функции main(), а содержать ещё множество собственных функций программиста. Каждая из них компилируется по-отдельности, к каждой из них подключаются необходимые стандартные функции, и все они добавляются к выходному файлу. В итоге компоновщик собирает из одного или нескольких объектных модулей плюс необходимых функций из стандартной библиотеки исполняемый модуль, пригодный для выполнения компьютером. Именно исполняемый модуль (исполняемая программа) запускается на исполнение.
8.
В языках программирования Си и C++, заголовочные файлы — основной способ подключить к программе типы данных, структуры, прототипы функций, перечислимые типы, и макросы, используемые в другом модуле. Имеет по умолчанию расширение .h; иногда для заголовочных файлов языка C++ используют расширение .hpp. Чтобы избежать повторного включения одного и того же кода, используются директивы #ifndef, #define, #endif. Заголовочный файл в общем случае может содержать любые конструкции языка программирования, но на практике исполняемый код (за исключением inline-функций в C++) в заголовочные файлы не помещают. Например, идентификаторы, которые должны быть объявлены более чем в одном файле, удобно описать в заголовочном файле, а затем его подключать по мере надобности. Подобным же образом работает модульность и в большинстве ассемблеров. По сложившейся традиции, в заголовочных файлах объявляют функции стандартной библиотеки Си и Си++.
Препроцессор С/С++ — программный инструмент, изменяющий код программы для последующей компиляции и сборки, используемый в языках программирования Си и его потомка - C++. Этот препроцессор обеспечивает использование стандартного набора возможностей:
Замена триграфов ??=, ??(, ??) (и других) символами #, [, ]
Замена комментариев пустыми строками
Включение файла — #include
Макроподстановки — #define
Условная компиляция — #if, #ifdef, #elif, #else, #endif
Важной областью применения препроцессоров С является условная компиляция. При подготовке программы к компиляции разработчик может с помощью нескольких изменений адаптировать программу к текущей ситуации (например, к определенной модели процессора). Препроцессор языка Си — низкоуровневый, лексический препроцессор, потому что он требует только лексического анализа, то есть он обрабатывает только исходный текст перед парсингом, выполняя простую замену лексем и специальных символов заданными последовательностями символов, в соответствии с правилами, установленными пользователями.
Директива #include включает в текст программы содержимое указанного файла. Эта директива имеет две формы: #include "имя файла", #include <имя файла>. Директива #include широко используется для включения в программу так называемых заголовочных файлов, содержащих прототипы библиотечных функций, и поэтому большинство программ на СИ начинаются с этой директивы.
Директива #define служит для замены часто использующихся констант, ключевых слов, операторов или выражений некоторыми идентификаторами. Идентификаторы, заменяющие текстовые или числовые константы, называют именованными константами. Идентификаторы, заменяющие фрагменты программ, называют макроопределениями, причем макроопределения могут иметь аргументы.
Директива #define имеет две синтаксические формы:
#define идентификатор текст
#define идентификатор (список параметров) текст
Эта директива заменяет все последующие вхождения идентификатора на текст. Такой процесс называется макроподстановкой. Текст может представлять собой любой фрагмент программы на СИ
Директивы #if, #ifdef, #ifndef, #else, #elif и #endif используются для избирательной компиляции различных фрагментов программы. Главная идея состоит в том, что если выражение, стоящее после директив #if, #ifdef и #ifndef, оказывается истинным, то будет скомпилирован код, расположенный между одной из этих трех директив и директивой #endif; в противном случае данный код будет опущен. Директива #endif используется для обозначения конца блока #if. Директиву #else можно использовать с любой из перечисленных выше директив для предоставления альтернативного варианта компиляции. Общая форма записи директивы #ifdef такова. #ifdef имя_макроса
Если имя_макроса определено в операторе #define, то будет скомпилирован блок кода, следующий за оператором #ifdef.
9.
Потоки