Искусство программирования на Си (984073), страница 32
Текст из файла (страница 32)
е.ч ...,, З и е *, *",, р/нл рнмсс Ореаннэаеенн данные Щ) ! Часть В /* Число байтов, которое счативает фувкция (Чегз[], ве бопьве, чем размер буфера, включая завераавцвй нуль (хего Сека(сапог) и символ возов строки, есла оа прасутствует среди этвх байтов.
Поэтому мотет потребоваться считывать более длиааые строки. Для этого будем вызывать фувкцив [чесз() сааза и ивова — до тех пор, пока ве встретим свмвол возов строка. и/ ый11е[0 == Еггог ЬЬ ВОЬЬ [= (йесз(бийуег, в(геоу Ви((ег, (р)) ( веыь(пе = вггсйг(виууег, ' )п'); гу(веыбйпе )= ВОЬЬ) ( *Веыбйпе = '10'; ) /' зта фувкцвя вггсас использует фувкцаи А11ос51гАггау(), иввцвапвзврупцув строка пустымв стрехами". */ всгсап(( Актау)[иоы), Ви((ег); гу(веыЬгпе )= ВОЬЬ) ( /* Присутствовал символ вовой строки, так что следувцая строка является вовой и/ Вивв1осйв = 1 ууйоы) //регтые адетрантнне структуры динана ффффф Глава 11 ) е1ве [ еггог = ееа Р1ье Орем РА1ьеп; /* Вевозмокво открыть файл '/ ) ) е1яе ( Еггог = ЕВИ АЬЬОС РА1ЬЕО; /и Вевозмокво вмделить память и/ (У[вггог !а О) ( /* если первоиачальвое выдепеаие памяти закоачилось аварийао, указатель *Аггау будет иметь звачевве ВОЬЬ.
Фувкдвя РгееЯГгАггау() соответствупцвм образом обрабатывает эту возмоиаув ситуации. */ РгееясгАггау(*Актау, *вивеоыв); *Виввоыв = 0; ) е1ве ( Сопво1[аасевсгйггау(*Актау, *Вивиоыв) Птнтыг абгтрактннггтруътуры данных Глава 11 Орта нигаиин бинниг Часть Е Листинг 11.6. Лятимерный массив. саве ЕЕЕ АЬЬОС РА1ЬЕОг саве Ееа ВОЮЯ ЮОТ АООЕОг роев( 1пвп((зсзепе аеаогу.")1 Ьтеаез саве ЕВЯ Р1ЬЕ ОРЕЕ РА1ЬЕОг рг[псг("Соп)ап'С орса Ъв сот геаб(пе1п , агчв[1))1 Ьгеак; аесап11 г рггпсу("Опеповп еггог! Сог)е 1Е.1п , еггот); Ьгеае> Фгпс1пде <вса1гЬ.Ь> Сурепке( Ьпт Т; Т ****нА11осяваггау01Т(в1ге С а, в1ге С и, вгве С р, ваге С Ч, в1ге С г) ) ) е1ве ( роев( Р1еаве врессуу СЬе Сете Ше паве."] Т *****Атгау = МОЬЬ; тпг япссевв = 1; в12е С а, Ь с б Аттау аа11ос(а ° в[геос *Аггау); 1от(а = О; а < а; а++) гетптп О; ( Аггау[а) аа11ос(п и взгео( *Аггау[0)); сот(Ь = О; Ь < и; Ь» ) Обратите вниманис. что функция выделения памя- значгпсльная проблема, поскольку на практике редко ( Аттау[а[[Ь) ти для массива строк вызывается через функцию требуется применять многомсрныс массивы (фактичсс- 11, 1 *А, О О Орган чтение данных !)рен тые аде трантные трзь трры данны е Часть Н Глава 11 ( При компиляции этой программы я по.!учаю чсты- Массивы разнородных объектов Сразу же видно, что лля маленьких объектов наклалдопые д; ре сообщения об ошибках; все они предупрежлают о ныс расходы весьма значительны.
Вряд ли было бы цснсиспользуелеых переменных. Это цена, которую приТрсбование, чтобы все элементы массива имели один и Р " лссообразным такое решение, если бы большинство д = гапд() / ((допЫе)вхвв влх + !.в)! тот же тип, может показаться ~лишком ограничиваю- ходится платить за сохранность типов. Все объекты в Р объектов были очень маленьким~. шим. Было бы очень хорошо. если бы можно было храгегпгп (гпс)й! массиве должны быть одного и того же типа. Посколь- Обратите также внимание на то, что, поскольку мы к) требовалось создать прототипы полностью для всех нить в одном массиве объекть! разных видов, не правда отказались от проверки типов в инкапсулированной зпс до )егг(гпг х, )пе у) * * функций, пришлось сделать так, чтобы все функции лиа Если бы можно было трактовать группу родствен- функции, большинство хороших компиляторов выдаст ( имели один и тот же тип.
Фактически каждой функции ных, но разных объектов как единое целое, сохраняя в при компиляции предупреждающие сообщения. К этим — *х; го же время способность работать с ними индивидуаль(за исключением я!ори), требуется только одно целое сообщениям нельзя относиться пренебрежительно. Как рггпе ("до(пя е ! и*); но в соотвествии с их типами, то ~акая возможность геспгп Вапдов(5); число.
Но первым двум требуется, чтобы это было х, а указывалось в предьшуших разделах, есть способы, по) двум другим — чтобы это было у. Функции в!орО треобеспечила бы огромную гибкость. зволяюшис от них избавиться, но эти уловки устраняСпе до г)чье((пе х, )пе у) * * буются оба эти числа. Реализовать это вполне возможно, причем относиют только предупреждающие сообщения, а не саму ( Проблема различающихся списков аргументов обычтельно легко. При этом мы неизбежно рискуем сохранпроблему. Это похоже на попытку погасить пожар, постыл менов, но можно в какой-то степени уменьшить г)пе(( Оогп гу ЬГ!'хп")! но возникает в подобных ситуациях, когда требуется выключая пожарную сирену. Так что будем обращать этот риск, прил!еняя теги типов.
Сначала объявляется геспгп дапдов(5)! трактовать функции одинаковым образом. внимание на предупреждающие сооб!пения, убеждатьОдно из возможных решений, как уже бьшо сказасзр) ктура с зетом типа и указатель на этот объект. При р Л'! у" ( ся,чтоопасность,окоторой они предупреждают,на Епс Ва доып()пг х, гпг у) е ' * но, — добавить лополнительные аргументы так, чтобы необхолимости можно также сохранить в этой структуре это! Раз отсутствует и осторожно продвигаться палыче. все функции были одного типа.
Другой способ заклюуказатель на функцию, что позволит вкусить все преф. У Р вЂ” Чтобы гарантировать, что мы нс получим повторяеу лести инкапсуляшзи (листинг ) ).8). чаезся в том, чтобы отказаться от сохранности типов и юшисся типы, будем использовать для татов перечис- Оргон <с>анан донные Просты адстрантные струит>ры данные Глава 11 Часть В ( Ьач[1гев].гав = Тач; Ьач[1гев].оЬ) = Авдеева< Ьач[1еев].(ппс = Рппсгзоп< ) гпс Оороо(РОО *(оо) ргзпе[( Ва [Вс])п", Рос->[по, Роо->дага); геепгп О; ) зпс ООВаг(ВАО *Ьаг) ( рг)пг(["Ва [11д)1п , Ьаг->Ьаг, Ьаг->дага)Г геепгп О; ) зпе ОоВаг(ВАЕ *Ьаг) ( рг[пс(("Вв [ВР, В[][п*, Ьаг->Ьав, Ьаг->дага а, Ьаг->даеа Ь) гегпгп ОЗ зпе вази(то]В) ( РОО [а = ('а', 1'в ЕЬе 1<гас (оо ); Конечно, эти тсгн нс обеспечивают такую сохранность типов, как, например, шаблон языка С+-ь.
Ни олин компилятор не сообшит, что вы использовали в стр) ктурс данных ненраниньный тег. (С другой стороны, шаблоны языка С+<- для каждого отдельного типа (объекта) создают новый комплект объектного кола, и некоторыс считают это неэкономным.) В настояшсй главе булсм твердо придерживаться указателей на неизвестные типы (обьсктов), а ответственность за правильность использования зилов возложим на плечи пользователя-программиста.
Так, вообц<е-то, и должно быть. Одни думают, что вопрос сохранности типов является решаюшим, другие полагают, что это смирительная рубашка, а третьи считают, что сохранность типов должна быть своего рола дорожным указателем, а не тюрел<ной камерой. Хорошая библиотека обслужила бы запросы всех этих внлов пользователей-программно<он.
Я большой поклонник спецификатора (уреде[. Многие С-программисты думают, что специфи кагор (уреде[— ной абстракцией, которая обеспечивается в стандартной библиотеке языка С. Я не говорю, что мы должны быть слепымя в оп<ошении гого, <то происходит внутри библиотек. Но не нужно фокусировать внимание на том, как они работаю<, каждый раз при их использовании. Чем чище интерфейс, тем лучше. Ключевое слово (ура<]е(помогает хранить низкоуровневые детали интерфейса библиотеки в гаком месте, откуда их можно при необходимости извлечь, но в месте, которое можно и проигнорировать.
Конечно, с агой идеей можно зайти слишком далеко и, я конце ко<шов, прийти к языку С++. Тем не менее, разумный уровень абстракции может помочь сконцентрироваться на важном, поверить в то, что наши библиотеки работаюг правильно и заняться собственно своей работой — писать приложения, в которых используются эти библиотеки. В оставшейся части этой главы будут рассматриваться классические структуры данных.
Чтобы сделать зна- Орготтоцнн слсннын Щ$ ЧастЫ! Простые олгтронтные гтретн» ры данные 1 [хпс1пде <всд[е.ь> Гуреде( асгпсг гтЕМ < сЬаг т[01е[301; сЬаг Апсьог[301; 1пг Мехе» ттвм[ Листинг 11.9. Односвязный список на основе массива. [пе ваза(чпгд) ( гтЕМ Ьтве[1 ( ("ОИ1Х Оп1еаяЬед , "Впгх апд Нагчась", 2), ("А19пг(еьвв (п С*, Бедвеялсх', 9», ("Вп(1дег Оп1еавьед , *Са1чегс*, 10), <"С++ Оп)еавьед., "Ьзьегсу", 12), ("0[пах Оп1еааьед , вппалп апд Рагкег", В), <"теась топгве)т всв , *везвдегрь", 1), ( овса вггпсгпгев ь А19пг[гьвв , ъа(оге", 3), ( ООБ Ргевгаввега Ве(егепсе", Оегевапп Ь ЗаЬпвпп Ответ на послелнни вопрос уже известен.
При рассмотрении массивов люжно было убедиться в том, насколько легко встроить в структуру указатель, который может указывать на любой объект. В результате можно рашелить поняысе списка и понятие данных приложения и рассматривать их по отлельности. Тогда станопится возможным и лаже желательным написать комплект библиотечных (под)программ лля управления связанным списком, состоящим из... ничего! Ответ на первый вопрос очень прост. Хотя структура данных не может солсржать экземпляр самой себя (чем бы это все закончилосьу), она может содержать указатель на экземпляр самой себя. Если используется этот указатель, чтобы указывазь на следуюьций элемент в списке, можно быстро и просто создавать списки, а также добавлять новые элементы в любое место списка, в том числе и в начало.
Потребуешься "сигнальное" значение для обозначения конца списка, и значение [л[Т)ЕЕ подходиз. лля этои цели превосходно. Рис. 11.2 быть весьма осторожным при считывании информации с внешнепз запоминающего устройсз на назад в оперативн> ю память, так как мы бы считывази указатели, солержашие неверную информацию, которую пришлось бы аккуратно исправлять. Не слелует делать жизнь такой зап>таиной. Чтобы припать списку, насколько это возможно, общий характер, нс будем полагать, что в списке хранятся объекты одного и того же типа.
Поэтому будем применять поле тета. Кроме того, можез быть полезно сохранять в структуре размер элемента, на который >казывает указатель (Эта информация может потребоваться приложению. а может и нет. Но пусть список будез более гибким.) Полный исхолпыц код для листинга 11.10 можно найти на нашем СВ-КОМ в файлах хНьа(.Ь и аН[а(.с: тестовый драйвер храни~ся в файле зй(а[шп.с. Прежде всего требуется подходящая структура лани ых. Глава Н Органа«антс данны« Прасткк абстрактные стр> кн~>ры данных Часть й наине — если освобождается память, не вылеленная ) Отметим тот приятный факт, что, несмотря на все 06НОВЛВНИВ ЭЛВМВНТВ СПИСКИ ранее одним из этих способов, то во время выполнения свя~анные с этой функцией проблемы, она короткая, геепгп Веяп11> Иногда требуется модифициповать данные, хоанящис- реачизация имеет полную свободу действий, включая, так лак улалось повторно использовать код ф>нкции а не исключая, освобожлсние львов из клеток в зоопар- Я АддО.