Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Язык С как инструмент системного программирования
Главным качеством языка C, которое делает его именно языком системного программиста, является то, что «C — это язык относительно «низкого уровня»... Это означает, что C имеет дело с объектами того же вида, что и большинство ЭВМ, а именно, с символами, числами и адресами. Они могут объединяться и пересылаться посредством обычных арифметических и логических операций, осуществляемых реальными ЭВМ.» [2]. Система программирования C при представлении данных не вносит никаких дополнительных структур памяти, которые не были бы «видны» программисту. Так, например, внутреннее представление массивов в языке C полностью совпадает с внешним: массив — это только последовательность слотов в памяти. Отсутствие специального дескриптора массива, с одной стороны, делает невозможным контроль выхода индексов за допустимое границы, но с другой, уменьшает объем памяти программы и увеличивает ее быстродействие за счет отсутствия в памяти дескриптора и команд проверки индекса при каждом обращении к элементу массива. Это общий принцип C-программ: программист имеет максимальные возможности для разработки эффективных программ, но вся ответственность за их правильность ложится на него самого. Поэтому отладка программ на языке C — непростой процесс, C-программы чаще «зависают» и выдают результаты, которые не всегда воспроизводятся и которые труднее объяснить, чем программы на других языках. Чрезвычайно важным свойством языка C, которого нет в других языках, является адресная арифметика. Над данными типа «указатель» возможны арифметические операции, причем в них могут учитываться размеры тех объектов, которые адресуются указателем. Другое свойство указателей — их явная связь с конструкциями интеграции данных (массивы, структуры, объединения) и возможность подмены операций индексации и квалификации операциями адресной арифметики. За счет указателей программист имеет возможность удобным для себя способом структурировать адресное пространство программы и гибко изменять это структурирование. Свойством, которое вытекает из общих принципов построения языка C, является слабая защита типов. В языках с сильной защитой типов (Pascal) для каждого типа данных определен набор доступных операций и компилятор запрещает применение к типу непредусмотренных для него операций и смешивание в выражениях данных разных типов. В C определен богатый набор правил преобразования типов по умолчанию, поэтому почти любая операция может быть применена к почти любому типу данных и выражения могут включать данные самых разных типов. Еще некоторые средства языка не ориентированы непосредственно на низкоуровневое системное программирование, но могут быть очень полезны при разработке системных программ: u обязательной составной частью языка является препроцессор. C не поддерживает сложных структур данных, но позволяет программисту определять свои типы. Включение в программу описания таких типов средствами препроцессора позволяет обеспечить однозначную интерпретацию типов во всех модулях сложного программного изделия; u процедурно-ориентированный язык C вместе с тем представляет все кодовые составляющие программы в виде функций. Это дает возможность применять язык C и як инструмент функционально-ориентированного программирования, как, например, язык LISP. Важное качество языка C — высокая эффективность объектных кодов C-программы как по быстродействию, так и по объему памяти. Хотя это качество обеспечивается не столько свойствами самого языка, сколько свойствами системы программирования, традиция построения систем программирования C именно такова, что они обеспечивают большую, эффективность, чем, например, Pascal. Это связано еще и с «родословной» языков. Pascal возник как алгоритмический язык, предназначенный в своей первой версии не для написания программ, а для описания алгоритмов. Отсюда Pascal-трансляторы строились и строятся как синтаксически-ориентированные трансляторы характерно компилирующего типа: транслятор выполняет синтаксический анализ программы в соответствии с формально представленными правилами, а объектные коды формируются в основном в виде обращений к библиотечным процедурам, которые реализуют элементарные функции. Язык C ведет свое происхождение от языка BCPL, который был языком Макроассемблера. Отсюда и объектный код C-программы строится як последовательность машинных команд, которая оптимизируется для каждого конкретного выполнения данной функции. : Порядок выполнения работ Для выполнения всех лабораторных работ предлагается единый порядок, предусматривающий следующие шаги. u Ознакомиться с постановкой задачи и исходными данными. Определить вариант индивидуального задания. u Сконструировать структуру программы. u Составить текст программы. u Набрать текст программы. u Выполнить компиляцию программы. u Провести анализ и исправление обнаруженных синтаксических ошибок в тексте программы. u Получить решение (изображение) и, в случае обнаружения логических ошибок, определить и устранить их. : Содержание отчета Отчет оформляется по каждой лабораторной работе и состоит из следующих разделов. u Лекция лабораторной работы. u Цель работы. u Индивидуальное задание. u Описание структур данных и алгоритмов u Результаты работы программы. u Интерпретация результатов. : Лабораторная работа №1. Цель работы Получение практических навыков в работе с массивами и указателями языка C, обеспечение функциональной модульности
Темы для предварительного изучения u Указатели в языке C. u Представление строк. u Функции и передача параметров. Постановка задачи По индивидуальному заданию создать функцию для обработки символьных строк. За образец брать библиотечные функции обработки строк языка C, но не применять их в своей функции. Предусмотреть обработку ошибок в задании параметров и особые случаи. Разработать два варианта заданной функции — используя традиционную обработку массивов и используя адресную арифметику. Индивидуальные задания Функция Copies(s, s1, n) Назначение: копирование строки s в строку s1 n раз Функция Words(s) Назначение: подсчет слов в строке s Функция Concat(s1, s2) Назначение: конкатенация строк s1 и s2 (аналогичная библиотечная функция C — strcat) Функция Parse(s, t) Назначение: разделение строки s на две части: до первого вхождения символа t и после него Функция Center(s1, s2, l) Назначение: центрирование — размещение строки s1 в середине строки s2 длиной l Функция Delete(s, n, l) Назначение: удаление из строки s подстроки, начиная с позиции n, длиной l (аналогичная библиотечная Функция есть в Pascal). Функция Left(s, l) Назначение: выравнивание строки s по левому краю до длины l. Функция Right(s, l) Назначение: выравнивание строки s по правому краю до длины l. Функция Insert(s, s1, n) Назначение: вставка в строку s подстроки s1, начиная с позиции n (аналогичная библиотечная функция есть в Pascal). Функция Reverse(s) Назначение: изменение порядка символов в строке s на противоположный. Функция Pos(s, s1) Назначение: поиск первого вхождения подстроки s1 в строку s (аналогичная функция C — strstr). Функция LastPos(s, s1) Назначение: поиск последнего вхождения подстроки s1 в строку s. Функция WordIndex(s, n) Назначение: определение позиции начала в строке s слова с номером n. Функция WordLength(s, n) Назначение: определение длины слова с номером n в строке s. Функция SubWord(s, n, l) Назначение: выделение из строки s l слов, начиная со слова с номером n. Функция WordCmp(s1, s2) Назначение: сравнение строк (с игнорированием множественных пробелов). Функция StrSpn(s, s1) Назначение: определение длины той части строки s, которая содержит только символы из строки s1. Функция StrCSpn(s, s1) Назначение: определение длины той части строки s, которая не содержит символы из строки s1. Функция Overlay(s, s1, n) Назначение: перекрытие части строки s, начиная с позиции n, строкой s1. Функция Replace(s, s1, s2) Назначение: замена в строке s комбинации символов s1 на s2. Функция Compress(s, t) Назначение: замена в строке s множественных вхождений символа t на одно. Функция Trim(s) Назначение: удаление начальных и конечных пробелов в строке s. Функция StrSet(s, n, l, t) Назначение: установка l символов строки s, начиная с позиции n, в значение t. Функция Space(s, l) Назначение: доведение строки s до длины l путем вставки пробелов между словами. Функция Findwords(s, s1) Назначение: поиск вхождения в строку s заданной фразы (последовательности слов) s1. Функция StrType(s) Назначение: определение типа строки s (возможные типы — строка букв, десятичное число, 16-ричное число, двоичное число и т.д.). Функция Compul(s1, s2) Назначение: сравнение строк s1 и та s2 с игнорированием различий в регистрах. Функция Translate(s, s1, s2) Назначение: перевод в строке s символов, которые входят в алфавит s1, в символы, которые входят в алфавит s2. Функция Word(s) Назначение: выделение первого слова из строки s. Примечание: под «словом» везде понимается последовательность символов, которая не содержит пробелов.
: Пример решения задачи Индивидуальное задание Функция substr(s, n, l) Назначение: выделение из строки s подстроки, начиная с позиции n, длиной l. Описание метода решения Символьная строка в языке C представляется в памяти как массив символов, в конце которого находится байт с кодом 0 — признак конца строки. Строку, как и любой другой массив можно обрабатывать либо традиционным методом — как массив, с использованием операции индексации, либо через указатели, с использованием операций адресной арифметики. При работе со строкой как с массивом нужно иметь в виду, что длина строки заранее неизвестна, так что циклы должны быть организованы не со счетчиком, а до появления признака конца строки. Функция должна реализовывать поставленную задачу — и ничего более. Это означает, что функцию можно будет, например, перенести без изменений в любую другую программу, если спецификации функции удовлетворяют условиям задачи. Это также означает, что при ошибочном задании параметров или при каких-то особых случаях в их значениях функция не должна аварийно завершать программу или выводить какие-то сообщения на экран, но должна возвращать какое-то прогнозируемое значение, по которому та функция, которая вызвала нашу, может сделать вывод об ошибке или об особом случае. Определим состав параметров функции: int substr (src, dest, num, len); где u src — строка, с которой выбираются символы; u dest — строка, в которую записываются символы; u num — номер первого символа в строке src, с которого начинается подстрока (нумерация символов ведется с 0); u len — длина выходной строки. Возможные возвращаемые значения функции установим: 1 (задание параметров правильное) и 0 (задание не правильное). Эти значения при обращениях к функции можно будет интерпретировать как «истина» или «ложь». Обозначим через Lsrc длину строки src. Тогда возможны такие варианты при задании параметров: u num+len < = Lsrc — полностью правильное задание; u num+len > Lsrc; num < Lsrc — правильное задание, но длина выходной строки будет меньше, чем len; u num > = Lsrc — неправильное задание, выходная строка будет пустой; u num < 0 или len < = 0 — неправильное задание, выходная строка будет пустой. Заметим, что интерпретация конфигурации параметров как правильная/неправильная и выбор реакции на неправильное задание — дело исполнителя. Но исполнитель должен строго выполнять принятые правила. Возможен также случай, когда выходная строка выйдет большей длины, чем для нее отведено места в памяти. Однако, поскольку нашей функции неизвестен размер памяти, отведенный для строки, функция не может распознать и обработать этот случай — так же ведут себя и библиотечные функции языка C. Популярное:
|
Последнее изменение этой страницы: 2017-03-08; Просмотров: 2094; Нарушение авторского права страницы