Главная страница

СИ. Программирование на языке CC Часть Структурное программирование


Скачать 1.65 Mb.
НазваниеПрограммирование на языке CC Часть Структурное программирование
Дата11.02.2022
Размер1.65 Mb.
Формат файлаpdf
Имя файлаAlgLangCpp.pdf
ТипУчебное пособие
#359040
страница9 из 11
1   2   3   4   5   6   7   8   9   10   11
Пример 4.4. Передача параметра по адресу. В листинге
4.8
первые два параметра и передаются, как и прежде, по значению, а третий параметр c
— по адресу (формальный параметр имеет тип указателя. В
теле функции для третьего параметра используется операция разыменования (звёздочка). При вызове функции на месте третьего параметра должно быть указано не имя или значение, а адрес (те. фактическая переменная–указатель или, как в данном случае, операция взятия адреса переменной. Теперь на экран будет выведена сумма двух введённых чисел (заданных при вызове функции на месте первых двух параметров).
Листинг 4.8: Передача параметра по адресу) {
2
*
z
=
x
+
y
;
3
}
4 5
i n t
main
() {
6
double
a
,
b
,
c
=0;
7
cin
>>
a
>>
b
;
8
fun1
(
a
,
b
, &
c
);
// вызов функции будет выведена сумма
10
return
0;
11
}
Передача параметров по ссылке
отсутствовала в языке C, нов именное рекомендуется использовать вместо указателей, когда некоторые параметры функции являются выходными, те. должны передавать вычисленные значения в вызвавшую программу. Как ив случае с указателями, при передаче параметра по ссылке в стек копируется адрес переменной, а нее значение

— 118 Пример 4.5. Передача параметра по ссылке. В листинге
4.9
при определении функции третий параметр является ссылкой, поэтому автоматически разыменовывается в теле функции (звёздочка ненужна. При вызове функции на месте третьего параметра указывается фактическая переменная (операция взятия адреса также не требуется).
Листинг 4.9: Передача параметра по ссылке) {
2
z
=
x
+
y
;
3
}
4 5
i n t
main
() {
6
double
a
,
b
,
c
=0;
7
cin
>>
a
>>
b
;
8
fun1
(
a
,
b
,
c
);
// вызов функции будет выведена сумма
10
return
0;
11
}
Как видим, при использовании ссылок текст программы выглядит более понятным, чем с указателями.
Константные параметры функции.
В некоторых случаях параметр функции приходится передавать по адресу или ссылке, нонам требуется,
чтобы его значение не изменялось при выполнении функции. Перед таким формальным параметром в заголовке функции надо поставить ключевое слово Передача массива в качестве параметра функции.

Напомним, что имя массива — это адрес нулевого элемента. Поэтому массивы не могут передаваться в функцию по значению (это разумно, т. к. при копировании в стек всех элементов большого массива возникло бы переполнение стека. Кроме

— 119 адреса массива в функцию требуется передавать все его размерности. Пример функции для суммирования элементов массива показан в листинге
4.10
Листинг 4.10: Суммирование элементов одномерного массива i n c l u d e

using namespace
std
;
// Ввод элементов массива o r

(
long
i
=0;
i
<
n
;
i
++){
cout
<< "arr[" <<
i
<< "]␣=␣";
cin
>>
arr
[
i
];
}
}
// Вывод элементов массива double
arr
[]
const
){
f o r
(
long
i
=0;
i
<
n
;
i
++)
cout
<< "arr[" <<
i
<< "]␣=␣" <<
arr
[
i
] <<
endl
;
}
// Суммирование элементов массива double
arr
[]
const
){
double
s
= 0;
f o r
(
long
i
=0;
i
<
n
;
i
++)
s
+=
arr
[
i
];
return
s
;
}
i n t
main
(){
long
n
;
setlocale
(0, "");
// Включаем кириллицу cout
<< "Количество␣элементов␣=␣";

— 120 —
cin
>>
n
;
double
*
a
=
new double
[
n
];
arrinput
(
n
,
a
);
// Ввод элементов массива cout
<< "Введён␣массив:␣\n";
arrprint
(
n
,
a
);
// Вывод элементов массива Суммирование элементов cout
<< "Сумма␣элементов␣=␣" <<
x
<<
endl
;
d e l e t Здесь параметр-массив arr во всех трёх функциях передаётся по адресу, нов функции arrinput элементы массива изменяются и это изменение передаётся в главную программу. В остальных двух функциях arrprint и перед именем массива в списке формальных параметров стоит ключевое слово const
. Это означает, что элементы массива не должны изменяться внутри функции. Если мы, например, попробуем написать arr[i] = 0
, то получим ошибку вовремя компиляции программы.
Вместо double для одномерного массива в списке формальных параметров можно писать double *arr
. Если элементы массива не должны изменяться, то пишут const double *arr
. Чтобы нельзя было изменить и сам указатель на начало массива, пишут const double * const В листинге
4.11
показана аналогичная программа для двумерного массива.
Листинг 4.11: Суммирование элементов двумерного массива i n c l u d e

using namespace
std
;
// Ввод элементов массива o r

(
long
i
=0;
i
<
n
;
i
++)

— 121 —
f o r
(
long
j
=0;
j
<
m
;
j
++){
cout
<< "arr[" <<
i
<< ",␣"
<<
j
<< "]␣=␣";
cin
>>
arr
[
i
][
j
];
}
}
// Вывод элементов массива double
*
const
arr
[]){
f o r
(
long
i
=0;
i
<
n
;
i
++)
f o r
(
long
j
=0;
j
<
m
;
j
++)
cout
<< "arr[" <<
i
<< ",␣"
<<
j
<< "]␣=␣" <<
arr
[
i
][
j
]
<<
endl
;
}
// Суммирование элементов массива double
*
const
arr
[]){
double
s
= 0;
f o r
(
long
i
=0;
i
<
n
;
i
++)
f o r
(
long
j
=0;
j
<
m
;
j
++)
s
+=
arr
[
i
][
j
];
return
s
;
}
i n t
main
(){
long
n
,
m
;
setlocale
(0, "");
// Включаем кириллицу cout
<< "Количество␣строк␣=␣";
cin
>>
n
;
cout
<< "Количество␣столбцов␣=␣";
cin
>>
m
;
// Выделение памяти (массив указателей на строки

— 122 —
double
**
a
=
new double
*[
n
];
f o r
(
long
i
= 0;
i
<
n
;
i
++)
a
[
i
] =
new double
[
m
];
arrinput2
(
n
,
m
,
a
);
// Ввод элементов массива cout
<< "Введён␣массив:␣\n";
arrprint2
(
n
,
m
,
a
);
// Вывод элементов массива Суммирование элементов cout
<< "Сумма␣элементов␣=␣" <<
x
<<
endl
;
f o r
(
long
i
= 0;
i
<
n
;
i
++)
// Освобождение памяти e l e t e
[]
a
[
i
];
d e l e t Вместо double для двумерного массива в списке формальных параметров можно писать double Что касается передачи массива по ссылке double (&arr)[]
, то этот способ обычно не используют, поскольку он не работает с динамическими массивами произвольной длины.
Указатель на функцию как параметр функции.
Функция не может являться параметром другой функции, но при необходимости можно передать указатель на функцию. В листинге
4.12
показан пример функции, предназначенной для вывода на экран таблицы любой другой функции, переданной первой в качестве указателя.
Листинг 4.12: Указатель на функцию как параметр функции i n c l u d e

# i n c l u d e

# i n c l u d e


— 123 —
// Указатель на функцию, имеющую два параметра типа int и double
// и возвращающую значение типа double:
typedef double
(*
Fun
)(
i n t
,
double
);
// Первая функция n t

k
,
double
x
){
return
x
* (
x
- k
);
}
// Вторая функция n t
k
,
double
x
){
return
x
/
k
;
}
// Третья функция (с другой сигнатурой Вывод таблицы заданной функции f:
void
tabfun
(
long
n
,
double
a
,
double
b
,
Fun f
,
i n t
k
){
double
d
= (
b
- a
)/(
n
- 1);
// Шаг изменения x printf
("\n----------------------\n");
printf
("␣␣␣␣x\t\ty\n");
//
\t - символ табуляции printf
("----------------------\n");
double
x
=
a
;
f o r
(
long
i
=0;
i
<
n
;
i
++){
double
y
=
f
(
k
,
x
);
printf
("%5.2lg␣\t␣%8.3lg\n",
x
,
y
);
x
+=
d
;
}

— 124 —
}
i n t
main
(){
double
a
,
b
,
y
,
x
,
d
;
long
n
;
i n t
k
;
SetConsoleOutputCP
(1251);
printf
("\n␣=====␣Табулирование␣функции␣=====\n");
printf
("Начало␣=␣");
scanf
("%lg", Конец, &
b
);
printf
("Кол-во␣строк␣=␣");
scanf
("%li", &
n
);
printf
("Целый␣параметр␣=␣");
scanf
("%i", &
k
);
printf
("\nФункция␣1:");
tabfun
(
n
,
a
,
b
,
f1
,
k
);
printf
("\nФункция␣2:");
tabfun
(
n
,
a
,
b
,
f2
,
k
);
// tabfun(n, a, b, f3, k); - здесь была бы ошибка!
system
("pause");
return
0;
}
Здесь мы описали новый тип указатель на функцию, имеющую один целый и один вещественный параметр и возвращающую вещественный результат. Определили функцию tabfun
, которая реализует вывод на экран значения любой функции в заданном диапазоне изменений аргумента 𝑥 ∈ [𝑎, Затем вы вызвали функцию tabfun два раза для вывода таблицы двух разных математических функций. В качестве фактического параметра функции tabfun можно задать указатель только на такие функции, которые имеют нужную сигнатуру (набор типов параметров).
Значения параметров по умолчанию.
При объявлении функции в её
заголовке можно указывать значения по умолчанию для последних параметров. Тогда при вызове функции можно опустить те параметры, которые имеют

— 125 значение по умолчанию. В листинге
4.13
показан пример функции, которая может суммировать два или три аргумента. Третий параметр по умолчанию
(если не указан при вызове) принимает нулевое значение.
Листинг 4.13: Значения параметров по умолчанию i n c l u d e

using namespace std
;
double
sum23
(
double
x1
,
double
x2
,
double
x3
=0){
return
x1
+
x2
+
x3
;
}
i n t
main
(){
double
x
=
sum23
(3, 5, 2);
double
y
=
sum23
(1, 4);
cout
<<
x
<< ",␣" Если значение по умолчанию задано для нескольких параметров (они должны быть последними в списке формальных параметров, а при вызове некоторый параметр опущен, то должны быть опущены и все остальные параметры,
стоящие в списке после него.
Функции с переменным числом параметров.
Если список формальных параметров функции заканчивается многоточием, то при вызове такой функции на месте многоточия можно указать несколько параметров любого типа. Таким способом определены некоторые системные функции, имеющие произвольное число аргументов, например n t
printf
(
const char
*, Для доступа к фактическим параметрам, переданным при вызове вместо многоточия, используются макросы из заголовочного файла

— 126 Возвращение указателя из функции.
Если функция должна возвращать другую функцию, массив или сложную структуру данных, до приходится использовать указатели. При этом надо следить за временем жизни той переменной, указатель на которую мы возвращаем из функции (независимо оттого, указана она в операторе return или является параметром функции. В
листинге
4.14
приведён пример распространённой ошибки из функции возвращается указатель на локальную переменную, описанную в самой функции. Поскольку после выхода из функции все её локальные (не статические)
переменные уничтожаются, то возвращаемый указатель уже никуда не указывает результат выполнения программы становится непредсказуемым. При компиляции данной программы будет выдано предупреждение (Листинг 4.14: Возвращение указателя из функции ошибка i n c l u d e

2
using std
::
cout
;
3
using std
::
endl
;
4 5
double
*
fun1
(
double
);
6 7
i n t
main
(
void
){
8
double
num
= 7.0;
9
double
*
ptr
=0;
10
ptr
=
fun1
(
num
);
11
cout
<< *
ptr
<<
endl
;
12
system
("pause");
13
return
0;
14
}
15 16
double
*
fun1
(
double
x
){
17
double
result
= 0.0;
// Локальная переменная 3.0 *
x
;
19
return
&
result
;
// Warning!

— 127 —
20
}
4.3. Многофайловые проекты
Размещение определений функций в отдельных файлах.
Сложные программы содержат большое число функций и часто разрабатываются командой программистов, поэтому удобно разделять весь текст программы на отдельные модули — файлы, содержащие определения функций, связанных по смыслу. Чтобы гарантировать, что до вызова любой функции компилятору уже будет известно количество и типы её параметров, а также тип возвращаемого значения, — объявления всех функций, определённых в каждом файле,
помещают в отдельный заголовочный файл обычно с расширением. Этот файл подключают к тексту программы с помощью знакомой нам директивы препроцессора
#include
Пример 4.6. Вынесем функцию из примера
4.1.
(см. св отдельный модуль (файл с именем compl.cpp
), а заголовок функции (е объявление)
поместим в заголовочный файл compl.h
. Файл, в котором определена главная функция, обычно таки называют. В итоге получится три файла (листинг
4.15
).
Листинг 4.15: Определение функции в отдельном файле ------- файл main.cpp: -------
2
# i n c l u d e

// для cin и cout
3
# i n c l u d e

// для system
4
# i n c l u d e
"compl.h"
// для complAbs
¬
5 6
using namespace
std
;
7 8
i n t
main
() {
9
double
a1
,
a2
,
x
;
10
SetConsoleOutputCP
(1251);
11
cout
<< "Введите␣действительную␣и␣мнимую␣часть\n"

— 128 —
12
"комплексного␣числа:\n";
13
cin
>>
a1
>>
a2
;
14
x
=
complAbs
(
a1
,
a2
);
// вызов функции "Модуль" <<
x
<<
endl
;
16
system
("pause");
17
return
0;
18
}
19 20
// ------- заголовочный файл compl.h: -------
21
double
complAbs
(
double
x1
,
double
x2
);
­
22 23 24
// ------- файл compl.cpp: -------
25
# i n c l u d e

// для sqrt
®
26 27
double
complAbs
(
double
x1
,
double
x2
) {
28
double
z
;
29
z
=
sqrt
(
x1
*
x1
+
x2
*
x2
);
30
return
z
;
31
}
¬ — в главном модуле main.cpp должны быть подключены необходимые заголовочные файлы. Обратите внимание, что в отличие от системных, они заключаются в кавычки, а не в угловые скобки — заголовочный файл содержит только объявление нашей функции — подключение объявлений математических функций перекочевали из главной программы (где они больше ненужны) в тот модуль, где они теперь используются. Шаблоны функций

— 129 —
5. Символы, строки, структуры, файлы. Символы
Символьные константы, определённые в программе на языке C, заключаются в одиночные кавычки, например:
’a’
Значением символьной константы является численное значение (код) этого символа, определённый в кодовой таблице ASCII (American Standard Code for Information Interchange — американский стандартный код для обмена информацией. Код каждого символа в коде ASCII занимает один байт, те. всего можно кодировать 2 8
= различных символов (от 0 до 255). Часто коды символов записывают в шестнадцатеричном виде, те. от до Таблица 5.1. Первая часть кодовой таблицы строка — первая 16-ричная цифра кода столбец — вторая цифра 01 02 03 04

05
06 07 08 09 0A 0B 0C 0D 0E 0F
00
NUL
SOH
STX
ETX
EOT
ENQ
ACK
BEL
BS
HT
LF
VT
FF
CR
SO
SI
10
DLE
DC1
DC2
DC3
DC4
NAK
SYN
ETB
CAN
EM
SUB
ESC
FS
GS
RS
US
20
!
"
#
$
%
&

(
)
*
+
,
-
/
30
0 1
2 3
4 5
6 7
8 9
:
;
<
=
>
?
40
@
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
50
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
^
_
60

a b
c d
e f
g h
i j
k l
m n
o
70
p q
r s
t u
v w
x В кодовой таблице ASCII первые 32 символа (с кодами от 0 до 31) являются управляющими, например, символ с кодом звуковой сигнал (стирание предыдущего символа (backspace);
9
— горизонтальная табуляция tab);
0x0A
— перевод строки (line feed);
0x0D
— возврат каретки return). Управляющим также является символ с кодом удаление Таблица 5.2. Вторая часть кодовой таблицы строка — первая 16-ричная цифра кода столбец — вторая цифра 01 02 03 04

05
06 07 08
09
0A 0B 0C 0D 0E 0F
80
Ђ
´
Г

´
г



A
C
0
/
00
Љ
<
Њ
´
К
Ћ
Џ
1   2   3   4   5   6   7   8   9   10   11


написать администратору сайта