Lab 5 [PDF]

Федеральное агентство связи Ордена Трудового Красного Знамени Федеральное государственное бюджетное образовательное учре

32 0 1MB

Report DMCA / Copyright

DOWNLOAD PDF FILE

Papiere empfehlen

Lab 5 [PDF]

  • 0 0 0
  • Gefällt Ihnen dieses papier und der download? Sie können Ihre eigene PDF-Datei in wenigen Minuten kostenlos online veröffentlichen! Anmelden
Datei wird geladen, bitte warten...
Zitiervorschau

Федеральное агентство связи Ордена Трудового Красного Знамени Федеральное государственное бюджетное образовательное учреждение высшего образования «Московский технический университет связи и информатики»

Кафедра «Математической кибернетики и информационных технологий»

Отчет по лабораторной работе по дисциплине «Низкоуровневое программирование» на тему: «Основы работы с указателями в языке программирования С»

Выполнил: Студент группы БВТ1801 Тимофеев И.И. Проверил: Фатхуллин Т.Д.

Москва 2021

Цель работы: Изучить и практически освоить основы работы с указателями в языке программирования C.

2

Задание     

Создайте проект для ознакомительного использования указателей. Создайте проект с объявлением и использованием указателей. Создайте проект для побайтового заполнения области памяти. Создайте проект с использованием указателей общего назначения. Создайте проект для побайтового заполнения целочисленного значения с использованием указателей общего назначения.  Создайте проект с многоуровневой адресацией.  Согласно пунктам выполнения лабораторной работы, сделать необходимые снимки экрана. Изучить полученную информацию и оформить ее в соответствии с требованиями раздела «Содержание отчета». 

3

Краткая теория ПЕРЕМЕННЫЕ И ИХ ПРЕДСТАВЛЕНИЕ В ПАМЯТИ Переменная — это поименованная область памяти под определенный тип данных. Как известно, каждая переменная хранится в памяти компьютера и имеет свой адрес, по которому она записана. Память компьютера можно представить в виде таблицы с ячейками (рисунок 1) по одному байту, каждая из которых имеет свой адрес, который записывается цифрами шестнадцатеричной системы.

Рисунок 1 – Пример представления памяти компьютера Для того чтобы получить адрес переменной необходимо перед её именем написать символ “&”. Кроме того, каждая переменная в зависимости от её типа, занимает в памяти различное количество байт. Для того, чтобы узнать размеры различных типов обычно используется функция sizeof(). В качестве примера, напишем программу, которая бы получала адрес переменных a,b и количество байт, отведенных для каждой из этих переменных (рисунок 2).

Рисунок 2 – Получение адреса переменных в памяти 4

На нашем компьютере мы получили два адреса 0x12ff60 и 0x12ff54. Так как это переменные целого типа (int) они занимают в памяти компьютера 4 байта. Как видно из рисунка, переменные указанного типа располагаются в памяти компьютера не подряд, а произвольным образом. Это выглядит примерно так (рисунок 3):

Рисунок 3 – Пример расположения переменных в памяти Для хранения адресов переменных и возможности получения данных непосредственно по адресу в памяти существуют специальные переменные, которые называются указателями. Указатель – переменная, предназначенная для хранения адреса какоголибо объекта (переменной, массива и тд.) в памяти компьютера. Согласно определению, указатель это переменная, следовательно, как и любая переменная, он должен быть как-то объявлен. Делается это в языке С следующим образом: - сначала указывается Базовый тип переменной, которая будет храниться в памяти, по адресу указателя. -далее следует специальный символ «*», называемый оператором косвенной адресации, который сообщает компилятору, что мы собираемся объявить указатель на переменную определенного типа (например, int). После звездочки пишется идентификатор (имя) указателя. Базовый тип указателя (т.е. l-value выражения объявления указателя) может принимать любой тип данных (как простой, определенный стандартом языка, так и составной, определенный стандартом языка или пользователем). После объявления локального указателя до первого присвоения он содержит неопределенное значение. Указатель, не ссылающийся в текущий момент времени на конкретный объект, должен содержать нулевое значение. Нуль (NULL или 0) используется, потому что С, в соответствии со стандартом, гарантирует отсутствие чего-либо по нулевому адресу. Следовательно, если указатель равен нулю, то это значит, во-первых, что он ни на что не ссылается, а во-вторых – что его сейчас нельзя использовать.

5

Выполним листинг (рисунок 4):

Рисунок 4 – Пример обнуления указателя ОПЕРАЦИИ НАД УКАЗАТЕЛЯМИ В языке С определены две операции для работы с указателями: операция разыменования (*) и операция взятия адреса (&). Оператор & - это унарный оператор, возвращающий адрес своего операнда (r-value). Оператор * - это унарный оператор, возвращающий значение переменной, расположенной по указанному адресу. Для лучшего понимания выполним следующий листинг (рисунок 5):

6

Рисунок 5 – Операции для работы с указателями В рамках данной программы мы выполнили операции взятия адреса, с последующим присвоением его указателю и операцию разыменования т.е. получения данных по адресу, на который «указывает указатель». Результат выполнения листинга представлен ниже на рисунке 6:

Рисунок 6 – Пример использования операций взятия адреса и разыменования Модифицируем предыдущий листинг и посмотрим, какое количество памяти занимают переменные разных типов (рисунок 7):

7

Рисунок 7 – Определение размеров переменных Как видно из рисунка 7 переменная «х» типа char занимает в памяти 1 байт. Но при этом, указатель «*р» на переменную х типа char занимает в памяти 8 байт. Этот пример иллюстрирует еще одну особенность указателей: указатель в памяти компьютера, в зависимости от архитектуры установленного процессора (32х-64х) занимает 4-8 байт. Объем занимаемой указателем памяти НЕ зависит от типа данных, на которые он указывает! Адресная арифметика В языке С допустимы только две арифметические операции над указателями: суммирование и вычитание. Все остальные арифметические операции запрещены. А именно: нельзя делить и умножать указатели, 8

суммировать два указателя, выполнять над указателями побитовые операции, суммировать указатель со значениями, имеющими тип float или doubleи т.д. Операции адресной арифметики подчиняются следующим правилам: После выполнения операции увеличения над указателем, данный указатель будет ссылаться на следующий объект своего базового типа. После выполнения операции уменьшения – на предыдущий объект. Применительно к указателям на char, операции адресной арифметики выполняются как обычные арифметические операции, потому что длина объекта char всегда равна 1 (рисунок 8).

Рисунок 8 – Количество байт, занимаемое в памяти переменными различных типов Операции адресной арифметики не ограничены увеличением (инкрементом) и уменьшением (декрементом). Например, к указателям можно добавлять целые числа или вычитать из них целые числа. В качестве примера выполним следующий листинг (рисунок 9):

9

Рисунок 9 – Пример выполнения операций адресной арифметики Кроме суммирования и вычитания указателя и целого, разрешена еще одна операция адресной арифметики: можно вычитать два указателя. Вычитание указателей друг из друга определено только в том случае, если оба указателя указывают на элементы одного и того же массива. Результатом вычитания одного указателя из другого будет количество элементов массива (целое число) между этими указателями. Помимо всего названного ранее, указатели можно сравнивать. Для сравнения указателей используются операции = =, >, ptr2=&ptr1, который в свою очередь будет ссылаться на значение

28