Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Базовые элементы языка Cи. Алфавит. Лексемы. Знаки операций. Литералы. Комментарии.

Поиск

ВОПРОСЫ К ЭКЗАМЕНУ ПО ДИСЦИПЛИНЕ

«ПРОГРАММИРОВАНИЕ ТЕХНИЧЕСКИХ СРЕДСТВ»

1. Структура ПЭВМ. Размещение данных и программ в памяти ПЭВМ. Биты, байты. Программа, машинная команда
2. Состав программного обеспечения технических средств. Среда программирования.
3. Виды файлов среды программирования. Программные модули: исходный, объектный, загрузочный.
4. Трансляторы, интерпретаторы, компоновщик, отладчик. Режимы компиляции и компоновки.
5. Особенности программирования и отладки встроенных систем.
6. Компоновка программных модулей и запись программной кодировки в целевое устройство.
7. Понятие структурного и модульного программирования.
8. Функциональная и модульная декомпозиции в программировании
9. Операционная система. Файловая система хранения информации
10. Понятие алгоритмов и способы их описания
11. Графическое описание алгоритма. Основные символы схемы алгоритма
12. Стандартизация графического представления алгоритмов. Программная документация.
13. Базовые элементы языка Cи. Алфавит. Лексемы. Знаки операций. Литералы. Комментарии.
14. Виды и характеристики языков программирования. Виды программных ошибок.
15. Идентификаторы и ключевые слова языка Си.
16. Структура программы на языке Си.
17. Декларация объектов. Основные типы данных
18. Категории типов данных (символьные, целые, с плавающей точкой).
19. Символьные и целые типы данных.
20. Вещественные типы данных (с плавающей точкой).
21. Преобразование типов (явное и неявное). Приведение типа
22. Использование модификаторов при декларации типов данных.
23. Системы счисления. Кодовая таблица ASCII. Классификация и преобразование символов.
24. Константы. Целые константы. Константы с плавающей точкой. Символьные константы. Строки. NULL.
25. Операции и выражения языка Си.
26. Арифметические операции. Аддитивные и мультипликативные операции.
27. Условный оператор if.
28. Тернарная условная операция?:.
29. Оператор выбора альтернатив switch.
30. Составление циклических алгоритмов. Операторы цикла с предусловием и с постусловием.
31. Оператор цикла с предусловием и коррекцией for.
32. Операторы передачи управления (break, continue, return, goto).
33. Побитовые логические операции, операции над битами
34. Операции сравнения. Логические операции. Унарные операции.
35. Операция присваивания. Сокращенная запись операции присваивания.
36. Стандартная библиотека языка Си. Математические функции.
37. Строки в языке Си. Функции работы со строками.
38. Стандартная библиотека языка Си. Ввод данных.
39. Стандартная библиотека языка Си. Вывод данных.
40. Управляющая строка функций ввода/вывода.
41. Ввод-вывод потоками
42. Препроцессор. Директивы #include, #define, #if…
43. Одномерные массивы. Инициализация одномерных массивов. Ввод и инициализация массива символов.
44. Многомерные массивы. Инициализация многомерных массивов.
45. Структуры. Вложенные структуры
46. Массивы структур. Битовые поля
47. Объединения. Перечисления
48. Указатели. Указатели и адреса объектов. Указатели и массивы.
49. Операции с указателями: присваивание адреса, определение значения по адресу, присваивание указателей
50. Операции с указателями: сложение и вычитание, инкремент и декремент, сравнение указателей
51. Работа с динамической памятью. Динамические массивы.
52. Операции typedef и sizeof
53. Функции. Определение функции, объявление функции и вызов функции. Возвращаемое значение функции.
54. Функции. Типы передачи параметров функции (по значению, по адресу, по ссылке).
55. Функции. Переменные в качестве параметров функций.
56. Функции. Массивы в качестве параметров функций.
57. Указатели на функции.
58. Перегрузка функций.
59. Классы памяти. Области действия объектов
60. Работа с файлами. Типы файлов (текстовый и бинарный). Дескриптор файла (“указатель на файл”). Режимы работы с файлами.
61. Работа с файлами. Открытие файла в различных режимах и закрытие файла.
62. Работа с файлами. Чтение и запись данных в файл. Посимвольный и построчный ввод-вывод
63. Работа с файлами. Чтение и запись данных в файл. Блоковый ввод-вывод
64. Работа с файлами. Чтение и запись данных в файл. Форматированный ввод-вывод
65. Работа с файлами. Указатель текущей позиции в файле, его перемещение к нужной позиции.
66. Графический режим. Функции черчения и заполнения. (arc, bar, bar3d, circle, drawpoly, ellipse, fillellipse, fillpoly, line, lineto, pieslice, rectangle, sector, setlinestyle, setfillstyle)
67. Графический режим. Функции вывода текста, функции управления цветом. (outtext, outtextxy, setbkcolor, setcolor, settextjustify, settextstyle, textheight, textwidth)
68. Среды разработки программ для микроконтроллеров. Особенности написания программ для микроконтроллеров и программирования их периферийных устройств.
69. Средства записи программ и отладки для микроконтроллеров. Программаторы, симуляторы и внутрисхемные отладчики.
70. Интерфейсы программирования и отладки встроенных систем. Интерфейс JTAG

 


 

