
- •Введение в системное программирование Основные понятия и определения Программы и программное обеспечение
- •Системное программирование
- •Этапы подготовки программы
- •Системное программирование
- •Лекция 1
- •1. Язык Си: Общая характеристика, историческая справкаи основные достоинства
- •2. Подготовка к выполнению и выполнение программ
- •3. Элементы языка с
- •Лекция 2
- •1. Понятие типа данных. Переменные и константы. Операция присваивания
- •2.Типы данных в языке си. Описание данных в программе
- •3. Константы в языке Си
- •4. Арифметические операции и арифметические выражения
- •5. Операции отношения, логические операции и логические выражения
- •6. Автоматическое преобразрвание типов и операция приведения
- •7. Простейшие операторы языка си. Составной оператор
- •Лекция 3
- •3. Инициализация переменных и массивов
- •4. Управляющие конструкции языка си
- •Лекция 4
- •1. Адреса и указатели
- •2. Отождествление массивов и указателей.Адресная арифметика
- •3. Указатели на массивы. Массивы указателей и многомерные массивы
- •4. Динамическое выделение памяти под массивы
- •5. Инициализация указателей
- •Лекция 5
- •1. Функции в языке си. Формальные и фактические параметры. Механизм передачи параметров. Возвращаемые значения
- •2. Использование указателей в качестве аргументов функций
- •3. Предварительное описание функций
- •4. Аргументы командной строки
- •Лекция 6
- •1. Ввод и вывод в языке си: Общие концепции
- •2. Файлы данных и каталоги. Внутренняя организация и типы файлов
- •3. Стандартные функции для работы с файлами и каталогами
- •4. Внешние устройства как специальные файлы. Организация обмена со стандартными внешними устройствами
- •5. Операции ввода/вывода через порты микропроцессоров intel 8086/80286
- •Лекция 7
- •1. Общая структура программы на языке си. Время существования и видимость переменных. Блоки
- •2. Классы памяти
- •3. Рекурсивные вызовы функций. Реализация рекурсивных алгоритмов
- •4. Препроцессор языка Си
- •5. Модели памяти, поддерживаемые компилятором ibm c/2
- •Лекция 8
- •1. Структуры в языке си: основные понятия
- •2. Массивы структур
- •3. Указатели на структуры
- •4. Вложение структур
- •5. Структуры и функции
- •6. Объединения
- •7. Перечисления
- •8. Определение и использование новых типов данных
- •9. Классы имен
Лекция 3
Массивы переменные как однородные статические структуры данных. Строки символов. Инициализация переменных и массивов. Управляющие конструкции языка Си: синтаксис и семантика.
$ 1. Массивы переменных как однородные статические структуры данных
В начале предыдущей лекции мы познакомились с основными типами данных языка Си и правилами описания переменных в программах. Однако до сих пор нам приходилось иметь дело лишь с простыми переменными, являющимися носителями одного единственного значения, будь то число или внутреннее машинное представление некоторого символа ASCII. Однако при решении на ЭВМ большинства практических задач приходится иметь дело с наборами данных, представимых в виде векторов, таблиц, строк или абстрактных множеств с неупорядоченной структурой. Для размещения перечисленных объектов в памяти ЭВМ аппарат простых переменных оказывается явно недостаточным, приводя к неоправданной громоздкости и логической сложности программ. Наиболее простой логической структурой данных является ограниченный вектор элементов фиксированного типа. Элементы вектора считаются занумерованными последовательно отрезком ряда натуральных чисел и доступ к каждому из них может осуществляться по его индивидуальному номеру. Простота подобных структур данных состоит в том, что они самым естественным образом отображаются на линейную структуру памяти ЭВМ.
Структурным аналогом векторов в языке Си (как и в большинстве других языков программирования) являются массивы переменных, т.е. упорядоченные последовательности элементов данных одного типа. С каждым таким массивом связывается его имя, тип элементов (а следовательно и объем машинной памяти, требуемой для размещения одного элемента) и их количество (т.е. длина массива). Для описания массивов в Си-программах используются инструкции, подобные тем, которые были введены для описания простых переменных. Различие состоит лишь в том, что теперь эти инструкции должны содержать информацию о длине массива и в общем случае имеют следующий формат:
<sc-specifier> type-specifier identifier[const-expression] <, ... >;
где sc-specifier есть описатель класса памяти (см. Лекцию 7, $ 2);
type-specifier - имя типа данных, которому принадлежат элементы массива;
identifier - имя переменной, объявляемой массивом;
const-expression - константное арифметическое выражение, определяющее количество элементов в массиве (т.е. его длину). Например, инструкции
int f[10];
char b[5];
определяют два массива: массив f, состоящий из десяти элементов типа int, и массив символов b, длина которого равна пяти. Для обращения в программе к индивидуальному элементу всякого массива следует указывать его имя и порядковый номер, заключенный в квадратные скобки:
c = 2*f[5] + 4;
причем последние в данном случае рассматриваются как символ операции взятия элемента, имеющей максимально высокий приоритет. Важно заметить, что компилятор языка Си нумерует элементы массивов, начиная с нуля (а не с единицы, как это принято во многих языках программирования). Поэтому в приведенном выше примере одним из операндов арифметического выражения в правой части является шестой (а не пятый!) элемент массива f. Последний же элемент этого массива должен индексироваться числом 9. В общем случае порядковые номера элементов могут задаваться произвольными арифметическими выражениями целого типа, которые будем называть индексными выражениями. Язык Си не обеспечивает возможности работы с массивами переменных как с единым целым: в качестве операндов выражений могут выступать лишь отдельные элементы. Однако ссылка на имя массива без следующего за ним индекса элемента все же имеет определенный смысл, поскольку отождествляется с адресом размещения в памяти самого первого элемента этого массива. Подробный разговор об использовании адресов и адресной арифметике пойдет в следующей лекции.
$ 2. Строки символов
В $ 3 предыдущей лекции, посвященном рассмотрению констант в языке Си, мы уже познакомились с понятием символьной строки как последовательности, состоящей из одного или более символов ASCII. Теперь нам предстоит обсудить вопрос о размещении строк в памяти ЭВМ и об их использовании в программах. Дело в том, что в языке Си нет специального типа, который можно было бы использовать для описания строк. Вместо этого они представляются в виде массивов элементов типа char. Такое решение проблемы означает, что символы строки располагаются в соседних ячейках памяти - по одному символу в ячейке. В то же время, столь упрощенное представление о строках несколько затрудняет рактическую работу с ними, поскольку в большинстве случаев строки интересуют нас как целостные в логическом отношении единицы информации, а не как наборы символов, из которых они состоят. Частичный выход из создавшейся ситуации достигается путем помещения нуль- символа (Esc-последовательность \0) в конец всякой строки. Это означает, что под строкой следует понимать последовательность символов, начинающуюся в нулевом элементе массива типа char и заканчивающуюся символом \0. При этом нужно помнить, что описывая символьный массив необходимо резервировать одну дополнительную ячейку памяти под хранение нуль- символа. Так, например, для представления строки, содержащей 40 символов, в программе необходимо иметь описание вида
char string[41];
т.е. размерность массива должна быть по крайней мере на единицу больше истинной длины строки. Тем не менее, ввиду того, что в языке Си нет средств для работы с массивами как с единым целым, то и не существует возможности манипулировать строками как неделимыми единицами информации. Это затруднение снимается за счет использования функций из стандартной библиотеки языка. Ниже приведены примеры некоторых из них.
Имя функции и назначение: strcat - добавление строки string2 в конец строки string1
Формат и описание аргументов:
char *strcat(string1, string2)
char *string1; /* Указатель на строку-приемник */
char *string2; /* Указатель на строку-источник */
Возвращаемое значение равно адресу начала стороки string1, т.е. указателю на эту строку.
Имя функции и назначение: strchr - поиск первого вхождения символа sym в строку string
Формат и описание аргументов:
char *strchr(string, sym)
const char *string; /* Указатель на строку */
int sym; /* Символ поиска */
Возвращаемое значение является указателем на первое вхождение символа sym в строку string и равно NULL, если этот символ в составе строки не найден.
Имя функции и назначение: strcmp - сравнение строк string1 и string2, считая различными большие и малые буквы латинского алфавита
Формат и описание аргументов:
int strcmp(string1, string2)
const char *string1; /* Указатель на первую строку */
const char *string2; /* Указатель на вторую строку */
Возвращаемое значение равно нулю для идентичных строк и отлично от нуля в противном случае.
Имя функции и назначение: strcmpi - сравнение строк string1 и string2, не делая различия между большими и малыми буквами латинского алфавита
Формат и описание аргументов:
int strcmpi(string1, string2)
const char *string1; /* Указатель на первую строку */
const char *string2; /* Указатель на вторую строку */
Возвращаемое значение равно нулю для идентичных строк и отлично от нуля в противном случае.
Имя функции и назначение: strcpy - копирование строки string2 в строку string1
Формат и описание аргументов:
char *strcpy(string1, string2)
char *string1; /* Указатель на строку-приемник */
const char *string2; /* Указатель на строку-источник */
Возвращаемое значение равно адресу начала строки string1, т. е. является указателем на эту строку.
Имя функции и назначение: strlen - определение длины строки string
Формат и описание аргументов:
int strlen(string)
const char *string; /* Указатель на строку */
Возвращаемое значение равно количеству символов в строке string, исключая завершающий нуль-символ.
Имя функции и назначение: strlwr - замена всех больших букв латинского алфавита в составе строки string соответствующими им малыми буквами
Формат и описание аргументов:
char *strlwr(string)
char *string; /* Указатель на преобразуемую строку */
Возвращаемое значение равно адресу начала строки string, т. е. указателю на эту строку.
Имя функции и назначение: strstr - поиск первого вхождения подстроки string2 в строку string1
Формат и описание аргументов:
char *strstr(string1, string2)
const char *string1; /* Указатель на строку */
const char *string2; /* Указатель на подстроку */
Возвращаемое значение является указателем на первое вхождение подстроки string2 в строку string1 и равно NULL, если подстрока поиска не обнаружена в составе строки string1.
Имя функции и назначение: strupr - замена всех малых букв латинского алфавита в составе строки string соответствующими им большими буквами
Формат и описание аргументов:
char *strupr(string)
char *string; /* Указатель на преобразуемую строку */
Возвращаемое значение равно адресу начала строки string, т. е. указателю на эту строку.
Предварительные описания всех этих функций (см. Лекцию 5, $ 3) помещены в файл string.h и при их использовании последний должен быть включен в состав исходного текста программы с помощью директивы препроцессора #include (см. Лекцию 7, $ 4 и примеры программ). Встречающееся в этом параграфе понятие указателя будет подробно рассмотрено в Лекции 4.