Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Основы разработки программ на языке С++ для систем информационной безопасности. Учебное пособие
.pdf
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 байта. При программировании учитывать разрядность не следует. Это делается автоматически
соответственно типу указателя.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