1

 

Размещение данных и программ в памяти ПЭВМ:

Программы хранят своё состояние в оперативной памяти, которое представлено набором различных структур данных, упомянутых выше. А каждая программа может по-своему представлять их в памяти. Это зависит от особенностей самой программы, от языка программирования, на котором написана программа, а также от особенностей ОС и аппаратной архитектуры компьютера.
Структуры данных обычно выравниваются на размер машинного слова компилятором при компиляции или интерпретатором для того чтобы более эффективно использовать преимущества аппаратной архитектуры поддерживаемыми ими инструкциями.
При сохранении данных на накопитель программа ничего не знает каким образом будут записываться данные в конечном итоге, так как за это отвечает файловая система. Если для программы данные в файле представлены линейно в виде последовательности блоков данных, то на файловой системе они могут быть сохранены совершенно в другом порядке и в разных частях накопителя (фрагментация жёсткого диска).
Аналогично и для оперативной памяти компьютера. ОС распределяет память как пользовательским программам, так и системным процессам, по мере необходимости. Одни блоки памяти резервируются для одних программ, которые по окончании их работы освобождаются и отдаются в последствии другим.

Бит - это единица информации. Может принимать два значения - в информатике это "1" или "0".

Байт - это величина информации равная 8 битам. Т.е. 1 байт это 8 последовательных "1" или "0" (битов).

Компью́терная програ́мма — последовательность инструкций, предназначенных для исполнения устройством управления вычислительной машины. Программа — один из компонентов программного обеспечения.

Указание процессору на выполнение одного из элементарных действий называется машинной командой.

В состав базового программного обеспечения входят:

· операционные системы;

· сервисные программы;

· трансляторы языков программирования;

· программы технического обслуживания.

Среда программирования служит для разработки (написания) программ и обычно ориентируется на конкретный язык или несколько языков программирования (в этом случае языки, обычно, принадлежат одной языковой группе, например, Си-подобные). Интегрированная среда программирования содержит в себе все необходимое для разработки программ:

· редактор с подсветкой синтаксиса конкретного языка программирования. В нем программист пишет текст программы, так называемый программный код;

· компилятор - транслирует программу, написанную на высокоуровневом языке программирования в машинный язык (машинный код), непосредственно понятный компьютеру.

· отладчик - служит для отладки программ.

 


