Основы программирования на c/c++ Лекция 2: Типы, память. oopCpp@yandex.ru
Типы
Типы
Важность понимания типов и памяти
Процесс компиляции и сегменты памяти
Понятие типа данных
Целочисленные типы
Типы с плавающей точкой
Логический тип и void
Оператор sizeof
Ключевое слово auto
Объявление и инициализация переменных
Область видимости и время жизни
Пример области видимости
Стек вызовов
Память и адреса
Оператор взятия адреса (&)
Указатели
Разыменование указателя (*)
Нулевой указатель (nullptr)
Ссылки
Сравнение указателей и ссылок
Передача по значению
Передача по указателю
Передача по ссылке
Стек vs Куча
Оператор new
Оператор delete
Динамические массивы
Утечки памяти
Утечки памяти
Висячие указатели
Указатели и const
Ссылки и const
Константные параметры функций
Составные типы данных: Структуры
Использование
Доступ к полям структуры
Передача структур в функции
Итоги
ДЗ 2. Создаем проект 6 – pr6
Контрольная работа 2
147.00K
Категория: ПрограммированиеПрограммирование

op2

1. Основы программирования на c/c++ Лекция 2: Типы, память. oopCpp@yandex.ru

1

2. Типы

Строго типизированный язык — это язык программирования, в
котором каждая переменная и выражение имеют определенный тип
данных или функций, который проверяется на этапе компиляции.
Основные характеристики:
Явная проверка типов — компилятор проверяет соответствие типов
перед выполнением операций.
Ограниченные неявные преобразования — автоматические
преобразования между типами минимальны или отсутствуют.
Предсказуемость — поведение программы более предсказуемо, так
как типы фиксированы.
В строго типизированных языках выражение "5" + 2 вызовет ошибку.
В слабо типизированных языках (JavaScript, PHP) это может дать
результат "52" (строковая конкатенация).
с/с++ - строго типизированный язык.
2

3. Типы

Тип называется встроенным, если компилятор знает, как представить
объекты такого типа и какие операторы к нему можно применять (такие
как + и -) без уточнений в виде объявлений, которые создает
программист в исходном коде.
Типы, не относящиеся к встроенным, называют типами,
определенными пользователем. Они могут быть частью стандартной
библиотеки stl (например, классы string, vector и ofstream), или типами,
создаваемыми самим программистом.
3

4. Важность понимания типов и памяти

Язык C++ предоставляет программисту низкоуровневый контроль
над ресурсами, включая управление памятью.
Неправильное управление памятью неизбежно приводит к серьезным
проблемам:
Утечкам памяти (memory leaks) при неосвобожденных ресурсах
Неопределенному поведению (undefined behavior = UB) при
некорректных операциях
Критическим сбоям и уязвимостям в безопасности
Основополагающий принцип C++: "Не плати за то, что не
используешь"
4

5. Процесс компиляции и сегменты памяти

Трансляция программы проходит этапы:
исходный код → компилятор → объектный код → линковщик →
исполняемый файл.
При запуске программа загружается в оперативную память, где организуется
несколько ключевых сегментов:
• Сегмент кода (Code) для инструкций программы
• Сегмент данных (Data) для глобальных переменных
• Стек (Stack) для вызовов функций и локальных переменных
• Куча (Heap) для динамического выделения памяти
5

6. Понятие типа данных

Тип данных представляет собой фундаментальное понятие, которое
определяет:
• Размер занимаемой памяти, измеряемый в байтах
• Диапазон представляемых значений
• Набор допустимых операций над данными этого типа
6

7. Целочисленные типы

Целочисленные типы включают:
• char (1 байт, может быть как signed, так и unsigned)
• short (2 байта), int (4 байта), long (4 или 8 байт), long long (8 байт)
• Все типы поддерживают модификаторы signed и unsigned
• Для гарантированного размера используются типы из <cstdint>: int32_t,
uint64_t
7

8. Типы с плавающей точкой

Типы с плавающей точкой обеспечивают работу с вещественными числами:
• float (4 байта, приблизительно 7 значащих цифр)
• double (8 байт, приблизительно 15 значащих цифр) рекомендуется для
большинства вычислений
• long double (8 или 16 байт) для специализированных задач
8

9. Логический тип и void

Логический тип bool представляет два значения: true и false, занимая
обычно 1 байт.
Специальный тип void не имеет значений и используется:
• Как возвращаемый тип функций, которые не возвращают значение
• В качестве универсального указателя void* для работы с памятью
9

10. Оператор sizeof

Оператор sizeof позволяет определить размер типа или переменной в
байтах во время компиляции.
Например:
std::cout << sizeof(int); // Выведет 4 на большинстве современных платформ
std::cout << sizeof(double); // Выведет 8
Важно отметить, что sizeof(char) всегда гарантированно равен 1.
10

