Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015

Тут можно читать онлайн Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - бесплатно полную версию книги (целиком) без сокращений. Жанр: Прочая старинная литература, издательство Вильямс, год 0101. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.

Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание

Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - описание и краткое содержание, автор Стивен Прата, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)

Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать книгу онлайн бесплатно, автор Стивен Прата
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

List movies;

устанавливает movies как указатель, подходящий для ссылки на связный список.

Является ли этот способ определения типа List единственным? Нет. Например, для отслеживания количества записей можно было бы задействовать переменную:

typedef struct list {

Node * head; /* указатель на заголовок списка */

int size; /* количество записей в списке */

} List; /* альтернативное определение списка */

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

List movies;

следует рассматривать как определение списка, а не установку указателя на узел или структуры.

Расширенное представление данных 733

Точное представление данных списка movies является деталью реализации, которая не должна быть видна на уровне интерфейса.

Например, при запуске программа должна инициализировать указатель на заголовок значением NULL, но не следует применять код вроде такого:

movies = NULL;

А почему? По той причине, что впоследствии может оказаться, что реализация типа List в виде структуры подходит больше, и тогда потребуется следующая инициализация:

movies.next = NULL; movies.size = 0;

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

InitializeList(movies);

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

Для предоставления руководства пользователю прототип функции можно сопровождать следующими строками:

/* операция: инициализация списка */

/* предусловия: plist указывает на список list */

/* постусловия: список инициализирован пустым содержимым */

void InitializeList(List * plist);

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

InitializeList(smovies);

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

Принятый в языке С метод объединения информации о типе и функциях в единый пакет предполагает помещение определений для типа и прототипов функций (в том числе комментариев с пред- и постусловиями) в заголовочный файл. Этот файл должен предоставлять всю информацию, в которой нуждается программист для использования типа. Заголовочный файл для простого типа list показан в листинге 17.3. В нем конкретная структура определена как относящаяся к типу Item, после чего тип Node определен в терминах Item и тип List — в терминах Node. Затем в функциях, представляющих операции над списком, типы Item и List применяются для аргументов. Если функции необходимо модифицировать аргумент, она использует указатель

734 Глава 17 на соответствующий тип, а не сам тип напрямую. В файле имена функций начинаются с прописных букв для их обозначения как части интерфейсного пакета. Кроме того, для защиты от множественного включения файла применяется прием с #ifndef, который обсуждался в главе 16. Если ваш компилятор не поддерживает тип bool из стандарта С99, можете заменить в заголовочном файле строку

#include /* функциональная возможность С99 */

такой строкой:

Листинг 173 Заголовочный файл для интерфейса listli Расширенное - фото 543

Листинг 17.3. Заголовочный файл для интерфейса list.li

Расширенное представление данных 735

Список модифицируют только функции InitializeList Addltem и EmptyTheList - фото 544

Список модифицируют только функции InitializeList() , Addltem() и EmptyTheList, поэтому формально только они требуют аргумента типа указателя. Однако если бы пользователю пришлось помнить о необходимости передачи аргумента List одним функциям и его адреса другим, то это могло бы приводить к путанице. Таким образом, для упрощения задачи пользователя во всех функциях используются аргументы типа указателей.

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

/* операция: применение функции к каждому элементу списка */ /* предусловия: plist указывает на инициализированный список */ /* pfun указывает на функцию, которая принимает */ /* аргумент Item и не имеет возвращаемого значения */ /* постусловия: функция, указанная pfun, выполняется один */ /* раз для каждого элемента в списке */ void Traverse (const List *plist, void (* pfun)(Item item) );

Аргумент pfun представляет собой указатель на функцию. В этом случае он является указателем на функцию, которая принимает значение item в качестве аргумента и не имеет возвращаемого значения. Возможно, вы помните из главы 14, что указатель на функцию можно передавать в виде аргумента другой функции, которая сможет вызывать эту указанную функцию. Так, например, pfun может указывать на функцию, отображающую элемент. Функция Traverse() будет применять эту функцию к каждому элементу списка, в результате отображая весь список.

Использование интерфейса

Мы заявляем, что этот интерфейс можно использовать для написания программы, не располагая никакими дополнительными деталями — например, ничего не зная о том, как реализованы функции интерфейса. Давайте прямо сейчас напишем новую версию программы вывода информации о фильмах еще до создания вспомогательных функций. Поскольку интерфейс определен в терминах типов List и Item, программа должна быть создана с применением этих же типов. Ниже показан один из возможных планов, представленный с помощью псевдокода:

736 глава 17

Создать переменную List.

Создать переменную Item.

Инициализировать список пустым содержимым.

Пока список не заполнен и есть входные данные:

Прочитать входные данные и поместить их в переменную Item.

Добавить элемент в конец списка.

Посетить каждый элемент списка и отобразить его.

Программа, приведенная в листинге 17.4, следует этому базовому плану; кроме того, в нее добавлен код для проверки ошибок. Взгляните, как в ней используется интерфейс, описанный в файле list.h (листинг 17.3). Обратите также внимание, что листинг содержит код функции showmovies(), которая соответствует прототипу, требуемому функцией Traverse(). Поэтому программа может передавать указатель showmovies в функцию Traverse(), чтобы та могла применять функцию showmovies() к каждому элементу списка. (Вспомните, что имя функции является указателем на эту функцию.)

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Стивен Прата читать все книги автора по порядку

Стивен Прата - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




Язык программирования C. Лекции и упражнения (6-е изд.) 2015 отзывы


Отзывы читателей о книге Язык программирования C. Лекции и упражнения (6-е изд.) 2015, автор: Стивен Прата. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x