3 Модули являются основой создания библиотек и приложений в C++ Builder. Модуль содержит исходный текст на языке C++ и первоначально представляет собой файл с расширением *.CPP. В дальнейшем каждый такой файл компилируется в объектный файл с расширением *.OBJ. Объектные файлы, в свою очередь, собираются компоновщиком в выполняемый файл с расширением *.EXE. Программа на исходном языке (исходный модуль) готовится с помощью текстовых редакторов и в виде текстового файла или разде­ла библиотеки поступает на вход транслятора. Объектный модуль представляет собой текст программы на ма­шинном языке, включающий машинные инструкции, словари, служеб­ную информацию.
Объектный модуль не работоспособен, поскольку содержит неразре­шенные ссылки на вызываемые подпрограммы библиотеки транслятора (в общем случае — системы программирования), реализующие функции ввода-вывода, обработки числовых и строчных переменных, а также на другие программы пользователей или средства пакетов прикладных программ. Построение загрузочного модуля осущ-ся спец программными средствами — редактором связей, построителем задач, компоновщиком, основной функцией которых является объединение объектных и загрузочных мо­дулей в единый загрузочный модуль с последующей записью в библио­теку или файл. Полученный модуль в дальнейшем может использовать­ся для сборки других программ и т.д., что создает возможность наращи­вания программного обеспечения.

4 Транслятор – это программа или техническое средство, выполняющее преобразование программы, представленной на одном из языков программирования, в программу на другом языке, в определенном смысле равносильную первой. Интерпретатор анализирует и тут же выполняет программу покомандно, по мере поступления ее исходного кода на вход интерпретатора. Отла́дчик является модулем среды разработки или отдельным приложением, предназначенным для поиска ошибок в программе. Отладчик позволяет выполнять пошаговую трассировку, отслеживать значения переменных в процессе выполнения программы, устанавливать точки или условия останова и т. д. Компоновщик (также реда́ктор свя́зей, англ. linker, link editor) — программа, которая производит компоновку — принимает на вход один или несколько объектных модулей и собирает по ним исполняемый модуль. Компиляция – преобразование программы, представленной на одном из языков программирования, в коды на машинно-ориентированном языке, которые принимаются и исполняются непосредственно процессором. Процесс компиляции состоит из следующих фаз: Лексический анализ, Синтаксический, Семантический, Оптимизация, Генерация кода

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

5 Сначала пишется текст основной программы, в котором, вместо каждого связного логического фрагмента текста, вставляется вызов подпрограммы, которая будет выполнять этот фрагмент. Вместо настоящих, работающих подпрограмм, в программу вставляются «заглушки», которые ничего не делают. Полученная программа проверяется и отлаживается. После того, как программист убедится, что подпрограммы вызываются в правильной последовательности (то есть общая структура программы верна), подпрограммы-заглушки последовательно заменяются на реально работающие, причём разработка каждой подпрограммы ведётся тем же методом, что и основной программы. Разработка заканчивается тогда, когда не останется ни одной «затычки», которая не была бы удалена. Такая последовательность гарантирует, что на каждом этапе разработки программист одновременно имеет дело с обозримым и понятным ему множеством фрагментов, и может быть уверен, что общая структура всех более высоких уровней программы верна. Отла́дка — этап разработки компьютерной программы, на котором обнаруживают, локализуют и устраняют ошибки. Чтобы понять, где возникла ошибка, приходится: узнавать текущие значения переменных; выяснять, по какому пути выполнялась программа. Существуют две взаимодополняющие технологии отладки:

Использование отладчиков — программ, которые включают в себя пользовательский интерфейс для пошагового выполнения программы: оператор за оператором, функция за функцией, с остановками на некоторых строках исходного кода или при достижении определённого условия.

Вывод текущего состояния программы с помощью расположенных в критических точках программы операторов вывода — на экран, принтер, громкоговоритель или в файл. Вывод отладочных сведений в файл называется журналированием.

