Передача аргументов в функции

Динамическое размещение данных

При активации exe-модуля программа размещается в оперативной памяти. Кроме нее там размещаются операционная система и другие программы. Оставшаяся часть оперативной пямяти может использоваться для динамического размещения данных. Эта часть оперативной памяти называется куча (heap). Объем ограничен общим объемом оперативной памяти и организацией работы с ней. Память из кучи выделяется работающей программой и может использоваться ей для своих нужд (обычно для размещения больших массивов данных). В exe-модуль динамическая память не входит.

Динамическое размещение данных в свободной памяти осуществляется с использованием понятия указатель и оператора new.

int *p; // указатель на динамическую переменную

p = new int; // выделение нужного объема памяти для хранения переменной, p присваивается адрес ячейки памяти, в которой будет храниться динамической значение переменной
p=new int(5) // лучше сразу инициализировать значением, иначе в этих ячейках памяти мусор (garbage)

Затем может идти сколь угодно сложный и длинный отрывок программы, в котором эта переменная используется наряду с обычными и другими динамическими переменными. Затем обязательно применяется оператор delete. Время жизни переменных, размещенных динамически, определяется программистом, поэтому во избежание засорения (загромождения) памяти ненужными уже переменными обязательно нужно ее освободить с помощью оператора delete. Если программист недосмотрел, ошибся, забыл освободить использованную в программе память, то возникают "утечки" памяти (memory leak).

delete p; // объект уничтожается, т.е. память освобождается и может использоваться системой для других целей

Динамическое размещение обычно не используется для переменных простых типов вроде int, char, и т.п., для которых гораздо эффективнее размещение в сегменте кода или стеке. Но зато для сложных (составных) типов данных оно используется практически всегда.

Теперь, когда мы знакомы с понятиями указатель и ссылка необходимо вернуться к вопросу передачи аргументов в функции.

1) Передача по значению (call by value)

Значения копируются в переменные-аргументы функции, но сами переменные при этом не изменяются:

void swap(int i, int j)
{
int t=i;
i=j;
j=t;
cout<<i<<j; // 75
}

void main()
{
int i=5;
int j=7;
swap(i,j); // перестановка
cout<<i<<j; // 57
}

2) Передача по указателю (call by pointer)

Не значения копируются в параметры, а передаются указатели на переменные, в которых хранятся переставляемые значения

void swap(int *i, int *j)
{
int t=*i;
*i=*j;
*j=t;
cout<<*i<<*j;
}

...
swap(&i, &j);
cout<<i<<j; // 75
...

Передача массивов в функции осуществляется с использованием именно этого способа.

3) Передача по ссылке (call by reference)

Самый удобный способ, когда передаются ссылки (псевдонимы) на переменные

void swap(int &i, int &j)
{
int t=i;
i=j;
j=t;
cout<<i<<j;
}
...
swap(i, j);
cout<<i<<j; // 75
...

Этот способ позволяет обходится без оператора разыменования.

2.1 Состав стандартной библиотеки C++

Что должно быть в стандартной библиотеке? Все! Но это невозможно, неразумно и все равно недостаточно. Стандартная библиотека C++ -- это набор функций и классов, который должен быть в каждой реализации языка, как основа, эффективно реализующая механизмы:

  • математические функции (в том числе комплексные числа, случайные числа);
  • работа с временем и дата;
  • строковый тип данных и форматные преобразования;
  • ввод/вывод.

STL (Stadard Template Library) -- стандартная библиотека шаблонов. Название обобщенное, может быть не совсем точное, так как ее составляют в основном шаблоны всевозможных контейнеров и алгоритмов их обработки (библиотека контейнеров). Библиотеку составляют:

  • контейнеры (объекты для хранения однотипных данных)
    • последовательные (vector, deque, list);
    • ассоциативные (set, multiset, map, multimap);
  • адапторы (объекты, созданные на основе базовых контейнеров, с измененным интерфейсом: например, queue, stack)
  • итераторы (объекты, которые используются для универсального доступа к элементам хранящимся в контейнере любого типа)
  • алгоритмы (обобщенные процедуры для обработки элементов любых контейнеров)
  • функции-объекты (объекты, у которых перегружен оператор вызова функций operator (): например предикаты, позволяющие без изменения шаблона изменять критерии сравнения элементов контейнера и другие подобные действия)

Это функции, механизмы, которые пользуются широкой потребностью, но многие из них сложны в реализации. Целесообразно осуществить стандартную реализацию этих функций и оформить ее в виде стандартной библиотеки языка С++. Теперь даже начинающий программист может воспользоваться низкоуровневыми функциями и механизмами.

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

Пространства имён

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

namespace std
{
...
double cos(double x);
...
}

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

#include <cmath>
using namespace std;

или

std::cos(0.);

2.2 Организация ввода/вывода

Потоковый ввод/вывод

Один из основных механизмов, который делает программу полезной является ввод/вывод. Все языки программирования имеют такой механизм. Среди операторов и ключевых слов нет ввода/вывода. Потому что в языке С++ ввод/вывод реализован в виде библиотеки. И вообще многие механизмы, которые делают язык С++ таким мощным реализованы в библиотеках (стандартные, специализированные, персональные).

В С++ используется механизм потокового ввода/вывода. Поток - механизм преобразования значений различного типа в последовательность символов (вывод) и наоборот (ввод), в значение переменной.

Вывод: Помещение (направление) данных в поток вывода осуществляется с помощью оператора << который также иногда называют экстрактор (extractor). Конечно, можно создать свой поток вывода, но обычно достаточно стандартных потоков:

  • cout - стандартный поток вывода (экран)
  • cerr - стандартный поток вывода ошибок (экран)

Переменную любого встроенного типа можно вывести используя следующую запись:

cout<<"x="<<x; // переменная x будет преобразована в набор символов

Можно определить операторы потокового ввода/вывода и для созданных абстрактных типов данных.

Ввод: Ввод данных из потока осуществляется аналогично с использованием обратного оператора >> (inserter):

  • cin - стандартный поток ввода (клавиатура)

Переменную любого временного типа можно ввести (считать) из потока:

cin>>x;

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

#include <iostream> // подключение стандартной библиотеки
using namespace std; // объявление об использовании стандартного пространства имен

void main() // функция main
{
cout<<"Data types:"<<endl; // вывод строки
cout<<"int = "<<sizeof(int)<<endl; // вывод строки и целочисленного значения
cout<<"float = "<<sizeof(float)<<endl;
cout<<"double = "<<sizeof(double)<<endl;
}

Форматированный ввод/вывод

В С++ используется механизм потокового ввода/вывода. Поток - механизм преобразования значений различного типа в последовательность символов (вывод) и наоборот (ввод)

#include <iostream>

Примеры, которые приводились выше и ввод/вывод, который вы использовали на практических занятиях до сих пор, обычно называют неформатированным выводом.

Часто программисту нужно более детализированное управление. Управление осуществляется для каждого потока отдельно, т.е. если вы определили какой-то формат для потока ввода, то на поток вывода он не подействует. Более того, управление влияет только на следующее выводимое значение.

#include <iomanip>

Управление можно организовать используя манипуляторы потока, которые вставляются между объектами (записываемыми или читаемыми) и тем самым изменяют состояние потока (формат вывода значений):


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: