Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Основы разработки программ на языке С++ для систем информационной безопасности. Учебное пособие

.pdf
Скачиваний:
1
Добавлен:
07.09.2026
Размер:
1 Мб
Скачать
☆
9. Указатели
51
Таблица 26
Модификация значений массива по указателю
int intArray[2]; intArray[0]=9; intArray[1]=99; int *pInt; pInt=&intArray[0]; *pInt=*pInt +1; *(pInt + 1) = *(pInt + 1 ) + 1;
intArray 0x0012ff18 int[2]
[0] 10 int [1] 100 int
Таблица 27
Преобразование типа указателя
int intArray[2]; intArray[0]=9; intArray[1]=99; int *pInt; pInt=&intArray[0]; char *pChar; pChar = (char *) pInt; char c1, c2, c3, c4; c1 = *pChar; c2 = (*pChar+1); c3 = (*pChar+2); c4= (*pChar +3);
Практическое задание 4. Поразрядная обработка данных
Задание: выполнить расчеты поразрядно.
Таблица 28
Варианты для практического задания 4
№
вар.
Входные данные
Представление
выходных данных
1
Выполнить конъюнкцию 3 чисел
У результата поменять знак
2
Выполнить сдвиг вправо на n разря- дов
Обнулить n-й бит
3
Выполнить дизъюнкцию 3 чисел
Вывести n-й бит числа
9. Указатели
52
Окончание табл. 28
№
вар.
Входные данные
Представление
выходных данных
4
Умножить результат на n-ю сте­пень числа 2
5
Выполнить исключающее ИЛИ
У результата поменять знак
6
Определить положение старшей единицы в длинном целом числе N
Заменить стоящую справа 1 на 0
7
Выполнить сдвиг влево на 3раз­ряда
Обнулить n-й бит
8
Выполнить инверсию целого числа
Результат округлить до следую­щей степени числа 2
9
Выполнить конъюнкцию 2 чисел. Заменить стоящий справа 0 на 1
10
Определить положение старшего нуля в длинном целом числе N
Вывести n-й бит числа
11
Выполнить инверсию целого числа
Умножить результат на n-ю сте­пень числа 2
12
Выполнить дизъюнкцию2 чисел
Обнулить n-й бит
13
Выполнить сдвиг вправо на 2 раз­ряда
Заменить стоящую справа 1 на 0
14
Выполнить сдвиг влево на nразрядов
У результата поменять знак
15
Выполнить исключающее ИЛИ
Вывести n-й бит числа
Символьные массивы и строки
53
10. СИМВОЛЬНЫЕ МАССИВЫ И СТРОКИ
Символьные массивы в языке С++ создаются и обрабатываются
двумя способами:
1. традиционным образом: операция над массивом осуществляется как
операция над отдельными элементами соответственно объявленному типу;
2. нетрадиционным образом: обработка символьного массива реализу-
ется как обработка строки. Строкой считается последовательность символов переменной длины. Для этого в массиве должен присутствовать символ ограничителя строки. Код символа ограничителя равен 0, поэтому его назы­вают нулевым символом. Этот символ программист может разместить в лю­бом месте массива, т.е. при одной и той же длине массива соответствующая ему строка может иметь различную длину.
Ответственность за наличие нулевого символа и корректность обра-
ботки возлагается на программиста. В табл. 29 приведен программный код, иллюстрирующий размещение символьного массива и строки в памяти. В окне отладчика можно увидеть, что объявленная строка символов содер­жит нулевой символ-ограничитель.
При обработке строк часто используют указатели.
Таблица 29
Строка и символьный массив в памяти
int _tmain(int argc, _TCHAR* argv[]) { char CharArray[]=”Строка символов”; char cArray[50];
return 0; }
Рис. 9. Строка и символьный массив в памяти
Стандартная библиотека С++ включает набор строковых функций,
которые позволяют: копировать строки, объединять две строки в одну, а также сравнивать пары строк между собой (табл. 30). Существуют функции
10. Символьные массивы и строки
54
sscanf и sprintf аналогичные функциям ввода/вывода с консоли. Чтение и за- пись данных они выполняют в символьные строки.
Таблица 30
Функции обработки строк
char *strcpy( char *strDestination, const char *strSource); char *strcpy( char *strDestination, const char *strSource); int strcmp( const char *string1, const char *string2 );
int sscanf( const char *buffer, const char *format [, argument] …); int sprint( char *buffer, const char *format [, ardument] …);
Функции работы со строками обеспечивают безопасную обработку строк. Им следует отдавать предпочтение перед использованием циклов.
Одна из частых ошибок обработки строк – выход за границу массива. Это иллюстрируется рис. 10. Строковая функция strcpy копирует строку большего размера.
Таблица 31
Пример копирования за пределы массива
char CharArray []=”Строка символов”; char cArray[10]; strcpy(cArray, CharArray); return 0;
Рис. 10. Пример копирования за пределы массива
Память программы оказывается некорректно измененной, что застав­ляет ее завершиться аварийно с помощью исключения. Сообщение об ис­ключении показано ниже программного кода.
Соблюдение границ выделенной памяти не вызывает исключения (см. табл. 32).
10. Символьные массивы и строки
55
Таблица 32
Пример корректного копирования
char CharArray []=”Строка символов”; char cArray[10]; strcpy(cArray, &CharArray[7]); return 0;
Практическое задание 5. Сравнение строк
Задание: разработать программу, позволяющую проводить сравнение
данных, введенных с клавиатуры, и выводить на экран результат сравнения в соответствии с вариантом.
Сравнить строку n со строкой n+5, где n – номер варианта по списку (для n > 15 продолжить считать с начала списка), вывести резуль­тат сравнения.
Таблица 33
Варианты для практического задания 5
№
вар.
Входные данные
Представление выходных данных
1
20 символов. Результат с учетом регистра
Выполнить побайтное копирование символов из строки n+5 в строку n
2
25 телефонных номеров в фор­мате XXXXXXXXXXX. Резуль­тат без учета регистра
Выполнить побайтное копирование n символов из строки n в строку n+5 в случае несовпадения
3
25 символов. Результат с уче­том регистра
Объединить n символов строки n+5 со строкой n. Результат сохранить в строке n
4
10 наименований учебных кур­сов. Результат без учета реги­стра
Выполнить побайтное копирование символов из строки n+5 в строку n в случае несовпадения.
5
15 телефонных номеров в фор­мате XXXXXXXXXXX. Резуль­тат с учетом регистра
Объединить n символов строки n+5 со строкой n. Результат сохранить в строке n
6
15 дат в формате дд. мм. гг. Ре­зультат с учетом регистра
Выполнить побайтное копирование n символов из строки n+5 в строку n в случае несовпадения
10. Символьные массивы и строки
56
Окончание табл. 33
№
вар.
Входные данные
Представление выходных данных
7
20 символов. Результат без учета регистра
Выполнить побайтное копирование символов из строки n+5 в строку n в случае несовпадения
8
10 фамилий. Результат с учетом регистра
Объединить n символов строки n+5 со строкой n. Результат сохранить в строке n
9
25 дат в формате дд. мм. гг. Ре­зультат без учета регистра
Выполнить побайтное копирование n+5 символов из строки n в строку n+5 в случае несовпадения
10
15 фамилий. Результат с учетом регистра
Выполнить побайтное копирование символов из строки n+5 в строку n в случае несовпадения
11
30 символов. Результат без учета регистра.
Выполнить побайтное копирование n символов из строки n в строку n+5 в случае несовпадения
12
10 дат в формате дд. мм. гг. Ре­зультат без учета регистра
Объединить n+5 символов строки n+5 со строкой n. Результат сохранить в строке n
13
10 фамилий. Результат с учетом регистра.
Выполнить побайтное копирование символов из строки n+5 в строку n в случае несовпадения
14
20 дат в формате дд. мм. гг. Ре­зультат без учета регистра
Объединить n символов строки n+5 со строкой n. Результат сохранить в строке n
15
15 фамилий. Результат с учетом регистра
Выполнить побайтное копирование n символов из строки n+5 в строку n в случае несовпадения
Передача параметров функциям
57
11. ПЕРЕДАЧА ПАРАМЕТРОВ ФУНКЦИЯМ
В C++ существует 3 способа передачи параметров в функцию:
1. Передача параметра по значению (Call-By-Value). При передаче по
значению в точке вызова функции копируются значения фактических пара­метров. Все преобразования внутри функции выполняются над копиями, не изменяя при этом оригиналы. При передаче по указателю (ссылке), в точке вызова передается указатель на фактические параметры. Все преобразования в функциях могут изменять оригиналы. Таким образом, если требуется изме­нить некоторую переменную за счёт вызова функции, следует использовать указатель. В этом случае изменение значений параметров в теле функции не изменит значений, которые передавались в функцию извне (при ее вызове).
2. Передача параметра по адресу переменной. В этом случае функции
в качестве параметров передаются не копии переменных, а копии адресов переменных, то есть указатель на переменную. Используя этот указатель, функция осуществляет доступ к нужным ячейкам памяти, где расположена передаваемая переменная, и может изменять ее значение.
3. Передача параметра по ссылке (Call-By-Reference). Передается
ссылка (указатель) на объект (переменную), что позволяет синтаксически использовать эту ссылку как указатель, и как значение. Изменения, внесен­ные в параметр, который передается по ссылке, изменяют исходную копию параметра вызывающей функции.
В табл. 34 приведен пример программного кода, в котором вызыва­емой функции передаются параметры по значению. В окне отладчика можно видеть, что исходные переменные не изменили своих значений по­сле вызова функции.
Таблица 34
Передача параметров по значению
void FunctionA (float x, float y, float z) { z = sqrt( x + y ); x = 5; y = 1; } int _tmain(int argc, _TCHAR* argv[]0 {
11. Передача параметров функциям
58
Окончание табл. 34
float x, y, z; x = 2; y = 6; z = 10; FuncA( x, y, z );
return 0; }
name
value
x
2.0000000
y
6.0000000
z
10.0000000
В табл. 35 параметры передаются по указателю. Как видно из отлад­чика, исходные значения переменных изменились. Заметим, что данный пример иллюстрирует механизм перегрузки функций: если объявлены функ­ции с одинаковыми именами, то при компиляции выбирается та, типы аргу­ментов которой соответствуют строке вызова. В данном случае это функция с параметрами-указателями.
Таблица 35
Передача параметров по указателю
void FunctionA (float x, float y, float *z) { z = sqrt( x + y ); x = 5; y = 1; } void FuncA (float *x, float *y, float z) { *z = sqrt( *x + *y ); *x = 5; *y = 1; } int _tmain(int argc, _TCHAR* argv[]0 { float x, y, z; x = 2; y = 6;
11. Передача параметров функциям
59
Окончание табл. 35
z = 10; FuncA( &x, &y, &z );
return 0; }
name
value
x
5.0000000
y
1.0000000
z
2.8284271
Таблица 36
Передача параметров по ссылке
void FuncB (float& x, float& y, float& z) { z = sqrt( x + y ); x = 5; y = 1; } int _tmain(int argc, _TCHAR* argv[]) { float x, y, z; x = 2; y = 6; z = 10; FuncB( x, y, z );
return 0; }
name
value
x
5.0000000
y
1.0000000
z
2.8284271
Во многих языках программирования используются ссылки на перемен-
ные. Ссылка в С++ – это аналог указателя, но с меньшими возможностями. В языке С++ ссылка рассматривается как производный тип. Переменная ссылоч­ного типа всегда ссылается на уже существующую переменную любого типа.
Использование ссылок как формальных параметров аналогично ука-
зателю. С синтаксической точки зрения в текстах функций не используются
11. Передача параметров функциям
60
знак *, принятый для указателя. В табл.37 показано, как с использованием ссылок можно получить результат, аналогичный использованию указателей.
Таблица 37
Передача массива
void ArrayFunc ( int *A, int N) { for (int i=0 ; i < N ; i++) *A++ = *A – i; } int _tmain(int argc, _TCHAR* argv[]) { int SomeArray[]= {1,2,3,4,5,6,7,8,9,10}; ArrayFunc( & SomeArray[0], sizeof( SomeArray) / sizeof(int) ); return 0; }
Рис. 11. Передача массива
Для обработки в функции массивов необходимо передавать указатель на массив. Программный код в функции строится исходя из этого требования, т.е. к элементам массива обращаются по указателю. В табл. 37 приведен при­мер функции, получающей указатель на целочисленный массив.
При обработке массива внутри функции для перехода от одних эле­ментов массива к следующим, используют операцию увеличения указа­теля ++. Увеличение на 1 указателя изменяет адрес на то число байт, которое соответствует типу указателя. Например, если указатель целого типа, а це­лые числа 32-разрядные, то адрес будет увеличен на 4 байта. При програм­мировании учитывать разрядность не следует. Это делается автоматически
соответственно типу указателя.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]