6 Компоновка – это один из этапов создания исполняемого файла. Компилировать – проводить трансляцию машинной программы с проблемно-ориентированного языка на машинно-ориентированный язык (создание объектного кода) для ее исполнения. Результатом компиляции является объектный файл с необходимыми внешними ссылками для компоновщика. Программа уже переведена в машинные инструкции, однако еще не полностью готова к выполнению. В объектном файле имеются ссылки на различные системные функции. Даже если в программе явно не упомянута ни одна функция, необходим, по крайней мере, один вызов системной функции – завершение программы и освобождение всех принадлежащих ей ресурсов.

При загрузке программы в некоторую область памяти (например, в DOS или в режиме эмуляции DOS в Windows) она может размещаться не с самого начала этой области. В этом случае осуществляется привязка адресов переменных, заданных в относительных адресах от начала программного модуля к адресам памяти с учетом перемещения программного модуля (так называемый перемещающий загрузчик, которая имеет место для exe-файлов в DOS).

7 Структурное программирование — методология разработки программного обеспечения, в основе которой лежит представление программы в виде иерархической структуры блоков. Любая программа представляет собой структуру, построенную из трёх типов базовых конструкций: последовательное исполнение — однократное выполнение операций в том порядке, в котором они записаны в тексте программы; ветвление — однократное выполнение одной из двух или более операций, в зависимости от выполнения некоторого заданного условия; цикл — многократное исполнение одной и той же операции до тех пор, пока выполняется некоторое заданное условие (условие продолжения цикла).

Модульное программирование - это искусство разбиения задачи на некоторое число различных модулей, умение широко использовать стандартные модули путем их параметрической настройки, автоматизация сборки готовых модулей из библиотек, банков модулей.

8 Функциональная декомпозиция - метод разбивки большой программы на отдельные функции, т.е. общий алгоритм - на отдельные шаги, которые потом и оформляют в виде отдельных функций.
Алгоритм декомпозиции можно представить следующим образом: - программу делать как последовательность более мелких действий; - каждую детализацию подробно описать.

Единицей компиляции в языке Си является отдельный файл (программный модуль). Модульная декомпозиция представляет собой разбиение программы на несколько отдельных файлов, каждый из которых решает отдельную конкретную задачу и, как правило, облегчает процесс ее работы. Кроме того, код программы, разделенный на отдельные файлы, позволяет части этого кода использовать в других программах.

9 Операцио́нная систе́ма — комплекс управляющих и обрабатывающих программ, которые, с одной стороны, выступают как интерфейс между устройствами вычислительной системы и прикладными программами, а с другой стороны — предназначены для управления устройствами, управления вычислительными процессами, эффективного распределения вычислительных ресурсов между вычислительными процессами и организации надёжных вычислений.

Фа́йловая систе́ма — порядок, определяющий способ организации, хранения и именования данных на носителях информации в компьютерах, а также в другом электронном оборудовании. Конкретная файловая система определяет размер имени файла (папки), максимальный возможный размер файла и раздела, набор атрибутов файла. Некоторые файловые системы предоставляют сервисные возможности, например, разграничение доступа или шифрование файлов. По предназначению файловые системы можно классифицировать на нижеследующие категории.

Для носителей с произвольным доступом (например, жёсткий диск): FAT32, NTFS, ext2 и др.

Для оптических носителей — CD и DVD: ISO9660, HFS, UDF и др.

10 Алгоритмом называется точное и понятное предписаниe исполнителю совершить последовательность действий, направленных на решение поставленной задачи. Способы описания алгоритмов:

на естественном языке;

на специальном (формальном) языке;

с помощью формул, рисунков, таблиц;

с помощью стандартных графических объектов (геометрических фигур) – блок-схемы.

11

 

Графический (наглядный) способ представления алгоритма - это БЛОК-СХЕМА. Блоки обозначают действия исполнителя, а соединяющие их стрелки указывают на последова-тельность выполнения действий.

 

