Программирование C++ (1 сем, мага) / Лабы / Лабораторная работа №3
.docxМинистерство науки и высшего образования Российской Федерации
Федеральное государственное автономное образовательное учреждение высшего образования
«Национальный исследовательский ядерный университет «МИФИ»
Кафедра экспериментальной ядерной физики и космофизики (№7)
Программирование на С и С++
Отчет по лабораторной работе № 3
Выполнил:
студент группы M22-105 Васильева А.П.
Москва, 2022
Цель работы: изучение способа доступа к элементам массива путем использования механизма указателей.
Введение
Использование механизма указателей - один из способов доступа к элементам массива. Массив – это расположенные вплотную друг за другом в памяти элементы одного и того же типа. Каждый массив имеет имя, оно является указателем‑константой, равной адресу начала массива (первого байта первого элемента массива). Доступ к отдельным элементам массива возможен по имени массива и индексу (порядковому номеру) элемента, причем имя рассматривается как указатель – используется операция *. Будут полностью эквивалентными обращения к i-ому элементу массива array (независимо от типа элемента) array[i] и *(array + i).
Имя двумерного массива является указателем-константой на массив указателей‑констант. Элементами массива указателей являются указатели-константы на начало каждой из строк массива: для array[2][2] указателями‑константами на нулевую и первую строки будут array[0] и array[1].
Задание
Создать массив размерности, соответствующей номеру телефона (четным цифрам), типа unsigned char и заполнить его. Началом массива будет число, которое представляет собой сумму трех символов, находящихся в середине файла. Значения остальных элементов получить с использованием операции инкремента. С помощью указателей обратиться к двум элементам, которые находятся в середине массива.
Ход работы
Согласно номеру телефона, требовалось создать массив размерности [6][7][1]. Выданный преподавателем файл имел следующий вид:
Три символа в середине файла – 0x20, 0x20, 0x20. Следовательно, первый элемент массива: 0x20 + 0x20 + 0x20 = 0x60.
Написана программа, имеющая следующий код:
Сначала вычисляется величина первого элемента и полученное значение присваивается переменной firstEl, имеющей тип unsigned long. Далее выполняется преобразование к требуемому в задаче типу – unsigned char. Результат присваивается переменной arrEl, значение которой теперь равно величине, которую должен иметь нулевой элемент массива.
Далее создается трехмерный массив arr[6][7][1], элементы которого имеют тип unsigned char.
Элементам массива ещё не были присвоены никакие значения, поэтому они на данном шаге равны случайным величинам.
Далее создается указатель unsigned char *arrp и ему присваивается адрес, указывающий на нулевой элемент массива arr[6][7][1]: *arrp = **arr. Покажем справедливость этого выражения.
Пусть есть трехмерный массив array[N1][N2][N3]:
(array + i) = &array[i], где (i = 0, …, N1);
(*(array + i) + j) = &array[i][j], где (i = 0,…,N1; j = 0,…,N2);
(*(*(array + i) + j) + k) = &array[i][j][k] (i = 0,…,N1; j = 0,…,N2; k = 0,…,N3);
Соответственно указатель на нулевой элемент трехмерного массива: **array = &array[0][0][0].
В памяти элементы массива хранятся последовательно. Тогда получаем, что (arrp + i) – указатель на i-ый элемент массива и, изменяя i в пределах 0 ≤ i < N (N – количество элементов в массиве), можно последовательно пройтись по всем элементам массива.
Количество элементов в массиве определено как sizeof(arr)/sizeof(unsigned char). Функция sizeof(operand) возвращает объем памяти, необходимый для хранения объекта operand в байтах. В общем случае sizeof(arr) = N*m, где N – количество элементов в массиве, m – объем памяти, занимаемый одним элементом и численно равный размеру типа данных элемента массива. Чтобы учесть выполненяется деление на sizeof(тип_данных). В конкретном случае количество элементов в массиве – 42, каждый элемент имеет тип unsigned char и занимает 1 байт. Поэтому sizeof(arr) = 42, а деление на sizeof(unsigned char) не влияет на результат.
Результат операции sizeof(arr)/sizeof(unsigned char) сохраняется в переменную arraySize:
Далее в цикле for происходит заполнение массива. В результате после работы цикла массив выглядит следующим образом:
В Приложении 1 показаны изменения значений переменных i, arrEl и элементов массива arr на каждой итерации цикла.
В Приложении 2 показан приведен код, в котором элементы массива выводятся в терминал в момент выполнения программы. Результаты вывода представлены там же.
После заполнения массива определяется индексы двух средних элементов:
Индекс первого среднего элемента: arraySize/2 – 1, т.е. выполняется целочисленное деление с последующим вычитанием из полученного результата единицы. Единица вычитается, чтобы учесть то, что индексация в массиве начинается с 0. Второй интекс: arraySize/2.
В случае четного числа элементов в массиве будет два средних элемента. При таком подходе мы определим индексы обоих.
В случае нечетного числа элементов в середине фактически находится один элемент – его индексу будет соответствовать arraySize/2. Второй вычисленный индекс будет принадлежать элементу, предшествующему среднему.
С помощью механизма указателей получены значения двух элементов, находящихся в середине массива:
Заключение
В лабораторной работе освоены механизм указателей как один из способов доступа к элементам массива.
В ходе работы создан и заполнен массив размерности [6][7][1], тип элементов которого – unsigned char. Значение нулевого элемента массива вычислено на основе данных из файла, предоставленного преподавателем. Значения остальных элементов получены с помощью операции инкремента.
Также получены значения двух средних элементов массива.
К выводам по работе можно отнести:
В памяти элементы массива хранятся последовательно, т.е. они расположены вплотную друг за другом.
Каждый элемент массива занимает объем памяти, требуемый для хранения переменной того типа, которому принадлежат элементы массива.
Объем памяти, занимаемый массивом равен общему количеству элементов, умноженному на размер одного элемента.
К массивам можно обращаться с помощью механизма указателей, что зачастую упрощает код. Доступ к отдельным элементам массива возможен по имени массива и индексу (порядковому номеру) элемента, причем имя рассматривается как указатель.
Приложение 1
Представлены значения переменных в момент входа в новую итерацию цикла. Строка “*(arrp + i) = arrEll++;” еще не выполнена. Элемент массива *(arrp + i) ещё не заполнен. Выведенное значение arrEl соответствуют той величине, которая будет присвоена i‑ому элементу массиву после завершения текущей итерации цикла. В свою очередь arrEl после текущей итерации увеличится на единицу.
Представленные результаты получены с помощью отладчика gdb.
Итерация 1
Итерация 2
Итерация 3
Итерация 4
Итерация 5
Итерация 6
Итерация 7
Итерация 8
Итерация 9
Итерация 10
Итерация 11
Итерация 12
Итерация 13
Итерация 14
Итерация 15
Итерация 16
Итерация 17
Итерация 18
Итерация 19
Итерация 20
Итерация 21
Итерация 22
Итерация 23
Итерация 24
Итерация 25
Итерация 26
Итерация 27
Итерация 28
Итерация 29
Итерация 30
Итерация 31
Итерация 32
Итерация 33
Итерация 34
Итерация 35
Итерация 36
Итерация 37
Итерация 38
Итерация 39
Итерация 40
Итерация 41
Итерация 42
После выхода из цикла
Приложение 2
Код программы:
Примечание по используемым при выводе функциям:
std::dec – вывод числа в десятичной форме;
std::hex – вывод числа в шестнадцатеричной форме;
std::setw(2) – ширина вывода 2 символа.
Результаты вывода в терминал:
