
- •1. Введение
- •2. Элементы языка
- •2.1. Первые программы
- •2.2. Алфавит языка
- •2.3. Комментарии
- •2.4. Типы данных
- •2.5. Целые типы данных
- •2.6. Плавающие типы данных
- •2.7. Константы-строки, или литералы
- •2.8. Директива препроцессора define
- •2.9. Описания
- •2.10. Модификатор const
- •3. Выражения
- •3.1. Операция и выражение присваивания
- •3.2. Арифметические операции
- •3.3. Операции отношения
- •3.4. Логические операции
- •3.5. Побитовые операции
- •3.6. Сдвиги
- •?????3.8. Тернарная или условная операция
- •3.9. Операция следования
- •3.10. Приоритеты операций и порядок вычисления
- •4.6. Оператор выбора switch
- •4.7. Оператор цикла while
- •4.8. Цикл с постусловием do-while
- •4.9. Оператор for
- •4.10. Оператор безусловного перехода
- •4.11. Оператор break
- •4.12. Оператор continue
- •4.13. Оператор return
- •5. Указатели
- •5.1. Определение указателей
- •5.2. Указатели и массивы
- •5.3. Адресная арифметика
- •5.4. Символьные массивы и строки
- •5.5. Многомерные массивы
- •5.6. Указатели и многомерные массивы
- •6. Операция sizeof
- •7. Операции для работы с динамической памятью
- •7.1. Операция выделения памяти new
- •7.2. Операция освобождения памяти delete
- •8. Функции
- •8.1. Определение и вызов функции
- •8.2. Функции. Передача аргументов
- •8.3. Передача многомерных массивов
- •8.4. Указатели на функции
- •8.5. Ссылки
- •8.6. Ссылки в качестве параметров функций
- •8.7. Аргументы по умолчанию
- •8.8. Переопределение функций
- •8.9. Шаблоны функций
- •9. Объявления и определения
- •10. Область существования имени
- •11. Область видимости
- •Здесь будет напечатано
- •12. Классы памяти
- •13. Объявления объектов и типов
- •14. Имена типов
- •15. Синоним имени типа
- •16. Правила преобразования стандартных типов
- •16.1. Явные преобразования
- •16.2. Неявные преобразования стандартных базовых типов
- •16.3. Преобразование производных стандартных типов
- •17. Перечисления
- •18. Классы
- •18.1. Объявление классов
- •18.2. Конструкторы
- •18.3. Деструкторы
- •18.4. Статические члены класса
- •18.5. Указатель this
- •18.6. Статические функции-члены
- •18.7. Указатели на члены класса
- •18.8. Инициализация данных–членов класса
- •18.9. Конструктор копирования и операция присваивания
- •18.10. Дружественные функции
- •18.11. Конструктор и операция new
- •18.12. Вызов деструктора
- •19. Производные классы
- •19.1. Построение производного класса
- •19.2. Защищенные члены класса
- •19.3. Управление уровнем доступа к членам класса
- •19.4. Последовательность вызова конструктора и деструктора при построении производного класса на основе одного базового
- •19.5. Преобразования типов
- •20. Полиморфизм
- •20.1. Раннее и позднее связывание
- •20.2. Виртуальные функции
- •20.3. Абстрактные классы
- •21. Переопределение стандартных операций
- •21.1. Основные определения и свойства
- •21.2. Операции new и delete при работе с абстрактными типами
- •21.3. Использование new при создании динамического объекта абстрактного типа
- •21.4. Операция delete
- •21.5. Преобразование типов
- •22. Некоторые особенности переопределенных операций
- •22.2. Операция [ ]
- •23. Классы и шаблоны
- •24. Списки
- •24.1. Операции над односвязными списками
- •24.2. Двунаправленные и кольцевые списки
- •24.3. Операции над кольцевыми списками
- •25. Стеки
- •25.1. Реализация стека через массив
- •25.2. Реализация стека через динамическую цепочку звеньев
- •26. Двоичные деревья
- •26.1. Определение и построение
- •26.2.Таблицы
- •27. Список литературы
8.2. Функции. Передача аргументов
Передача аргументов по значению. В приведенных выше примерах происходит передача аргументов по значению. Такая передача аргументов означает, что в вызываемой функции для каждого формального аргумента создаётся локальный объект, который инициализируется значением фактического аргумента. Следовательно, при такой передаче изменения значений формальных параметров функции не приводит к изменению значений соответствующих им фактических аргументов.
Рассмотрим, например, вариант функции, возводящей целое x в целую степень n, где используется это обстоятельство.
int power (int x, int n){
for (int p = 1; n > 0; n – –) p* = x;
return p;
}
Аргумент n используется как временная переменная. Что бы ни происходило с n внутри функции power, это никак не влияет на фактический аргумент, с которым первоначально обратились к этой функции в вызываемой функции:
void main (){
…
int n=6, x=3;
x=power(x, n); // n - не меняется.
В случае если функция должна менять свои аргументы, можно использовать указатели. Указатели также передаются по значению, внутри функции создается локальная переменная – указатель. Но так как этот указатель инициализируется адресом переменной из вызываемой программы, то эту переменную можно менять, используя этот адрес.
В качестве примера рассмотрим функцию, меняющую местами свои аргументы:
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);
Пример. Вычисление многочлена по его коэффициентам.
Пусть требуется вычислить многочлены
(1)
в точке x=0.6.
Ввиду важности вычисления многочленов составим функцию, осуществляющую вычисление многочлена степени n
по его коэффициентам Ci. Для эффективного вычисления многочлена используем так называемую схему Горнера (которую на самом деле за 100 лет до Горнера описал Ньютон). Эта схема состоит в том, что многочлен переписывается в следующей форме:
.
При таком порядке вычислений для получения значения Pn(x) требуется лишь n умножений и n сложений.
Коэффициенты многочленов будем хранить в массиве с.
Для вычисления многочленов (1) напишем программу, в которой схема Горнера реализована в функции pol().
#include <iostream.h>
const n = 10;
double pol (int n, double c[ ], double x){
double p=0;
for (int i = n; i >= 0; i – –) p = p*x + c[i];
return p;}
void main(){
double x=0.6, p, c[n] = {1, 0, 2, 4};
p=pol(3, c, x);
cout<<”x= ”<<x<<” Polynom = ”<<p<<’\n’;
c[0]=7;
c[1]=c[2]=c[3]=c[4]=c[5]=1;
p=pol(5, c, x);
cout<<”x= ”<<x<<” Polynom = ”<<p<<’\n’;
c[0]=2; c[2]=1; c[5]=1; c[6]=3; c[7]=2; c[9]=1;
c[1]=[3]=c[4]=c[8]=0;
cout<<”x= ”<<x<<” Polynom = ”<<pol(9, c, x)<<’\n’;
}