В ходе разработки программы должен быть подготовлен следующий графический материал:

технико-экономические показатели; структура программы; формат представления входных данных программы; общая схема алгоритма (2 листа); основные вычислительные алгоритмы; пример работы программы. Лучше всего готовить документацию параллельно с процессом составления, отладки и тестирования. Программная документация, кроме формальных документов (спецификация, ведомость держателей подлинников, формуляр и др.), включает: техническое задание (назначение, область применения программы, требования, предъявляемые к программе); текст программы (запись программы с необходимыми комментариями); описание программы (сведения о логической структуре и функционировании программы); пояснительная записка (схема алгоритма, общее описание алгоритма и/или функционирования программы, обоснование принятых решений); эксплуатационные документы.

Функции

int wcscasecmp(const wchar_t *s1, const wchar_t *s2) — широкосимвольный эквивалент функции strcasecmp. int strcasecmp(const char *s1, const char *s2) — сравнивает две строки s1 и s2, игнорируя регистр символов. Возвращает отрицат, нулевое или положит значение int, если s1 соответственно меньше, совпадает или больше s2. int strncasecmp(const char *s1, const char *s2, size_t n) — почти аналогичная strcasecmp, за исключением того, что сравнивает только первые N символов s1. int wcscmp(const wchar_t *s1, const wchar_t *s2) — широкосимвольный эквивалент функции strcmp.

stdio.h (от англ. standard input/output header — стандартный заголовочный файл ввода/вывода) заголовочный файл стандартной библиотеки языка Си, содержащий определения макросов, константы и объявления функций и типов, используемых для различных операций стандартного ввода и вывода.

Функция printf() является функцией стандартного вывода. С помощью этой функции можно вывести на экран монитора строку символов, число, значение переменной.


Битовое поле.

В противоположность другим компьютерным языкам С имеет возможность, называемую битовыми полями, позволяющую работать с отдельными битами. Битовые поля полезны по нескольким причинам. Ниже приведены три из них: 1 Если ограничено место для хранения информации, можно сохранить несколько логических (истина/ложь) переменных в одном байте. 2 Некоторые интерфейсы устройств передают информацию, закодировав биты в один байт. 3 Некоторым процедурам кодирования необходимо получить доступ к отдельным битам в байте. Хотя все эти функции могут выполняться с помощью битовых операторов, битовые поля могут внести большую ясность в программу.

Метод использования битовых полей для доступа к битам основан на структурах. Битовое поле, на самом деле, - это просто особый тип структуры, определяющей, какую длину имеет каждый член. Стандартный вид объявления битовых полей следующий:

struct имя структуры {

тип имя1: длина;

тип имя2: длина;

...

тип имяN: длина;

}

Битовые поля должны объявляться как int, unsigned или signed. Битовые поля длиной 1 должны объявляться как unsigned, поскольку 1 бит не может иметь знака. Битовые поля могут иметь длину от 1 до16 бит для 16-битных сред и от 1 до 32 бит для 32-битных сред.

 

 

Объединение – это тип данных, позволяющий переменным различного типа использовать одну и ту же область памяти. Для объявления объединения используется ключевое слово union. Объединение, так же как и структура, содержит несколько полей. Однако в любой момент времени доступно только одно поле. Под объединение выделяется столько памяти, сколько требуется для размещения самого большого поля. Все поля поочередно используют выделенную память для хранения своих значений. Определение типа:

union tag

{

тип1 переменная1;

тип2 переменная2;

……

};

где tag – имя типа.

Объявление переменной:

union tag u1;

или

union tag

{

тип1 переменная1;

тип2 переменная2;

……

} u1;

При обращении к полям объединения следует помнить, какое поле размещалось в памяти последним. Если пытаться извлекать данные с помощью поля другого типа, значение может быть прочитано неправильно.

Пример

union tag

{

int i;

double d;

} u={1.2};

