Передача параметров по значению и по ссылке

Переменные, в которых сохраняются параметры, передаваемые функции, также являются локальными для этой функции. Эти переменные создаются при вызове функции и в них копируются значения, передаваемые функции в качестве параметров. Эти переменные можно изменять, но все изменения этих переменных будут "забыты" после выхода из функции. Рассмотрим это на примере следующей функции, "меняющей" значения двух переданных ей переменных: #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. А вот вызывать функцию в виде swap(3,5) уже нельзя, поскольку 3 и 5 — это константы, и сделать переменные синонимами констант нельзя.

Вызов функции может обрабатываться двумя разными способами. Если она объявлена встроенной (inline), то компилятор подставляет в точку вызова ее тело. Во всех остальных случаях происходит нормальный вызов, который приводит к передаче управления ей, а активный в этот момент процесс на время приостанавливается. По завершении работы выполнение программы продолжается с точки, непосредственно следующей за точкой вызова. Работа функции завершается выполнением последней инструкции ее тела или специальной инструкции return. Ф-ция должна быть объявлена до момента ее вызова, попытка использовать необъявленное имя приводит к ошибке компиляции. Определение функции может служить ее объявлением, но ему разрешено появиться в программе только один раз. Поэтому обычно его помещают в отдельный исходный файл. Иногда в одном файле находятся определения нескольких ф-ций, логически связанных друг с другом. Чтобы использовать их в другом исходном файле, необходим механизм, позволяющий объявить ее, не определяя. Объявление ф-ции состоит из типа возвращаемого значения, имени и списка параметров. Вместе эти три элемента составляют прототип. Объявление может появиться в файле несколько раз. В объявлении ф-ции описывается ее интерфейс. Он содержит все данные о том, какую информацию должна получать функция (список параметров) и какую информацию она возвращает. Для пользователей важны только эти данные, поскольку лишь они фигурируют в точке вызова. Интерфейс помещается в заголовочный файл.

17. В случае если функция должна менять свои аргументы, можно использовать указатели. Указатели также передаются по значению, внутри функции создается локальная переменная - указатель. Но так как этот указатель инициализируется адресом переменной из вызываемой программы, то эту переменную можно менять, используя этот адрес. В качестве примера рассмотрим функцию, меняющую местами свои аргументы: void swap (int* x, int* y){ int t = *x; *x = *y; *y = t;}

Обратиться к этой функции можно так:

int a = 3, b = 7;
swap (&a, &b);

Теперь а =7, и b=3.

Некоторую особенность имеет использование массивов в качестве аргументов. Эта особенность заключается в том, что имя массива преобразуется к указателю на его первый элемент, т.е. при передаче массива происходит передача указателя. По этой причине вызываемая функция не может отличить, относится ли передаваемый ей указатель к началу массива или к одному единственному объекту. int summa (int array[ ], int size){ int res=0; for (int i = 0; i < size; i++) res+ = array[i];
return res; }
В заголовке int array[ ] можно заменить на int* array, а выражение в теле функции array[i] заменить на *(array+i), или даже на *array ++, т.к. array не является именем массива, и следовательно, не является константным указателем. К функции summa можно обратиться так:
int mas[100];
for (int i = 0; i < 100; i++) mas[i] = 2*i + 1;
int j = summa (mas, 100);




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

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

19. Динамическая память — оперативная память компьютера, предоставляемая программе (процедуре, подпрограмме) при её работе. Динамическое размещение данных означает распределение динамической памяти непосредственно при работе программы или процедуры (подпрограммы). В отличие от этого статическое размещение осуществляется в момент запуска программы или процедуры. На этапе компиляции не известны ни тип, ни количество динамически размещаемых данных. Для хранения переменных может использоваться стек или динамическая память.
чтоб поместить в стек нужно объявить так:

Код C++

int i; // переменная int Cat cat; // объект класса Cat

стек, который и используется в большинстве компиляторов C++ для реализации автоматической памяти. Именно вследствие такой реализации (такого внутреннего устройства) автоматическую память часто называют стеком, а локальные объекты — стековыми. Объекты в стеке размещаются последовательно друг за другом в порядке их определения (см. рис. 11). Выделение памяти в стеке в общих чертах сводится к смещению указателя вершины стека в направлении роста стека на размер размещаемого объекта; освобождение памяти — к смещению указателя вершины стека в обратном направлении на размер удаляемого объекта (помните о вложенности времён жизни локальных объектов). Операции выделения и освобождения памяти в стеке выполняются очень быстро. Размещение объектов в стеке имеет неоспоримые преимущества. Прежде всего, в силу автоматического разрушения объектов: нам не нужно заботиться об удалении стековых объектов, это делает за нас компилятор, генерируя на выходе локального имени из области видимости код разрушения соответствующего ему объекта — код вызова деструктора и освобождения отведённой (в стеке) под объект памяти. Существенное значение имеет и высокая скорость размещения объектов в стеке.

Однако специфика работы со стеком накладывает и определённые ограничения — далеко не все объекты могут быть в нём размещены. Стратегия автоматического удаления не позволит нам создать в функции стековый объект, время жизни которого превышало бы время выполнения функции. Из того, что выделение памяти в стеке возлагается на компилятор, следует, что размер (а значит и тип) размещаемых в стеке объектов должен быть известен на этапе компиляции, что часто бывает невозможно. Простейшая задача обработки массива, размерность и элементы которого вводятся с клавиатуры или из файла, является ярким тому подтверждением. Кроме того, размер стека в большинстве случаев ограничен (для программ, разрабатываемых в среде Microsoft Visual Studio, размер стека по умолчанию — 1 Мб), что приводит к невозможности размещения в нём больших объектов, к примеру, тех же массивов. Средством преодоления рассмотренных ограничений является динамическая память, особенностям работы с которой посвящен следующий раздел.

гмм... Всегда считал, что динамическая память это байты-биты резервируемые в процессе работы (то есть динамически) под хранение данных, а стек это способ хранения данных. Чувствуете разницу? То есть с точки зрения программирования:
вся память - это континент
выделенная память (статически или динамически) - ограждение области под грядки с капустой
стек - правило по которому эту капусту будут высаживать или собирать.
вот такая метафора получилась.

20. Функция - это группа операторов у которой есть имя. Функции позволяют разбить программу на небольшие части, каждая из которых выполняет какую-то небольшую задачу. Обязательными для функции являются два компонента: определение и вызовы.Определение функции Определение функции должно располагаться в глобальной области видимости, до начала функции main. Рассмотрим пример, простого определения: int simple_function () { return 0; }. Определение функции состоит из заголовка и тела. Заголовок фукнции включает в себя:Тип возвращаемого значения: Почти все функции должны возвращать значения. Тип этого значения указывается в заголовке перед именем функции. Вот несколько примеров заголовков функций: int simple_function() float simple_function() char simple_function(). В первом случае функция должна вернуть целое число (int), во втором - вещественное число (float), а в третьем случае - символ (char). Тело функции: Тело функции располагается сразу под заголовком и заключено в фигурные скобки. В теле функции может содержаться сколько угодно операторов. Но обязательно должен присутствовать оператор return. Оператор return возвращает значение: int simple_function () { return 0;}

Вызов функции: После того как создано определение функции, её можно вызвать. int sum (int a, int b){ int c; c = a + b;return c;}

int main(){ int s; s = sum(2,2); // вызов функции cout << s; return 0;}В результате выполнения программы, на экран будет выведено: 4.Вызов функции состоит из идентификатора функции и списка аргументов в круглых скобках. Вот несколько вызовов функции sum:int x = 5;int y = 4;int z;sum(0,1); // 1sum(x,2); // 7sum(x,y); // 9z = sum(x,y); // z = 9Объявление функции может находиться в любом месте программы (за пределами определений функций программы или в любом определении), главное, чтобы оно появилось до первого вызова функции. Если вы не используете объявления, то до первого вызова функции должно стоять определение, которое также может располагаться в любом месте программыБиблиотечные фун-и - это отработанный и протестированный разработчиками код подпрограмм, с помощью которых облегчается создание новых приложений. Любое неразумное изменение библиотечных файлов сделает невозможным их дальнейшее использование и у вас не будет уверенности в правильности полученного результата)например: #include <header.h> (Файлы заголовков, содержащие прототип для функции или определения констант, перечисляемых типов ит.д., используемые функцией).

Наши рекомендации