Skip to content

Latest commit

 

History

History

lab_pointers

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Лабораторная работа №2. Динамические массивы, указатели и функции

Цель работы

Закрепить практические навыки работы с динамической памятью, указателями, ссылками и функциями в C++.

Задачи

  1. Изучить различия между передачей параметров в функцию по значению, по указателю и по ссылке.
  2. Освоить применение модификатора const с указателями и ссылками для защиты данных.
  3. Исследовать представление статических и динамических массивов в памяти, понять принципы адресной арифметики.
  4. Научиться корректно работать с динамически выделяемой памятью: создавать массивы, передавать их в функции, изменять и освобождать.
  5. Попрактиковаться в организации модульного проекта с использованием системы сборки CMake.

Структура проекта

lab_pointers/
├── CMakeLists.txt          # корневой файл сборки
├── README.md               # этот файл
├── 01_task/                # передача параметров в функцию
├── 02_task/                # const с указателями и ссылками
├── 03_task/                # массивы и адресная арифметика
├── 04_task/                # передача динамического массива в функцию
└── 05_task/                # зубчатые двумерные массивы

В каждой папке задания:

NN_task/
├── CMakeLists.txt          # сборка задания
├── main.cpp                # точка входа
├── <utils>.h               # объявления
├── <utils>.cpp             # реализации
└── README.md               # ответы на контрольные вопросы

Что нужно сделать

Задание 1. Передача параметров в функцию

  • Объявить три версии функции modify в modifiers.h: modifyByValue(int), modifyByPointer(int*), modifyByReference(int&).
  • В modifiers.cpp реализовать их так, чтобы каждая выводила адрес параметра и значение до и после присваивания x = 999.
  • В main.cpp реализовать demonstrateBasicDifferences(): объявить int a = 10, последовательно вызвать все три функции, после каждого вызова вывести текущее значение a.
  • Ответить на вопросы в 01_task/README.md: почему по значению оригинал не меняется, разница между указателем и ссылкой, когда что безопаснее, что предпочтительнее для больших неизменяемых объектов, что копируется при каждом способе передачи.

Задание 2. const с указателями и ссылками

  • Объявить в const_utils.h функции printValue(const int*), printValueRef(const int&), tryModify(const int*), setValue(int*, int).
  • В main.cpp: объявить int x = 42, вызвать printValue(&x) и printValueRef(x), изменить x через setValue(&x, 100).
  • Создать const int* p1 = &x, вызвать tryModify(p1), показать закомментированной строку *p1 = 50; с пояснением ошибки компиляции.
  • Создать int y = 200; int* const p2 = &y;, показать закомментированной строку p2 = &x; (ошибка), выполнить *p2 = 300; и вывести новое y.
  • Ответить на вопросы в 02_task/README.md: различие const int* и int* const, почему нельзя менять данные через const int*, почему const T& принимает неконстантные объекты, что происходит при попытке переприсвоить константный указатель, зачем const в параметрах, что лучше для больших неизменяемых объектов.

Задание 3. Массивы и адресная арифметика

  • Объявить в array_utils.h функцию fillArray(int*, int), в .cpp реализовать заполнение по правилу arr[i] = (i + 1) * 7.
  • В main.cpp создать статический int staticArr[5] и динамический int* dynamicArr = new int[5], заполнить оба массива через fillArray.
  • Для каждого массива вывести таблицу: i, arr[i], &arr[i], arr + i, разница в байтах с предыдущим элементом (— для i = 0).
  • Вывести sizeof(staticArr) и sizeof(dynamicArr), освободить динамический массив через delete[].
  • Ответить на вопросы в 03_task/README.md: почему имя массива работает как указатель, отличие статического от динамического по времени жизни и размещению, почему различается sizeof, почему &arr[1] - &arr[0] равно 1, а не 4, можно ли переприсвоить staticArr/dynamicArr, что будет без delete[], почему int arr[] работает с обоими массивами.

Задание 4. Передача динамического массива в функцию

  • Объявить в array_utils.h три функции: modifyElementsOnly(int*, int), reallocateArray(int*&, int&), fakeByValue(int*, int).
  • В main.cpp: создать int* data = new int[3]{1, 2, 3}, вывести адрес и содержимое.
  • Вызвать modifyElementsOnly(data, 3) — элементы изменились, адрес тот же.
  • Вызвать fakeByValue(data, 3) — внутри arr = nullptr, внешний data не изменился.
  • Вызвать reallocateArray(data, size) — освободить старый массив, выделить новый размером size * 2, заполнить, обновить data и size.
  • Вывести новый адрес и содержимое (должны отличаться), освободить память.
  • Ответить на вопросы в 04_task/README.md: почему нельзя изменить указатель при передаче int*, что означает int*&, можно ли передать массив «по значению», что будет при забытом size, зачем освобождать старый массив, какие риски при передаче указателя без размера.

Задание 5*. Зубчатые двумерные массивы

  • Объявить в matrix_utils.h функции createMatrix(int, int), fillMatrix(int**, int, int), printMatrix(int**, int, int), freeMatrix(int**, int), resizeMatrix(int**&, int&, int&, int, int).
  • В matrix_utils.cpp реализовать: создание int** с построчным new int[cols] и инициализацией нулями, заполнение matrix[i][j] = i * j, вывод матрицы, освобождение всех строк и массива указателей, перевыделение с сохранением старых данных в левом верхнем углу и инициализацией новых элементов нулями.
  • В main.cpp создать матрицу 3×4, заполнить, вывести, расширить до 5×6 через resizeMatrix, снова вывести, освободить память.
  • Собрать с -fsanitize=address и убедиться, что программа не имеет утечек.
  • Ответить на вопросы в 05_task/README.md: почему нельзя void f(int arr[][]) без размеров, чем int** отличается от int[rows][cols] в памяти, почему строки освобождают до массива указателей, что будет при delete[] только matrix, зачем int**& в resizeMatrix, какие риски у int**.

Сборка

mkdir build && cd build
cmake ..
cmake --build .

Исполняемые файлы появятся в build/: 01_task, 02_task, task03, 04_task, 05_task.

Отладка утечек памяти

Задание 5 собирается с AddressSanitizer:

target_compile_options(05_task PRIVATE -fsanitize=address -g)
target_link_options(05_task PRIVATE -fsanitize=address)

При наличии утечек, double free или использования после delete[] ASan выведет подробный отчёт.

Требования

  • C++23 (set(CMAKE_CXX_STANDARD 23))
  • CMake ≥ 3.10
  • Никаких глобальных переменных — все данные передаются через параметры.
  • Код разделён на .h / .cpp, в заголовках используется #pragma once.
  • В каждом README.md задания — ответы на контрольные вопросы.

Сдача

Архив со всем проектом lab_pointers/ загружается в SmartLMS курса.