printf("%d\n",u.i); //Вывод на экран числа 1

printf("%lf\n",u.d); //Вывод на экран числа 0

Ответ «1» получен потому, что инициализация должна соответствовать типу первого поля – int; ответ «0» – ледствие того, что данные типа int прочитаны полем типа float неправильно.

Перечисления - это набор именованных целочисленных констант, определяющий все допустимые значения, которые может принимать переменная. Перечисления можно встретить в повседневной жизни. Например, в качестве перечислений монет в Соединенных Штатах используются: один цент, пять центов, десять центов, двадцать пять центов, полдоллара, доллар

Перечисления определяются с помощью ключевого слова enum, которое указывает на начало перечисляемого типа. Стандартный вид перечислений следующий:

enum ярлык { список перечислений} список переменных;

Как имя перечисления - ярлык, так и список переменных необязательны, но один из них должен присутствовать. Список перечислений - это разделенный запятыми список идентификаторов. Как и в структурах, ярлык используется для объявления переменных данного типа. Следующий фрагмент определяет перечисление coin и объявляет переменную money этого типа:

enum coin { penny, nickel, dime, quarter, half_dollar, dollar);

enum coin money;

Имея данное определение и объявление, следующий тип присваивания совершенно корректен:

money = dime;

if (money==quarter) printf("is a quarter\n");

Важно понять, что в перечислениях каждому символу ставится в соответствие целочисленное значение и поэтому перечисления могут использоваться в любых целочисленных выражениях. Например:

printf("The value of quarter is %d ", quarter); совершенно корректно.

Если явно не проводить инициализацию, значение первого символа перечисления будет 0, второго - 1 и так далее. Следовательно: printf("%d %d", penny, dime); выводит 0 2 на экран.

Указатель – это переменная, значением которой является адрес некоторого объекта (обычно другой переменной) в памяти компьютера. Подобно тому, как переменная типа char имеет в качестве значения символ, а переменная типа int – целочисленное значение, переменная типа указателя имеет в качестве значения адрес ячейки оперативной памяти. Допустимые значения для переменной-указателя – множество адресов оперативной памяти компьютера. Указатель является одной из наиболее важных концепций языка C. Правильное понимание и использование указателей особенно необходимо для составления хороших программ по следующим причинам: · указатели являются средством, при помощи которого функции могут изменять значения передаваемых в нее аргументов; · при помощи указателей выполняется динамическое распределение памяти; · указатели позволяют повысить эффективность программирования; · указатели обеспечивают поддержку динамических структур данных (двоичные деревья, связные списки).

Однако указатель может вызвать и ряд затруднений, например, если указатель содержит неправильное значение, программа может быть неработоспособной. Можно легко ошибиться при использовании указателей; к тому же ошибки, связанные с неправильными значениями указателей, найти очень трудно.

Итак, указатель – это новый тип данных. Для него определены понятия константы, переменной, массива. Как и любую переменную, указатель необходимо объявить. Объявление указателя состоит из имени базового типа, символа * (звездочка) и имени переменной.

Общая форма объявления указателя: тип *имя;

Тип указателя определяет тип объекта, на который указатель будет ссылаться, например, int *p1;

Фактически указатель любого типа может ссылаться на любое место в памяти, но выполняемые над указателем операции существенно зависят от его типа. Так, если объявлен указатель типа int *, компилятор предполагает, что любой адрес, на который он ссылается, содержит переменную типа int, хотя это может быть и не так. Следовательно, объявляя указатель, необходимо убедиться в том, что его тип совместим с типом объекта, на который он будет ссылаться.

Указатели и массивы

В языке C массивы и указатели тесно связаны друг с другом. Например, когда объявляется массив в виде int a[25], то при этом не только выделяется память для 25 элементов массива, но и формируется указатель с именем a, значение которого равно адресу первого по счету (нулевого) элемента массива. Доступ к элементам массива может осуществляться через указатель с именем a. С точки зрения синтаксиса языка указатель a является константой, значение которой можно использовать в выражениях, но изменить это значение нельзя.