11. Ключевое слово auto

Ключевое слово auto позволяет компилятору автоматически вывести тип
переменной на основе инициализатора.
Пример использования:
auto x = 42; // Компилятор определит тип int
auto y = 3.14; // Компилятор определит тип double
auto z = y; // Тип будет выведен как double
Несмотря на удобство, понимание системы типов остается обязательным.
11

12. Объявление и инициализация переменных

Определение переменной:
int value; // создает неинициализированную переменную.
Инициализация:
int value = 10;
или современный синтаксис:
int value{10};
который предотвращает сужающие преобразования.
Настоятельно рекомендуется всегда инициализировать переменные при
объявлении.
12

13. Область видимости и время жизни

Глобальные переменные обладают глобальной областью видимости и
существуют в течение всей работы программы.
Локальные переменные видны только внутри блока
{}
где объявлены.
Время жизни локальных переменных ограничено временем выполнения
блока.
13

14. Пример области видимости

int global = 0; // Глобальная переменная
void foo() {
int local = 42; // Локальная переменная в foo
// global - видна здесь
} // local уничтожается здесь
int main() {
foo();
// local - здесь не видна
}
14

15. Стек вызовов

Стек вызовов работает по принципу LIFO (последний пришел — первый
вышел).
При вызове функции в стек помещаются ее аргументы и локальные
переменные.
При возврате из функции эти данные автоматически удаляются из стека.
15

16. Память и адреса

Оперативная память представляется как массив байтов, каждый из которых
имеет уникальный адрес.
Адрес представляет собой числовое значение, обозначающее положение в
памяти.
Переменная является именованной областью памяти с определенным
типом.
16

17. Оператор взятия адреса (&)

Оператор взятия адреса (&)
Оператор & возвращает адрес переменной в памяти.
Пример:
int x = 10;
std::cout << &x;
// Выведет адрес переменной x
17

18. Указатели

Указатель — это переменная, которая хранит адрес памяти другой
переменной.
Объявление:
int* p; // создает указатель на тип int.
Инициализация:
p = &x; // сохраняет адрес переменной x в указателе p.
18

19. Разыменование указателя (*)

Оператор * над указателем предоставляет доступ к значению по
сохраненному адресу.
Пример:
int x = 10;
int* p = &x;
std::cout << *p; // разыменование p. выведет 10
*p = 20;
// Изменяет значение x на 20
19

20. Нулевой указатель (nullptr)

Нулевой указатель не ссылается ни на какой объект.
Современный C++ использует nullptr вместо устаревших NULL или 0.
Пример:
int* p = nullptr;
Попытка разыменования нулевого указателя приводит к неопределенному
поведению (UB).
20

21. Ссылки

Ссылка представляет собой псевдоним для уже существующей
переменной.
Объявление:
int& ref = x; // создает ссылку на переменную x.
Ссылка должна быть инициализирована при объявлении и не может быть
перенаправлена.
21

22. Сравнение указателей и ссылок

Указатель:
• Может содержать значение nullptr
• Может быть перенаправлен на другой адрес
• Требует явного разыменования оператором *.
Ссылка:
• Всегда должна ссылаться на существующий объект
• Не может быть перенаправлена после инициализации
• Используется синтаксически как обычная переменная.
22

23. Передача по значению

При передаче по значению функция получает копию аргумента.
Изменения внутри функции не влияют на оригинальную переменную.
Пример:
void func ( int x) { x = 100; }
int a = 5;
func(a);
// Значение a останется равным 5
23

24. Передача по указателю

При передаче по указателю функция получает адрес переменной.
Изменения через указатель изменяет оригинальную переменную.
Пример:
void func (int* x) { *x = 100; }
int a = 5;
func ( &a ); // Значение a станет равным 100
24

25. Передача по ссылке

При передаче по ссылке функция работает непосредственно с
оригинальной переменной.
Изменения напрямую влияют на оригинал.
Пример:
void func (int& x) { x = 100; }
int a = 5;
func(a); // Значение a станет равным 100
Данный способ часто предпочтительнее для передачи параметров.
25

26. Стек vs Куча

Стек характеризуется:
• Высокой скоростью выделения и освобождения памяти
• Автоматическим управлением памятью
• Ограниченным размером
Куча (динамическая память) характеризуется:
• Большим доступным размером
• Ручным управлением через new/delete
• Относительно медленной скоростью работы
26

27. Оператор new

Оператор new выделяет память в куче и возвращает указатель на ее
начало.
Примеры:
int* p = new int;
// Неинициализированная память
int* p2 = new int(33); /* Память инициализирована значением 33 */
27

28. Оператор delete

Оператор delete освобождает память, ранее выделенную оператором new.
Пример:
delete p;
Крайне важно освобождать всю выделенную память.
28

29. Динамические массивы

Выделение динамического массива:
int* arr = new int [n]; // n – размер масссива.
Освобождение:
delete[ ] arr; // с обязательным использованием [ ].
Доступ к элементам:
arr[0], arr[1], и так далее.
29

30. Утечки памяти

Утечка памяти происходит когда память выделена (new), но не освобождена
(delete).
Пример:
void leak() {
int* p = new int(100);
// забыли delete p;
}
// Указатель p уничтожается, но память остается занятой
30

31. Утечки памяти

Чтобы найти утечку памяти надо:
В начале главного файла проекта разместить :
#define _CRTDBG_MAP_ALLOC
#include <cstdlib>
#include <crtdbg.h>
// А в начале main() добавить следующую строку:
_CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
Тогда в окне Output покажется утечка.
Пример.
int* leak = new int[10]; // Пример утечки
В окне Output будет что-то вроде этого :
Dumping objects ->
{157} normal block at 0x000001F845F66630, 40 bytes long.
Data: <
> CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
31
Object dump complete.

32. Висячие указатели

Висячий указатель ссылается на уже освобожденную память.
Пример:
int* p = new int(10);
delete p;
*p = 5; // Неопределенное поведение!
32

33. Указатели и const

Указатель на константу:
const int* p = &x; // запрещает изменение *p.
Константный указатель:
int* const p = &x; // запрещает изменение p.
Комбинация:
const int* const p = &x; // запрещает оба изменения.
33

34. Ссылки и const

Константная ссылка:
const int& ref = x; // не позволяет изменять значение через ссылку.
Особенно полезно для передачи больших объектов в функции без
копирования и с гарантией неизменности.
34

35. Константные параметры функций

Пример использования:
void print( const std::string& str) {
std::cout << str;
// str[0] = 'X'; // Ошибка компиляции – попытка изменить значение
}
Данный подход обеспечивает эффективность и безопасность.
35

36. Составные типы данных: Структуры

Структура — это пользовательский тип данных, который позволяет
объединять переменные разных типов под одним именем.
Аналог "записи" или "объекта" в реальном мире (например, карточка
студента, книга в каталоге, меню в кафе).
struct Student {
int id;
// ID номер
char name [256]; // ФИО – здесь не более 255 символов
int course;
// Курс
double grade; // Средний балл
};
36

37. Использование

// При создании
Student student1 = {12345, "Иванов Иван", 2, 4.8};
// Или позже, обращаясь к полям
Student student2;
student2.id = 54321;
// student2.name = "Петрова Мария"; // будет ошибка – так нельзя
strcpy(student2.name, "Петрова Мария");
student2.course = 1;
student2.grade = 5.0;
37

38. Доступ к полям структуры

Через оператор точку (.) — если работаем с самой структурой.
student1.id = // Новый id ;
cout << student1.id;
Через оператор стрелку (->) — если работаем с указателем на структуру.
Student* ptr = &student1;
ptr->course = 3; // Эквивалентно (*ptr).course = 3;
38

39. Передача структур в функции

• По значению: Создается копия всей структуры. Изменения внутри функции
не затрагивают оригинал.
void printStudent( Student s);
• По ссылке: Передается сам оригинал. Изменения внутри функции меняют
переданную структуру. Эффективно по памяти.
void initStudent ( Student& s);
• По константной ссылке: Передается оригинал, но защищен от изменений.
Идеально для передачи больших структур только для чтения.
void printStudent( const Student& s);
39

40. Итоги

• Типы данных определяют размер памяти, представление и допустимые
операции
• Память организуется в стек (автоматическое управление) и кучу (ручное
или умное управление)
• Указатели и ссылки предоставляют различные механизмы работы с
памятью
• Константность (const) обеспечивает безопасность и выразительность кода
• Структуры помогают организовать код, делая его более читаемым и
отражающим предметную область.
40

41. ДЗ 2. Создаем проект 6 – pr6

Дан некоторый неполный код. Надо его дополнить в соответствии с
комментариями.
#include <iostream>
int main() {
int a = 10;
int *p = &a;
double b = 5.5;
double *q = &b;
std::cout << "p: " << p << std::endl;
// добавляем к р 1 и снова распечатываем (p+1)
// то же самое для переменной q
// затем распечатать ++p
// при помощи оператора new выделить память и не освобождать ее для
// проверки на утечку памяти – добавить в код нужное для такой проверки.
// распечатать также имя, фамилию, группу и дату рождения
return 0;
}
Кратко прокомментировать каждую операцию. Объяснить результаты.
41

42. Контрольная работа 2

На листе бумаги напишите свою фамилию, имя и группу.
Задание.
Напишите функцию
void swap (int *a, int *b)
которая меняет значения переменных a и b местами, используя
указатели.
В функции main задайте два числа, выведите их на консоль, затем
передайте их в swap и вновь выведите их на консоль.
42
English     Русский Правила