Поскольку имя массива является указателем-константой, допустимо, например, такое присваивание:

int a[25]; // int *ptr; // ptr=a;

В этом примере в переменную-указатель ptr записывается адрес начала массива a, т. е. адрес первого элемента массива.

Также справедливы следующие соотношения: например, имеется массив a[N], тогда истинными будут следующие сравнения:

a==&a[0]; // *a==a[0].

Указатели можно увеличивать или уменьшать на целое число:

ptr=a+1;

Теперь указатель ptr будет указывать на второй элемент массива a, что эквивалентно &a[1].

При увеличении указателя на единицу адрес, который он представляет, увеличивается на размер объекта связанного с ним типа, например:

int a[25]; // int *ptr=a; // ptr+=3;

Первоначально указатель ptr указывал на начало массива a. После прибавления к переменной ptr числа 3 значение указателя увеличилось на 3*sizeof(int), а указатель ptr теперь будет указывать на четвертый элемент массива a.

Таким образом, в языке C для доступа к элементам массива существует два различных способа. Первый способ связан с использованием обычных индексных выражений в квадратных скобках, например, a[7]=3 или a[i+2]=5. При таком способе доступа записываются два выражения, причем второе выражение заключается в квадратные скобки. Первое из этих выражений должно быть указателем, а второе – выражением целого типа. Указатель, используемый в индексном выражении, не обязательно должен быть константой, указывающей на какой-либо массив, это может быть и переменная-указатель. В частности, после выполнения присваивания ptr=a доступ к седьмому элементу массива можно получить как с помощью константы-указателя a в форме a[7], так и переменной-указателя ptr в форме ptr[7].

Операция получения адреса

Понятие указателя тесно связано с понятием адреса объекта. В C есть специальная операция, позволяющая получить адрес любой переменной: &p – получение адреса, где p – идентификатор переменной. Результатом операции является адрес переменной p. Пример программы:

# include <stdio.h> // int main() // { // int x=2,*p; // p=&x;

printf("\n x=%d address of x=%u",x,p); // return 0; // }

Понятие переменной типа указатель также связано с операцией косвенной адресации *, называемой еще операцией разыменования, которая имеет структуру: *р – разыменование, где р – идентификатор переменной-указателя. Эта запись означает, что в ячейку с адресом, записанным в переменную р, помещено значение некоторой величины.

Операторы ptr=&a; и val=*ptr; равнозначны оператору val=a;

Например,

n=32;

p=&n; /* p–адрес ячейки, куда записано n */

v=*p;

В результате выполнения этих действий в переменную v будет помещено число 32.

Операции над указателями

Над указателями определено 5 основных операций.

§ Определение адреса указателя: &p, где p – указатель (&p – адрес ячейки, в которой находится указатель).

§ Присваивание. Указателю можно присвоить адрес переменной p=&q, где p – указатель, q – идентификатор переменной.

§ Определение значения, на которое ссылается указатель: *p (операция косвенной адресации).

§ Увеличение (уменьшение) указателя. Увеличение выполняется как с помощью операции сложения (+), так и с помощью операции инкремента (++). Уменьшение – с помощью операции вычитания (–) либо декремента (––).

Например, пусть p1 – указатель, тогда р1++ перемещает указатель на:

o 1 байт, если *p1 имеет тип char;

o 4 байта, если *p1 имеет тип int (в 32 разрядной операционной системе) или 2 байта (в 16 разрядной операционной системе);

o 4 байта, если *p1 имеет тип float.

§ Разность двух указателей. Пусть р1 и р2 – указатели одного и того же типа. Можно определить разность р1 и р2, чтобы найти, на каком расстоянии друг от друга находятся элементы массива.

Далее смотрим вопрос 50.

Операции адресной арифметики (вопрос 50) подчиняются следующим правилам. После увеличения значения переменной-указателя на 1 данный указатель будет ссылаться на следующий объект своего базового типа. После уменьшения – на предыдущий объект. Для всех указателей адрес увеличивается или уменьшается на величину, равную размеру объекта того типа, на который они указывают. Поэтому указатель всегда ссылается на объект с типом, тождественным базовому типу указателя.

Применительно к указателям на объект типа char операции адресной арифметики выполняются как обычные арифметические операции, потому что длина объекта char всегда равна 1.

Операции адресной арифметики не ограничены увеличением (инкрементом) и уменьшением (декрементом). К указателям, например, можно добавлять или вычитать из них целые числа.

При операции вычитания двух указателей можно определить количество объектов, расположенных между адресами, на которые указывают эти два указателя. При этом необходимо, чтобы указатели имели один и тот же тип. Кроме того, стандартом C допускается сравнение двух указателей. Как правило, сравнение указателей может оказаться полезным только тогда, когда два указателя ссылаются на общий объект, например, на массив.

Все остальные операции над указателями запрещены.

 

51 Распределение памяти. Память для хранения данных может выделяться как статически, так и динамически. В первом случае выделение памяти выполняет компилятор, встретивший при компиляции объявление объекта. В соответствии с типом встретившегося объекта вычисляется объем памяти, требуемый для его размещения. Класс памяти задает место, где эти объекты (данные) будут располагаться. Это может быть сегмент данных либо стек. Напомним, что стек (магазин, список LIFO – Last In First Out) представляет собой последовательный список переменной длины, в котором включение и исключение элементов производится только с одной стороны. Главные операции при работе со стеком – включение и исключение элемента – осуществляются с вершины стека, причем в каждый момент доступен элемент, находящийся на вершине стека.

Часто возникают ситуации, когда заранее не известно, сколько объектов – чисел, строк текста и прочих данных будет хранить программа. В этом случае используется динамическое выделение памяти, когда память занимается и освобождается в процессе исполнения программы. При использовании динамической памяти (ДП) отпадает необходимость заранее распределять память для хранения данных, используемых программой. Управление динамической памятью – это способность определять размер объекта и выделять для его хранения соответствующую область памяти в процессе исполнения программы.

При динамическом выделении памяти для хранения данных используется специальная область памяти, так называемая «куча» (heap). Объем «кучи» и ее местоположение зависят от модели памяти, которая определяет логическую структуру памяти программы (гл. 8).

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

При каждом обращении к функции распределения памяти выделяется запрошенное число байт. Адрес начала выделенной памяти возвращается в точку вызова функции и записывается в переменную-указатель. Созданная таким образом переменная называется динамической переменной. Распределенная память гарантируется от повторного выделения при следующих обращениях за байтами памяти. Дальнейшая работа с выделенной областью осуществляется через переменную-указатель, хранящую адрес выделенной области памяти. Сама же переменная остается безымянной.

Если выделенный участок памяти больше не требуется, он может быть освобожден. При высокой активности по динамическому распределению памяти «куча» фрагментируется. Для смягчения отрицательных последствий фрагментации служат функции повторного распределения памяти. Они пытаются либо расширить, либо уменьшить размер ранее выделенного блока памяти.

Функции управление памятью. Рассмотрим функции управления памятью:

· malloc() – предназначена для выделения непрерывной области памяти заданного размера, например, void * malloc(size_t size),

где size_t – тип результата операции sizeof, определяемый в различных объектах-заголовках (stdio.h,stdlib.h,string.h и др.) и соответствующий типу unsigned long; size – размер выделяемой памяти в байтах.

Функция malloc возвращает указатель без типа. Если выделить память не удалось, функция возвращает значение NULL.



Поделиться:


Последнее изменение этой страницы: 2016-08-14; просмотров: 345; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.226.200.93 (0.011 с.)