М И Н И СТ Е РСТ В О О БРА ЗО В А Н И Я РО ССИ Й СК О Й Ф Е Д Е РА Ц И И В О РО Н Е Ж СК И Й ГО СУ Д А РСТ В Е Н Н Ы Й У...
7 downloads
185 Views
460KB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
М И Н И СТ Е РСТ В О О БРА ЗО В А Н И Я РО ССИ Й СК О Й Ф Е Д Е РА Ц И И В О РО Н Е Ж СК И Й ГО СУ Д А РСТ В Е Н Н Ы Й У Н И В Е РСИ Т Е Т
Ф акультетп рикладной математикиимеханики
К афедравычислительной математики
Я З Ы К И ПРО Г РА М М И РО В А Н И Я Д Л Я Ч И С Л Е Н Н Ы Х М Е ТО Д О В М ет одические указания к спецкурсу Ч аст ь 1 для ст удент ов 4 курса д/о и м агист ров ф акульт ет а ПМ М
С оста вите л и: Гл уш а кова Т.Н . Е сипе нко Д .Г. Ш а ш кин А.И. Экса ре вска яМ .Е . В ороне ж 2001
2 В В ЕД ЕН И Е В п редлагаемом сп ец курсе вы освоите современные технолог ии создания п рог раммных п родуктов, вклю чая как основныеконц еп ц ии, так и конкретные инструменты, необходимые для нап исания п рог рамм реализац иитех илииных численных методов. В сп ец курсе изучаю тся наиболее расп ространенные всовременной мировой индустрииразработкип рог рамм языкиC, C++ иJava, объектноориентированное п рог раммирование, клиент-серверные технолог ии баз данных наоснове языказап росовSQL. Н ачинается сп ец курс с изучения языкаС. Я зык С является универсальным языком п рог раммирования, реализац ии которог о имею тся п рактически на лю бой ап п аратной п латформе. Среди языков высоког о уровня, он наиболее п риближ ен к архитектурным особенностям комп ью тера, что п озволяет п исать нанем наиболее эффективные п рог раммы. В месте с тем он содерж итдостаточно мощ ные конструкц ии языка высоког о уровня. Э ти факты сделали ег о языком п рог раммирования номер один для системног о п рог раммирования. К рометог о, развитость стандартных библиотек п озволяетсделать больш ое количество кода, нап исанног о наС п ереносимым меж ду п рог раммными ап п аратнымип латформами. Я зык С очень удобен для всевозмож ных математических расчетов. О днако он сохраняетсвою актуальность икак язык для п рог раммирования задач друг ог о рода. Н аязыке С нап исаны п рактически все современные оп ерац ионные системы, вклю чая разнообразные варианты Unix и Windows, мног ие среды разработки, системы уп равления базамиданных, офисныеп акеты ит.д. В данном п особииоп исываю тся конструкц ии, входящ ие вязык C, и некоторые рекомендац ии п о их исп ользованию . Стандартная библиотека функц ий (втом числеоп ерац ииввода-вывода) нерассматривается, так как неп осредственно вязык онаневходит. Зная основныеконструкц ииязыка, стандартную библиотеку освоить достаточно лег ко, учитывая больш ое количество сп равочных материалов, вклю чая автоматизированные
3 состав всех современных сред
сп равочные системы, входящ ие в разработки. О тдельный п араграф п освящ ен особенностям исп ользования массивов, указателей и динамической п амяти в языке C, так как этот воп рос обычно оказывается одним из самых слож ных для начинаю щ их п рог раммистовнаC. § 1. ЗН А К О М С Т В О С Я ЗЫ К О М С 1.1. Базовы е элем ент ы язы ка Програм м а — это совокуп ность п редп исаний для комп ью тера о вып олнении конкретных действий п о обработке информац ии, обесп ечиваю щ ая п олучениенуж ног о для п ользователя результата. П од термином "п рог рамма" часто п одразумеваю т: ее исходный текст, код, нап исанный п ользователем; загрузочный модуль, хранимый во внеш ней п амяти; системную п рог рамму, нап ример комп илятор, редактор связей и т.д. Д алее, г оворя "п рог рамма", мы будем иметь в виду код, нап исанный наязыке С, который формируется п утем комп озиц ииш ести базовых элементовязыка: констант, п еременных, оп ерац ий, разделителей, клю чевых слов, меток. В п рог рамме наС доп ускаю тся комментарии, но они не являю тся частью языка. К онстанты ип еременныесоставляю тда нные языкаС. 1.1.1 К онста нты К онст ант а — явное п редставление значения. П ри вып олнении п рог раммы значениеконстанты никог данеменяется. К онстанты вязыкеС мог ут быть оп ределенных тип ов: ц елые, длинные ц елые, символьные, с п лаваю щ ей точкой, строковые, п еречислимые. О днако, вязыкеС нетсп особаявно задать, что п еременная каког о-то тип а будет константой. В тех местах г де необходимо исп ользовать константы в истинном п онимании этог о слова, п ользую тся макроп одстановкой, нап ример: #define PI 3.1415
4 П осле таког о оп ределения п еред комп иляц ией в тексте п рог раммы PI будет заменено насимволы 3.1415. Н о и такой сп особ не является настоящ им исп ользованием константы, так как в настоящ ие константы залож енаинформац ия об их тип е, как ивобычной п еременной. Здесь ж е 3.1415 это п росто набор символов. В место них мы мог ли бы нап исать иabc, тог дап риисп ользованиизап исиPi мог лабы возникнуть ош ибка. Н ап ример, если вп рог рамме есть п еременная abc, то вданном случаеп олучится, что вместо PI мы обращ аемся к этой п еременной. Ц елы е конст ант ы мог ут быть зап исаны в десятичной, восьмеричной илиш естнадц атеричной системесчисления. Ц елочисленные константы в десятичной системе счисления зап исываю тся обычным сп особом, нап ример: 0, -15356, 25. И сп ользование восьмеричных и ш естнадц атеричных систем счисления удобно исп ользовать, ког даваж но соответствие конкретног о значения двоичным разрядам. Д ля зап иси восьмеричной константы необходимо начать с ц ифры 0, п осле которой следую твосьмеричные ц ифры (от0 до 7). Ш естнадц атеричныеконстанты начинаю тся с символов0x, п осле которых следую т ш естнадц атеричные ц ифры (0-9, a-f). Д линны е целы е конст ант ы явно оп ределяю тся буквой L, стоящ ей п ослеконстанты. С им вольны е конст ант ы п редставляю т единственный символ таблиц ы кодовASCII, заклю ченный вап острофы. Символьная константа мож ет исп ользоваться как ц елая константа, п ричем ее значением является интерп ретац ия в виде ц елог о значения внутреннег о п редставления символьной константы. Н е которые символ ы обозна ча ются с помощ ью упра вл яю щ е й посл е дова те л ьности, ка к пока за но ниж е : Т аблиц а1 С имвол
О бозначе ние
Н овая строка
‘\n’
Т абуляц ия
‘\t’
В озвратнасимвол
‘\b’
В озвраткаретки
‘\r’
5 П еревод формата А п остроф
‘\f’ ‘\'’
К авычки ‘\”’ О братная наклонная ‘\\’ К онст ант ы с плаваю щ ей т очкой всег дап редставляю тся числамис п лаваю щ ей точкой двойной точности, т.е. как имею щ ие тип double, и состоят из следую щ их частей: ц елой части - п оследовательности ц ифр; десятичной точки; дробной части - п оследовательности ц ифр; символа эксп оненты e; эксп оненты ввидец елой константы (мож етбыть со знаком). К онстанты с п лаваю щ ей точкой п редставляю тся только в десятичной системесчисления. С им вольны е ст роки п редставляю тся п оследовательностью символов, заклю ченной вдвойные кавычки, вмаш инном п редставлении оназаверш ается символом 0. П о этому символу оп ределяю тконец строки. Строки в языке С рассматриваю тся как символьные массивы. О ни ог раничиваю тся с п омощ ью символа ‘\0’. В строковые константы комп илятор автоматическидобавляет‘\0’. О днако п рог раммиствп роц ессе создания строки как массива символов долж ен п ри выделении п амяти п редусматривать доп олнительный байт на символ ‘\0’, а п ри иниц иализац иистрокикак массивасимволовп оследним следуетвклю чить вчисло иниц иализирую щ их элементовсимвол ‘\0’. Ч тобы п оместить символ кавычки(") ег о нуж но вклю чить встроку с п омощ ью уп равляю щ ей п оследовательности из таблиц ы 1. Слиш ком длинная строкамож етбыть п родолж енанаследую щ ую линию с п омощ ью символа\. Н ап ример: “ очень больш ая п ребольш ая длинная п редлинная \ длинная п редлинная строка” Строкимог утсодерж ать такж енеп ечатаемыесимволы из таблиц ы 1, такие, как, нап ример, символ п ереходанановую строку ит.п . Перечислим ы е конст ант ы трактую тся как ц елыеконстанты. 1.1.2 Пе ре ме нные Перем енная - это данное, которое мож ет иметь только одно значение в каж дый конкретный момент времени. В п роц ессе работы
6 п рог раммы значение п еременной мож ет меняться. Л ю бую п еременную п еред ее исп ользованием вп рог рамме нуж но оп исать, п ри этом указываю тся ее тип , класс п амяти, к которому она п ринадлеж ит, идентификатор, иниц иализатор. И нициализацией называется п роц есс п рисвоения п еременной п ервог о значения. П еременную мож но п роиниц иализировать: п ри ее оп исании; с п омощ ью функц ий ввода; исп ользуя оп ерац ию п рисваивания; п ростой макроп одстановкой. И дент иф икат ор – п оследовательность символов, закреп ляемая за п еременными, метками, функц иямиитип амиданных вкачественазвания. И дентификатор состоит из п роп исных илистрочных букв, ц ифр, символа п одчеркивания ( _ ), п ричем обязательно он долж ен начинаться с буквы или символап одчеркивания. В некоторых реализац иях идентификаторы, начинаю щ иеся с символап одчеркивания, резервирую тся для системных п рог рамм, п оэтому во избеж ание возмож ных ош ибок п ри именовании п рог раммных объектов следует избег ать таких идентификаторов. В се комп иляторы различаю тп роп исныеистрочныебуквы видентификаторах. Х отя вязыке нет явных ог раничений надлину идентификаторов, мног ие комп иляторы рассматриваю т только п ервые восемь символов. И дентификаторы мог ут облег чить или затруднить документирование п рог рамм. Х орош о выбранныеидентификаторы сп особствую тп ониманию п рог раммы, тог да как слиш ком п охож ие или не несущ ие смысловой нагрузкизатрудняю тег о. 1.1.3 О пе ра ц ии О перации информирую т комп ью тер, какие действия и в каком п орядке нуж но вып олнить. Н иж е п риводится п олный п еречень оп ерац ий языкаС: Т аблиц а2 () []
В ызовфункц ии И ндексац ия
. -> !
Д оступ к элементу структуры (объединения) Д оступ к элементу структуры (объединения) п о указателю Л ог ическоеотриц ание
7 отриц ание
~ ++ -& * (т ип) sizeof * / % + << >> < <= > >= == != & ^ | && ||
П обитовое И зменениезнака У величениенаединиц у У меньш ениенаединиц у П олучениеадреса(унарная) Д оступ п о указателю (разименование) П реобразованиетип а О п ределениеразмеравбайтах У множ ение Д еление Д елениеп о модулю Слож ение В ычитание Сдвиг влево Сдвиг вп раво М еньш е М еньш еилиравно Больш е Больш еилиравно Равно He равно П обитовая оп ерац ия И П обитовая оп ерац ия исклю чаю щ ееИ Л И П обитовая оп ерац ия И Л И Л ог ическая оп ерац ия И Л ог ическая оп ерац ия И Л И
?: =
У словная оп ерац ия П рисваивание
*=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= ,
Составныеоп ерац иип рисваивания О п ерац ия зап ятая
8 1.1.4 Р а зде л ите л и Разделит ели служ ат для выделения составляю щ их языка. В качестве разделителей в С исп ользую тся: фиг урные скобки { } - для выделения телафункц ииилиблока, элементовструктур илиобъединений; круг лые скобки ( ) - для г руп п ировкиэлементовввыраж ениях; двойные кавычки“ ” - для сп ец ификац иисимвольной строки; ап острофы ‘‘- для сп ец ификац ии символа; зап ятая - , - для разделения элементов. Д ля обозначения началаи конц акомментариевп рименяю тся соответственно п ары символов/* и */. Т очкас зап ятой ; - мож ет исп ользоваться: для ог раничения п ростог о оп ератора; внутри комментария, г де она будет рассматриваться как обычный символ; внутри оп ератора for; внутри ап острофовилидвойных кавычек. П равильное исп ользование круг лых скобок сущ ественно п овыш ает удобочитаемость п рог раммы. Т ак как п оследовательность вып олнения оп ерац ий оп ределяется их п риоритетами, то п ри нап исании п рог рамм мож но свести к минимуму количество скобок. О днако п ри этом в некоторых случаях затрудняется чтение п рог раммы. П оэтому в лю бой сомнительной ситуац ии рекомендуется во избеж ание ош ибок ставить в выраж ениях скобки. 1.1.5 К л юче вые сл ова Ряд идентификаторов являю тся зарезервированными. О ни называю тся кл юче выми сл ова ми. П риведем сп исок клю чевых словязыкаС иих русских эквивалентов. Т аблиц а3 Типы данны х int char float double long short unsigned enum
- ц елый; - символьный; - п лаваю щ ий; - двойная точность; - длинные; - короткие; - беззнаковые; - п еречислимый;
К лассы пам ят и auto extern register static
- автоматический; - внеш ний; - рег истровый; -статический.
9 struct union sizeof typedef void
- структура; - объединение; - размер; - оп ределить тип ; - тип функц ии, невозвращ аю щ ей значения. О перат оры
break - разрыв; for - для; case - вариант; goto - на; continue - п родолж ить; if - если; default - п рочий; return - возврат; do - п овторить; switch - п ереклю чатель; else - иначе; white - п ока. Заметим, что каж дое клю чевое слово долж но отделяться от текста п рог раммы одним илинесколькимип робелами. 1.1.6 М е тки М е тки исп ользую тся в языке С для идентификац ии оп ератора в п рог рамме, накоторый п ередаетуп равлениеоп ератор goto. М еткасостоит из идентификатора, п осле которог о следует двоеточие. О бластью оп ределения меткиявляется данная функц ия. Н ап ример: MET: printf ("\n К онец п рог раммы"); П ри уп отреблении оп ератора goto рекомендуется п ередавать уп равление наоп ератор п о ходу чтения п рог раммы. И г норирование этой рекомендац иизатрудняетчтениеиотладку. 1.1.7 К омме нта рии К омме нта рии начинаю тся с символов/* изаканчиваю тся символами */. К омментарии мож но п ереносить на следую щ ую строку п рог раммы. О ни не мог ут быть влож енными. П рог раммисту следует уделять значительное внимание стилю комментирования, так как комментарии п редставляю т собой сущ ественную часть документац ии п рог раммы. К омментарии долж ны п омог ать читать п рог рамму. Н еверный комментарий мож етввестивзаблуж дениеп риотладкеп рог раммы.
10 К омментарии, которые неадекватно отраж аю т текст п рог раммы, п орож даю т п роблему, состоящ ую в том, что на них бессознательно п олагаю тся и п оэтому не анализирую т п рог рамму критически. Ч тобы избеж ать этог о, рекомендуется зап исывать комментарий сп рава, а текст п рог раммы — слева, чтобы комментарии мог либыть закрыты вп роц ессеотладки. К омментарии долж ны сообщ ать новую информац ию и нести оп ределенную смысловую нагрузку, анеп ерефразировать оп ерац ииязыка. Ч тобы это было действительно так, следует п исать комментарии п араллельно с создаваемой п рог раммой, ане вставлять комментарии в г отовую . 1.2. Ф ункции и прог рам м а 1.2.1 О сновные све де ния М ног ие п рог раммы слиш ком г ромоздки, чтобы их мож но было восп ринимать ц еликом. И х следует разделять на небольш ие части – ф ункц ии. Э то единственный сп особ п овысить надеж ность п рог рамм, а такж еп равильно п рочитать ип онять их. Ф ункц ия в языке С является модулем. Ф ункц ия мож ет транслироваться отдельно, а п осле занесения в библиотеку она мож ет исп ользоваться вдруг их функц иях. Ф ункц иивС состоят из двух частей: заголовкафункц ииителафункц ии. В общ ем видеш аблон функц иивыг лядиттак: тип имя(описа ние па ра ме тров) { те л о ф ункц ии } П од (описа ние па ра ме тров) п одразумевается следую щ ее: тип1имя1[,тип2 имя2,… ,тип n имяn] или void – без п араметров. Заметим, что квадратные скобкиобозначаю т необязательную часть. Ф ункц ия мож ет иметь от 1 до n п араметров. Я зык C п озволяет такж е исп ользовать функц ии с п еременным числом п араметров. О днако, такие
11 функц ии п рог раммисту п риходится п исать очень редко. П оэтому здесь мы их нерассматриваем. З аг оловок ф ункции п редставляет собой идентификатор функц ии, за которым в круг лых скобках мож ет следовать сп исок п араметров, а за круг лыми скобками – оп исания каж дог о элементаиз сп искап араметров. И дентификатор функц ии формируется п о п равилам образования идентификаторов в языке С. Рекомендуется давать функц иям имена, которыераскрывалибы назначениефункц ии. Сп исок п араметров, атакж е их оп исания мог ут отсутствовать, но п устые круг лые скобкип осле имени функц ииоп ускать нельзя. Тело ф ункции – г руп п а оп ераторов, реш аю щ ая оп ределенную задачу. Т ело функц ии заклю чается в фиг урные скобки{}. Рекомендуется размещ ать открываю щ ую и закрываю щ ую фиг урные скобки в разных строчках с одной итой ж еп озиц ии. Т ело функц иисостоитиз двух частей: оп исаниелокальных п еременных; оп ераторы. К ак только заканчивается п ервая часть, начинается вторая. Н икаких сп ец иальных разделителей меж ду ниминет. П рог рамманаязыкеС мож етсостоять из нескольких функц ий, среди которых обязательно долж на быть функц ия с именем main ( ). Э та функц ия обычно п ервой п олучаетуп равление. Ч тобы быливып олнены все остальные функц ии п рог раммы, к ним долж ны быть обращ ения из функц ии main( ) или из друг их функц ий п рог раммы, которые в свою очередь такж евызываю тся из функц ииmain( ) . П ринап исаниип рог рамм наС рег истр вкотором набираю тся имена п еременных, функц ий имеетзначение. И если, нап ример, вфункц ииMain() сделать хотя бы одну букву заглавной, то это будетуж еимя совсем друг ой функц ии. П оэтому п ри нап исании п рог рамм на С необходимо точно следить заточным совп адением имен. К од функц иирасп олагается водном илинескольких файлах. Болееменее круп ная п рог раммавсег даимеет несколько файловс исходными текстами, вкоторыеп омещ аю тфункц ии, связанныекакой-то общ ей идеей. В С влож енных функц ий не бывает. Ф ункц ии мог ут расп олагаться г де
12 уг одно, не зависимо друг от друг а. О днако, для удобстваих формирую т п о разным файлам. И обычно водном файле расп олагаю т функц ии, имею щ иечто-то общ ее. Е слифункц ия, вызываемая внекотором файле, оп ределенавдруг ом файле, то она долж на быть оп исана п редварительно. Т акое п редварительное оп исание называется прот от ипом ф ункции. В общ ем видеп рототип функц иизап исывается следую щ им образом: тип имя(описа ние па ра ме тров); П рототип требуется такж е, если одна функц ия вызывает друг ую , которая ещ е не оп ределена. Заметим, что вязыке С отсутствие п рототип а не вызывает ош ибки п ри комп иляц ии п рог раммы. К омп илятор лиш ь выдастп редуп реж дение, но п рог раммабудетскомп илирована. О днако п ри этом онамож ет не всег дап равильно работать, п оэтому п рототип ы лучш е всег о всег даисп ользовать. Заметим, что лю бая п рог рамма не мож ет содерж ать тело всех п олезных функц ий, которые онаисп ользует. М ног ие функц иидостаточно слож ны инуж ны во мног их друг их п рог раммах. П оэтому такие функц ии выделяю т в библиотеки. Э ти библиотеки мож ет нап исать и сам п рог раммист. К роме тог о у языка С имеется больш ая стандартная библиотека, содерж ащ ая множ ество п олезных функц ий. Д ля тог о, чтобы исп ользовать библиотечные функц ии необходимо оп исание п рототип ов этих функц ий, атакж енекоторых сп ец иальных тип овданных, которыеэти функц ииисп ользую т. Т ак как этип рототип ы иоп исание тип овнуж ны во мног их файлах, их сами выделяю т втот или иной исходный файл п ри п омощ идирективы п реп роц ессора#include. В ней имя файлауказывается в уг ловых скобках #include <имяф а йл а > еслифайл берется из стандартных библиотек ивкавычках “ ” #include “ имяф а йл а ” еслифайл оп ределен п ользователем. Э ти файлы с оп исаниями называю т за гол овочными и им даю т расш ирение h. Т аким образом, п рилож ение на языке С обычно имеет несколько файловс расш ирением с, вкоторых находятся исходныетексты функц ий и несколько файлов с расш ирением h, в которых находятся п рототип ы нуж ных функц ий инекоторыедруг иеоп исания.
13 1.2.2 В ызов ф ункц ии и опе ра тор return. В ызовфункц ии имеетвид: имя(список па ра ме тров) Здесь сп исок п араметровэто ноль, одно илинесколько выраж ений, разделенных зап ятыми. В случае, еслип араметровнет, сп исок п араметров п уст, круг лые скобки () обязательны. П араметры п ередаю тся вфункц ию п о п орядку их следования. П ри вызове функц ии комп илятор п роверяет соответствие п редаваемых п араметров п араметрам, которые оп исаны в п рототип е функц ии. С доп ускает вызовфункц иибез п рототип а, но будет выдано п редуп реж дение ип рог раммамож ет работать не п равильно, если п ереданы нетеп араметры. Результатом вызова функц ии является значение, которое она возвращ аетоп ератором return. О п ератор return исп ользуется для возврата значений из функц иииимеетследую щ ий вид: return (выра ж е ние ); В ыраж ениемож етбыть без круг лых скобок, амож ет, ивообщ е, быть оп ущ ено, в функц ии тип а void. Е сли функц ия имеет тип void, то этот результатисп ользовать вболееслож ном выраж ениинельзя. 1.3. С реды разраб от ки К ак уж е было сказано во введении, средаразработки для языкаC есть влю бой современной оп ерац ионной системе, что делает этот язык одним из самых расп ространенных. Средаразработкидля языкаC вклю чаетследую щ иеэлементы: редактор исходных текстов(файлов) п рог раммы; комп илятор с п реп роц ессором, п реобразую щ ие исходные тексты в объектные файлы (объектный файл – это набор маш инных команд, реализую щ ий код функц ий, оп исанных висходном файле, п ричем ссылки на внеш ние функц ии и п еременные остаю тся в объектном файле неоп ределенными); библиотекифункц ий; редактор связей (комп оновщ ик), собираю щ ий из объектных файлов и библиотек исп олняемую п рог рамму или друг ую библиотеку (наэтап е комп оновкиразреш аю тся всессылкинавнеш ниефункц ииип еременные);
14 отладчик исп олняемых п рог рамм. Средаразработкимож етсостоять из отдельных п рог рамм (редактор, комп илятор, комп оновщ ик, отладчик), зап ускаемых п о отдельности, или мож ет быть инте грирова нной, ког да все модули лег ко и удобно зап ускаю тся из-п од одной п рог раммы. И нтег рированная средаудобнее в исп ользовании. В системах Windows сущ ествую т следую щ ие наиболее расп ространенныеинтег рированныесреды для языкаC: Microsoft Visual C++; Borland C++ Builder; атакж енеинтег рированная средаWatcom C/C++. В системах Unix наиболеерасп ространенанеинтег рированная среда наоснове комп илятораGNU C/C++, отладчикаGDB ип рог раммы make. Сущ ествую т отдельные п рог раммы, интег рирую щ ие эти средства, нап римерK Developer. В системеMS-DOS наиболеерасп ространенаинтег рированная среда Borland C++. В се эти среды п оддерж иваю т как язык C, так и объектноориентированный язык C++. М еж ду тем, это совсем разныеязыки(п росто язык C++ исп ользовал основные базовые элементы из языкаC, так что зная язык C нанег о п ерейтидостаточно лег ко). Здесь мы рассматриваем только язык C. Сущ ествует мног о разных оп ерац ионных систем, всоставкоторых входят комп иляторы C, не оп исанные здесь. Н о эти системы не так расп ространены. В се п еречисленные среды разработки отличаю тся п о составу библиотек, мог ут вводить свои расш ирения языка и т.д. О днако все основы, рассматриваемые вданном п особии, верны для лю бой из этих сред. 1.4. С т андарт ная б иб лиот ека Т акие оп ерац ии, как ввод-вывод, работа с п амятью , файлами, строкамиит.д. невходятвязык C, т.е. онинерасп ознаю тся комп илятором языка C. В место этог о они реализованы в виде функц ий стандартной
15 которым
библиотеки, обращ ение к осущ ествляется на этап екомп оновкип рог раммы. И склю чениеп еречисленных оп ерац ий из языкап озволило сократить количество клю чевых слов языка и уп ростить комп илятор. Н ап ример, оп ерац ииввода-выводас точкизрения комп илятора– обычные функц ии, которыеоп ределены невтекстеп рог раммы, аг де-то извне(вбиблиотеке). Н аличиеста нда ртной библиотекитребуетреализац иивсех еефункц ий во всех средах разработки для языкаC. В результате п рог раммист мож ет сп окойно п ользоваться этимифункц иямивлю бой оп ерац ионной системе, как еслибы это быливстроенныеоп ераторы языка. § 2. Т И ПЫ Д А Н Н Ы Х И ПЕ РЕ М Е Н Н Ы Е 2.1. О сновны е сведения Тип данны х характеризует: множ ество значений, которые мож ет п ринимать объект; множ ество оп ерац ий, которые мог ут п рименяться к объекту; размер п амяти, занимаемой объектом. О сновными элементами данных (объектами) языкаявляю тся п еременныеиконстанты. Перем енная - это реальный объект, который исп ользуется для хранения значения оп ределенног о, связанног о с ним тип а. Зап оминание новог о значения вп еременной уничтож аетстароезначение, котороедо сих п ор хранилось вп еременной. Т аким образом, п еременная мож ет менять своезначениевп роц ессевып олнения п рог раммы. К онст ант а — явное п редставление значения. К онстантане мож ет менять своезначение. В С различаю т две катег ориитип овданных: ба зовые (символьный, ц елый, п лаваю щ ий, которые такж е называю т арифметическими, п еречислимый) и производные (указатели, массивы, структуры, объединения, функц ии). 2.2. Базовы е т ипы данны х . П риведем сп исок различных тип ов данных, размер (в битах) и диап азон п ринимаемых значений, нап ример, для 32-разрадног о п роц ессора. Т ип
Размер, бит
Д иап азон п ринимаемых значений
16 char
8
-128… 127
enum
16
-32768… 32767
short
16
-32768… 32767
unsigned int
16
0… 65535
int
16
-32768… 32767
long
32
-2147483648… 2147483647
float
32
-3.4e-38… 3.4e+38
double
64
-1.7e-308… 1.7e+308
2.2.1 Ц е л ый тип Ц елые тип ы данных п озволяю т хранить ц елые числавразличных диап азонах. Н аиболее часто исп ользуемым ц елым тип ом является int. О днако насамом деле int не является самостоятельным тип ом, аявляется синонимом для одног о из тип овshort илиlong. Э титип ы неп осредственно связаны с архитектурой конкретной маш ины. short – обозначаеткороткоец елое, аlong – длинное, всоответствиис маш инным словом комп ью тера. Размер маш инног о словазависит от разрядностип роц ессора. Е сли п роц ессор32-разрядный, то размер маш инног о словаравен 32 битам или4 байтам. В этом случае 4 байтовому маш инному слову соответствует тип long, а тип short соответствует 2 байтовому маш инному слову. Соответственно диап азон значений, которые мог ут храниться в этих числах зависит от количестваразрядовисоставляет от 0 до 2 n − 1 , г де nколичество разрядов. Э та формула п рименяется только для п олож ительных чисел. Е сли п риходится хранить отриц ательные и п олож ительныечисла, то максимальноец елоечисло п о модулю вдвараза меньш е, чем 2 n − 1 . Н азвания тип а short и long обозначаю т числа в которые входит отриц ательная часть. Е сли отриц ательные числа не нуж ны, то зап исывается unsigned short илиunsigned long. Т ип int является синонимом тог о из двух тип ов(short илиlong), который соответствует оп тимальному размеру маш инног о словакомп ью тера. Д ля обозначения беззнаковог о int п иш утunsigned int илип росто unsigned.
17 Ц елочисленные константы зап исываю тся в двоичной, восьмеричной иш естнадц атеричной системах счисления. П одробнее они оп исывались вп .1.1.1. А рифметическиеоп ерац иис ц елымичислами: + , - , * , / , %. Е сли п ри вып олнении арифметической оп ерац ии с двумя ц елыми числами одно из них короткое, адруг ое – длинное, то результат будет длинным ц елым (long). Т о ж е относится и к оп ерац ии п рисвоения, если п еременная слеваотзнакаравенстватип аlong. П ри п оп ытке вып олнения оп ерац ии с одним знаковым и одним беззнаковым числом (или п рисвоении знаковог о беззнаковому) комп илятор выдаетп редуп реж дение, так как результатмож етбыть нетем, какой ож идается. О днако комп илятору мож но дать инструкц ию о том, как трактовать число. Д ля этог о есть оп ерац ия приведения т ипа, которая имет вид: (имятипа ) выра ж е ние Здесь имя типа – это short, long и т.д. (мож ет быть лю бым тип ом языкаС). 2.2.2 С имвол ьный тип Т ип char обозначаетсимвол. Символьный тип характеризуетданные, п редставляю щ ие один символ кодаASCII изанимаю щ ие п амять объемом один байт. Т аким образом, значением данног о символьног о тип аявляется ц елое число, равное коду данног о символа в конкретной реализац ии. Следовательно, символы мог ут трактоваться как ц елые, и наоборот. Э то п озволяет хранить до 256 кодовсимволов(от 0 до 255, если трактовать char как беззнаковое ц елое). В некоторых комп ью терах символы рассматриваю тся как знаковые, от– 127 до 128. Ч тобы рассматривать char как беззнаковоеп еред ним ставится unsigned. Символьная константа дифференц ируется от соответствую щ ег о числовог о значения п утем заклю чения символьной константы в ап острофы. Значением символьной константы является ц елое число, равное коду данног о символавтаблиц е кодовASCII. Н ап ример, значение символа‘0’ вкоде ASCII равно 48. И меется символьная константадля действительног о нулевог о числовог о значения. О накодируется ввиде‘\0’.
18 Сущ ествует ряд сп ец иальных символов, которые п редставляю тся ввиде уп равляю щ ей п оследовательности. У п равляю щ ие п оследовательности оп ределяю тся в языке С с п омощ ью обратной наклонной черты ‘\’, с которой начинается каж дая такая п оследовательность. Заобратной наклонной чертой следует один символ, или некоторый ог раниченный сп исок символов, или три ц ифры восьмеричног о числа. П еременные не мог ут исп ользоваться в уп равляю щ их п оследовательностях. Сп исок уп равляю щ их п оследовательностей п редставлен вп . 1.1.1. П еременные символьног о тип а долж ны быть оп ределены до их исп ользования с п омощ ью клю чевог о словаchar. Т ак как значением объектасимвольног о тип аявляется ц елое число, п редставляю щ ее код данног о символа в конкретной реализац ии, к символьным данным мож но п рименять все оп ерац ии, п редусмотренные в С. Н ап ример, выраж ение ‘b’+’%’-‘!’ вязыке С соверш енно законно. Э то выраж ение вычисляется вкоде ASCII иимеетзначениесимволаf, т.е. (98 + 37 - 33 = 102). Т акие символьные выраж ения встречаю тся редко, так как они не имею т смысла. Н о мож но п ривестип ример, ког давып олнение оп ерац ии слож ения с кодами символовимеет смысл и часто исп ользуется. К оды символовверхнег о и ниж нег о рег истровлатинског о алфавитавтаблиц е кодовASCII отличаю тся назначение 32. Н ап ример, символ ‘A’ имееткод 65, асимвол ‘а’ – код 97. Разниц амеж ду кодамиравна32. А так как все коды п оследую щ их символовувеличиваю тся наединиц у втаблиц еASCII, то, для тог о чтобы п олучить код алфавитног о символаниж нег о рег истра, нуж но п рибавить значение 32 к значению кода верхнег о рег истра, нап ример: char n_reg, v_reg; … … … n_reg=v reg+32;
19 2.2.3 Пл а ва ющ ий тип К онстанта с п лаваю щ ей точкой состоит из ма нтиссы и порядка . М антиссасодерж итц елую идробную части. Значениечислас п лаваю щ ей точкой п олучается умнож ением мантиссы на 10 в степ ени, задаваемой п орядком. Ц елая часть – это десятичная константа, дробная часть – точка, закоторой следуетдесятичная константа. Л ибо ц елая, либо дробная часть вмантиссе мож ет быть оп ущ ена. П орядок зап исывается буквой е , знаком п орядка и десятичной константой, п редставляю щ ей ег о значение. Знак п орядка мож ет быть оп ущ ен, и в этом случае п одразумевается знак «п лю с». В языке С имею тся два п лаваю щ их тип а: float (п лаваю щ ий нормальной точности) иdouble (п лаваю щ ий двойной точности). П еременные п лаваю щ ег о тип аоп ределяю тся с п омощ ью клю чевог о слова float или double, за которым через п робел следую т одно или несколько имен п еременных. В С п ри вып олнении оп ерац ий, а такж е п ри п ередаче значений арг ументовданныетип аfloat п реобразую тся к тип у double. К данным тип овfloat иdouble разреш ается п рименять всеоп ерац ии, п редусмотренныевязыке. 2.2.4 Пе ре числ имый тип П еречислимый тип п озволяет задать именованные ц елочисленные константы тип аint. П ричем п о умолчанию этиконстанты имею тзначения 0, 1, … иобычно ониисп ользую тся для обозначения различных вариантов чег о-либо. О бъявлениеп еречислимог о тип аимеетвид: enum имя{конста нта 1,… ,конста нта n}; Здесь конста нта i вп ростейш ем случае – это символическое имя. конста нта 1 п олучает значение 0, а каж дая п оследую щ ая – значение п редыдущ ей п лю с 1. О днако, конста нта i мож етиметь вид имя=зна че ние . В этом случае константа п олучает указанное значение (оно долж но быть больш е значений всех п редыдущ их констант). П оследую щ ие константы, как и раньш е, п олучаю тсвоизначения п утем увеличения на1, еслиониявно не заданы.
Д ля исп ользования тип а
20 enum исп ользуется следую щ ий
вид: enum имя Имя в enum мож но не указывать п ри оп исании только одной п еременной, еслиэтотenum больш ениг денеисп ользуется. 2.3. И нициализация перем енны х К ог давп рог рамме наязыке С создается п еременная, ее значение мож ет быть п роизвольным, в зависимости от тог о, что находилось в соответствую щ их ячейках п амятивмомент ее создания. П оскольку такое значение заранее п редуг адать невозмож но, ег о называю т «мусором». И сп ользование такой п еременной без п рисвоения ей явног о значения мож ет п ривести к неп редсказуемым результатам. П оэтому п еременные п еред их исп ользованием начтениедолж ны быть инициализированы , т.е. им необходимо п рисвоить начальное значение. Э то мож но сделать в оп ераторе п рисвоения, а мож но и п ри оп ределении п еременной. И ниц иализац ия п еременных обычных тип овне отличается от п ростог о п рисвоения изап исывается одним из следую щ их сп особов, нап ример, для ц елочисленной п еременной: 1. int i=0; 2. int i=0,j=0,k=0; 3. int i,j,k; int j=0; i=j=k=0; int k=0; Т акая ж еиниц иализац ия разреш енаидля структур, идля массивов. Д ля структур сп рава от знака равенства п еречисляю тся соответствую щ ие значения п олей п о п орядку и через зап ятую , заклю ченныевфиг урныескобки. Т .е. иниц иализац ия имеетвид: тип имя={зна че ние пол я1,… ,зна че ние пол яn}; П ричем, если само п оле является структурой, то для нег о задается такой ж е иниц иализатор. П ри иниц иализац ии структур в фиг урных скобках мож но указывать не все п оля. Т ог даоставш иеся п оля п олучат нулевыезначения. Э лементы массива, так ж е как п оля структур, п еречисляю тся через зап ятую и заклю чаю тся вфиг урные скобки. Е сли п еречислено меньш е элементов, оставш иеся обнуляю тся.
Более детально оп исанап риих рассмотрении.
21 иниц иализац ия всех п еременных
2.4. О пределение т ипа В языке С п редусмотрена возмож ность оп ределения имен тип ов данных. Л ю бому тип у данных с п омощ ью клю чевог о словаtypedef мож но п рисвоить имя иисп ользовать ег о далееп риоп ределениип еременных. П усть вп рог раммеимеется оп ределениеименитип а: typedef struct {double re, im ;} complex; Д алее имя complex мож ет быть исп ользовано п ри оп ределении п еременных. Н ап ример: complex chislol; г де chislol является структурной п еременной. Э та зап ись эквивалентнаследую щ ей: struct {double re, im ;} chislol; Рекомендуется выделять втекстеп рог раммы всеимена, созданныес п омощ ью typedef иdefine с п омощ ью п роп исных букв: typedef int VOID; #defineVOID int О п ределениеtypedef рекомендуется исп ользовать: 1) для улучш ения документирования п рог рамм, так как мож но вводить именатип ов, соответствую щ иеих содерж анию . 2) для п овыш ения мобильности п рог рамм. Н ап ример, мож но оп ределить собственный ц елый тип , который наразных маш инах мож ет быть заменен одним из п одходящ их тип ов: int, short, long илиunsigned. 2.5. К лассы пам ят и 2.5.1 О бл а сть видимости и вре мяж изни пе ре ме нной В языкеС сущ ествую тчетыреклассап амяти: автоматический (auto); внеш ний (extern); статический (static); рег истровый (register). В основе деления наклассы п амятилеж ат две базовые конц еп ц ии: область видимостип еременной ивремя ж изнип еременной.
22 О бл а сть видимости оп ределяет ту часть п рог раммы, вп ределах которой известны имя итип п еременной. О бласть видимости мож ет быть локальной или глоб альной . Н ап ример, п еременные автоматическог о классап амяти являю тся локальными п о отнош ению к функц ии, в которой они оп ределены. П оп ытка исп ользовать эту ж е п еременную внетелафункц ии, г деэтап еременная оп ределена, п риведетк ош ибке. П еременная г лобально видима, если онавидиманап ротяж ении всег о файла. В ре мя ж изни оп ределяет время сущ ествования п еременной в п роц ессе вып олнения п рог раммы. В ремя ж изни п еременной мож ет быть г лоб альны м или локальны м . П еременная с гл оба л ьным вре ме не м ж изни обладает оп ределенными п амятью и значением на п ротяж ении всег о времени вып олнения п рог раммы. П еременная с л ока л ьным вре ме не м ж изни захватываетновую п амять п рикаж дом входевблок, вкотором она оп ределена. К ог дазаверш ается вып олнение блока, локальная п еременная п роп адает, азначитп роп адаетиеезначение. Т аким образом, время ж изни п еременной оказывает п рямое воздействие на возмож ность ее исп ользования, П еременные, п ринадлеж ащ ие различным классам п амяти, мог ут быть локальны м и или г лоб альны м и. П еременные, п ринадлеж ащ ие автоматическому (auto), рег истровому (register) и в некоторых случаях статическому (static) классу п амяти, являю тся л ока л ьными. П еременные, п ринадлеж ащ ие внеш нему (extern), а такж е в некоторых случаях статическому (static) классу п амяти, — гл оба л ьные . Т аким образом, п еременныестатическог о классап амятимог утбыть как локальными, так и г лобальными. 2.5.2 Л ока л ьные пе ре ме нные . Автома тиче ский кл а сс па мяти. Л окальной п еременной называется п еременная, доступ к которой возмож ен только внутринекоторог о блокаоп ераторовилифункц ии. П ри этом имя локальной п еременной мож ет совп адать с именем друг ой п еременной, оп ределенной снаруж и. Л окальная п еременная вэтом случае п ерекрываетвнеш ню ю во всем блокекодаилифункц ии. Л окальные п еременные мог ут быть автоматические. А вт ом ат ические – это теп еременные, которыесоздаю тся автоматически
23 п ри входе вфункц ию или блок кодаиуничтож аю тся п ривыходе из нег о. П амять п од автоматическиеп еременныевыделяется встеке. А втоматическими п еременными являю тся п араметры функц ии, а такж е п еременные, оп ределенные вее начале иливначале блокакодап о схеме [auto] тип имя[=на ча л ьное зна че ние ]; О бычно слово auto оп ускаю т, и, п о умолчанию , п ринимается, что п еременные, оп ределенные таким образом, в теле функц ии, являю тся автоматическими. О бласть видимости, а такж е время ж изни автоматических п еременных ог раничены телом функц ии. К ним невозмож но обратиться из друг их функц ий. 2.5.3 Л ока л ьные пе ре ме нные . С та тиче ский кл а сс па мяти С т ат ические локальные п еременные оп ределяю тся такж е как и автоматическиетолько со словом static вп ереди, нап ример, static тип имя[=на ча л ьное зна че ние ]; В отличие от автоматических п еременных, статические создаю тся один раз п ризап ускеп рог раммы (п ричем, п еред вызовом функц ииmain), и сущ ествую тдо самог о еезаверш ения. 2.5.4 Р е гистровый кл а сс па мяти. В языке С введен сп ец иальный класс п амяти, п одобный автоматическому, который п редусматривает, что значение п еременной будетразмещ аться врег истре. Э тоткласс п амятиназывается ре гистровым (register). П редп олагалось, что он будет обесп ечивать более быстрое вып олнение оп ерац ий. Н е все комп иляторы п оддерж иваю т этот класс п амяти. В этих случаях рег истровый класс п амяти рассматривается как автоматический. М ог ут быть оп ределены как рег истровые только п еременные тип аchar, short иint. О п ределение п еременной рег истровог о классап амятиначинается со словаregister. Н ап ример: register int i=0; П еременные рег истровог о классап амяти имею т такие ж е область видимостиивремя ж изни, как иавтоматическиеп еременные. О п ределение рег истровых п еременных обычно долж но быть вначалеблока. Сущ ествует
24 одно ог раничение: оп ерац ия указателей п рименяться к рег истровым п еременным.
(&)
не
мож ет
2.5.5 Гл оба л ьные пе ре ме нные . В не ш ний кл а сс па мяти. Глобальные п еременные, как и static локальные, создаю тся п ри зап уске п рог раммы и сущ ествую т до ее заверш ения. О тличие втом, что они оп ределяю тся за п ределами всех функц ий и доступ ны из лю бой функц ии (если только она не п ерекрывает г лобальную п еременную локальной). Глобальная п еременная долж набыть оп исанадо ее исп ользования. В неш ние(extern) п еременныеоп ределяю тся внетелафункц ии, чащ евсег о в начале исходног о файла. Н ап ример, оп ределение символьной п еременной с иц елой п еременной a с классом п амятиextern мож етиметь следую щ ий вид: int а=10; char c=’y’; main() {… } К лю чевое слово extern в этом случае не указывается. Т ак как п еременная оп ределенавкачествевнеш ней, онамож етбыть исп ользована неп осредственно в лю бой из функц ий, составляю щ их исходный файл. Е сли какая-либо функц ия изменяет значение внеш ней п еременной, то лю бая п оследую щ ая функц ия п олучитизмененноеновоезначение. Н о иног даследует объявить и внеш ню ю п еременную внутри тела какой-либо функц ии, и это объявление долж но начинаться с клю чевог о словаextern, котороенельзя оп ускать. Д елать это нуж но вследую щ их случаях: 1) ког да функц ия, которая исп ользует внеш ню ю п еременную , размещ енависходном файледо оп ределения этой внеш ней п еременной; 2) ког да функц ия, которая исп ользует внеш ню ю п еременную , размещ енавдруг ом исходном файле. В друг их случаях обычно г лобальные п еременные оп ределяю т в начале файлаили хотя бы до функц ий, исп ользую щ их эти п еременные.
25 Е сли необходимо исп ользовать г лобальную п еременную , оп ределенную вдруг ом файле, онадолж набыть оп исанавданном файле как extern: extern имятип; П рисвоение начальног о значения здесь не доп ускается, так как это неоп ределениеп еременной, аоп исаниетог о, что онаберется г де-то извне (ссылкананеебудетразреш енанаэтап екомп оновкип рог раммы). О п исание г лобальной п еременной, исп ользуемой в нескольких друг их файлах, часто выносят в заголовочный h-файл, так ж е как и п рототип ы функц ий. О бъявление внеш них п еременных информирует комп илятор, что такая п еременная уж е сущ ествует и п амять для нее уж е выделена. В неш няя п еременная имеет г лобальное время ж изни, т.е. обладает оп ределенными п амятью и значением на п ротяж ении всег о времени вып олнения п рог раммы, начиная с момента оп ределения внеш ней п еременной. В неш ние п еременные мож но иниц иализировать только выраж ениямис константамииуказателяминаранее оп исанные объекты. П о умолчанию , если не задана иниц иализац ия, внеш ние п еременные п олучаю тнулевыеначальныезначения. 2.5.6 Гл оба л ьные пе ре ме нные . С та тиче ский кл а сс па мяти. Глобальная п еременная мож етбыть сделанавидимой только водном файле. Д ля этог о п еред ееоп исанием ставятслово static. В разных файлах мог ут быть оп ределены и исп ользоваться разные static – г лобальные п еременные с одним и тем ж е именем без всяког о конфликта. Н икаког о сп особадоступ ак статической п еременной одног о файлаиз друг ог о нет. П еременные статическог о классап амяти мог ут быть внеш ними и внутренними. В обоих случаях п еременные долж ны быть оп ределены с п омощ ью клю чевог о словаstatic. В ремя ж изни статических п еременных г лобальное: начинается п ослеоп ределения п еременной ип родолж ается до конц а п рог раммы. О бласть видимости статических п еременных будет зависеть оттог о, являю тся лионивнеш нимииливнутренними. Статические п еременные мож но иниц иализировать только выраж ениями с константами или указателями на ранее оп исанные
26 п еременные. Статические п еременные иниц иализирую тся один раз – п рип ервом входе вту область, г де ониоп исаны (либо нулем, еслиначальные значения не заданы). П рип оследую щ их входах вданную область статические п еременные сохраняю т те значения, которые они имелип рип оследнем выходеиз области. В нутре нние ста тиче ские пе ре ме нные оп ределяю тся вначалеблока, вкотором онибудутисп ользоваться. О бласть видимостирасп ространяется только на этот блок. П оэтому внутренние статические п еременные п одобны автоматическим п еременным, за исклю чением тог о, что они сущ ествую тип ослевыходаиз функц ииилиблока. В не ш ние ста тиче ские пе ре ме нные оп ределяю тся вне всех функц ий, так ж екак ивнеш ние(extern) п еременные. О днако воп ределениивнеш них статических п еременных п ервым долж но быть клю чевоеслово static. Н ап ример, оп ределениевнеш ней double п еременной е истатической ц елой i, иниц иализированной единиц ей, долж но размещ аться п еред функц ией main() ииметь вид: double e=1.0; static int i=l; main( ) {… } И так, если нуж но сделать недоступ ной информац ию вфайле для друг их файлов, надо исп ользовать внеш ниестатическиеп еременные. § 3. О ПЕ РА Ц И И И В Ы РА Ж Е Н И Я 3.1. О сновны е сведения В ыра ж е ния являю тся объектами, конструируемыми с исп ользованием оп ерац ий, констант, п еременных (вклю чая структуры, массивы и вызовы функц ий). В ыраж ения состоят из опе ра ндов (элементов языка) и опе ра ц ий. В ыраж ения, ссылаю щ иеся на п еременную , которой мож ет быть п рисвоено значение, называю тся а дре сными (взарубеж ных комп иляторах и литературе адресноевыраж ениеобозначается символом lvalue). О п ерац ииклассифиц ирую тся п о числу участвую щ их вних оп ерандовили п о тип у действия, котороеонивып олняю т.
27 П ри классификац ии п о числу оп ерандоввсе оп ерац ии языка С мог утбыть разделены на4 катег ории: 1) п ервичные, оп ределяю щ ие разделители и комп оненты составных объектовязыка; 2) унарные, вып олняю щ ие оп ределенные действия только над одним оп ерандом; 3) бинарные, для вып олнения которых требую тся два оп еранда; больш инство оп ерац ий языкавходитвэту г руп п у; 4) тройная, для вып олнения которой требую тся три оп еранда; в С сущ ествуеттолько однатройная оп ерац ия — условная оп ерац ия. К лассификац ия оп ерац ий языка С п о тип ам вып олняемых действий п редставленавтаблиц е. Т аблиц а4 П риоритет
К ласс оп ерац ии
О п ерац ия Первичны е
1 вызовфункц ии
имя(п араметры)
индексац ия
[]
доступ к элементу структуры п о имени
.
доступ к элементу структуры п о указателю
-> У нарны е
2 разименование
*
п олучениеадреса
&
изменениезнака
-a
п риведениетип а
(тип ) выраж ение
размер
sizeof()
автоинкремент
++a
автодекремент
--a
инверсия
~a
лог ическоеотриц ание
!a Бинарны е
3
мул ьтипл ика тивные
28 умнож ение
a*b
деление
a/b
остаток отделения
a%b а ддитивные
4
5
слож ение
a+b
вычитание
a-b
побитовые сдвиги
a<>b отнош е ния
6 меньш е
a
меньш еилиравно
a<=b
больш е
a>b
больш еилиравно
a>=b ра ве нства
7 равно
a= = b
неравно
a! = b
8
побитовое И
a&b
9
искл юча ющ е е ИЛ И
a^b
10
побитовое ИЛ И
a|b
11
л огиче ское И
a&&b
12
л огиче ское ИЛ И
a||b
13
У словное вы раж ение
условие? выр1: выр2
14
Присваивания
a=b, a*=b, a+=b, a<<=b, a&=b, a^=b, a/=b, a- =b, a>>=b, a|=b, a%=b
15
З апят ая
выр1, выр2
Бинарные оп ерац ии разделяю тся на тип ы: мультип ликативные, аддитивные, сдвиг а, отнош ения, равенства, п обитовое И , п обитовоеИ Л И , исклю чаю щ ееИ Л И , лог ическоеИ , лог ическоеИ Л И . В се оп ерац ии языкаС имею т дваваж ных атрибута– п риоритет и п орядок. П риоритет мож но рассматривать как ранг оп ерац ии. П риоритет оп ерац ий имеет такой ж е смысл, как и в алг ебре. Самый высокий п риоритетимею тп ервичныеоп ерац ии.
29 П орядок мож но рассматривать как нап равление, вкотором вып олняю тся оп ерац ии, обладаю щ иеодинаковым п риоритетом. О п ерац ии, требую щ ие более одног о оп еранда, мог ут быть коммутативными и некоммутативными. Говорят, что оп ерац ия коммут ат ивна, еслип ерестановкаместамидвух ееоп ерандовнеизменяет значение результата оп ерац ии. К оммутативные оп ерац ии в языке С: умнож ение( * ), слож ение( + ), равно ( = = ), неравно ( ! =), п обитовоеИ ( & ), п обитовоеисклю чаю щ ееИ Л И (^) , п обитовоеИ Л И ( | ). В ыраж ения, вклю чаю щ ие одну из коммутативных оп ерац ий, даж е п ри наличии скобок мог ут быть п ереуп орядочены комп илятором. В о мног их случаях это несущ ественно, но втех ситуац иях, г деваж но оставить п орядок вычислений, мож но исп ользовать явную п ромеж уточную п еременную . В языке С не задан п орядок вычисления оп ерандовдля оп ерац ий. В этом случае для задания оп ределенног о п орядка вып олнения п ромеж уточный результат мож но сохранить внекоторой п ромеж уточной п еременной. Н о сущ ествую т четыре оп ерац иивязыке С, которые имею т ж есткий п орядок вычисления: лог ическое И (&&), лог ическое И Л И (||), зап ятая (,), условное выраж ение (? :). О п еранды в этих оп ерац иях вычисляю тся всег даслеванап раво. 3.2. Первичны е вы раж ения П ервичные выраж ения вклю чаю т оп ерац ии: доступ а к элементу структуры п о имени, доступ а к элементу структуры п о указателю , индексац ииивызовафункц ии. П олный сп исок п ервичных выраж ений вязыкеС: константа, строка, идентификатор, (выраж ение), п ервичное выраж ение [выраж ение], п ервичное выраж ение (сп исок выраж ений), п ервичный адрес.идентификатор, п ервичноевыраж ение-> идентификатор. К онстанта имеет тип в соответствии с ее видом. Символьные константы имею ттип int, константы с п лаваю щ ей точкой – тип double. Строкап редставляется указателем наначало массивасоставляю щ их еесимволов.
30 И дентификатор в п ервичном выраж ении обозначает п еременную или составной объект (массив, структура, функц ия). Значениями составных объектов являю тся указатели на эти объекты. 3.3. Первичны е операции 3.3.1 О пе ра ц ия() вызова ф ункц ии ил и изме не нияпорядка вычисл е ния выра ж е ния О п ерац ия вып олняется слеванап раво. О п ерац ия () оп ределяет п орядок вып олнения оп ерац ий и ог раничивает сп исок арг ументовот имени функц ии ввызове функц ии. Скобкитакж еисп ользую тся п риобразованиисоставных объектов. О бращ ение к функц ии – п ервичное выраж ение. Заним вскобках следует (через зап ятую ) ряд выраж ений, являю щ ихся фактическими арг ументамиэтой функц ии. Болееп одробно об этом оп исано вп .1.2 3.3.2 О пе ра ц ияинде кса ц ия О п ерац ия имеетвид: пе рвичное выра ж е ние [ц е л ое выра ж е ние ] О п ерац ия вып олняется слеванап раво. П ервичное выраж ение вэтой оп ерац ии п редставляет имя массива, которое является адресом п ервог о элементамассива. Ц е л ое выра ж е ние долж но находиться вп ределах г раниц массива. О но мож ет п ринимать значения в интервале от нуля до количества элементов в массиве минус единиц а. Э лементы массива в п амятиразмещ аю тся п острочно. О п ерац ия индексац ии исп ользуется как для оп ределения массивов, так идля обращ ения к оп ределенным элементам массива. n-мерный массивоп ределяется следую щ им образом: тип да нных имяма ссива [t][n]… [r] Буквы в квадратных скобках п редставляю т выраж ения, которые п риводятся к ц елому тип у. Э ти ц елые значения, называемые инде кса ми, обозначаю т размерность массива, азначение каж дог о индексаоп ределяет количество элементовп о каж дому измерению . О п ерац ия индексац ии исп ользуется п ри обращ ении к отдельному элементу массива. Э лементы массиванумерую тся, начиная с нуля икончая
31 значением индекса минус единиц а. Более п одробно мы рассмотрим это п риоп исаниимассивов. 3.3.3 О пе ра ц ии доступа к эл е ме нту структуры/объе дине ния О п ерац ииимею твид: п ервичный адрес.идентификатор п ервичноевыраж ение->идентификатор О п ерац иивып олняю тся слеванап раво. О п еранд пе рвичный а дре с воп ерац иидоступ к элементу структуры п о имени ( . ) есть адресное выраж ение, обозначаю щ ее структуру или объединение. О п еранд пе рвичное выра ж е ние в оп ерац ии доступ к элементу структуры п о указателю (->) есть указатель наструктуру илиобъединение. О п еранд иде нтиф ика тор для обеих оп ерац ий долж ен быть именем элементаструктуры илиобъединения. Результатом оп ерац ий является адресное значение, указываю щ ее на п оименованный элементструктуры илиобъединения. О п ерац ия доступ к элементу структуры п о имени( .) дает удобный метод для обращ ения к элементу п еременной структуры. Н ап ример, еслиs - п еременная тип аструктуры struct test_struct, содерж ащ ей п оле f, то к этому п олю удобно обращ аться п рип омощ иконструкц ии s.f Е слиж еу нас есть указатель натакую структуру ps, то мы мог либы исп ользовать зап ись (*ps).f Скобки вданном случае необходимы, так как п риоритет оп ерац ии доступ к элементу структуры п о имени( . ) выш е, чем унарной оп ерац ии доступ п о указателю (*). О днако, исп ользованиеоп ерац ии-> п озволяетсделать зап ись короче ип онятнее: ps->f Болееп одробно структуры иобъединения рассмотрены в§ 5.
32 3.4. У нарны е операции 3.4.1 О пе ра ц ии доступа по ука за те л ю и взятияа дре са О п ерац ииимею твид: *выра ж е ние &а дре сное выра ж е ние О п ерац иивып олняю тся сп раваналево. У нарная оп ерац ия * означает доступ п о указателю к значению п еременной. В ыраж ениесп раваотзвездочкидолж но быть указателем или иметь результат тип а указатель. Результатом оп ерац ии доступ п о указателю (*) является значение п еременной, на которую ссылается указатель. У нарная оп ерац ия ( & ) означает п олучение адреса некоторог о объекта. О п ерандом мож етбыть п еременная илиэлементмассива. Н ельзя п олучить адрес константы. Н ельзя п рименять оп ерац ию к п еременным рег истровог о классап амяти. О п ерац ия доступ п о указателю (*) мож ет исп ользоваться вобеих частях оп ераторап рисваивания ( *а== *b), вто время как оп ерац ия взятия адреса(&) — только вп равой частиоп ераторап рисваивания ( c=&d) . О п ерац иидоступ ап о указателю ивзятия адресап озволяю тработать с указателями. Н ап омним, что указатель — это п еременная, которая содерж ит адрес размещ ения в п амяти друг ой п еременной. О п ерац ия указатель дает адрес размещ ения в п амяти п еременной, элемента структуры илиэлементамассива. П реимущ ество исп ользования указателей особенно ярко п роявляется п ри работе с такими п роизводными тип ами данных, как массивы и структуры. Следует заметить, что различные тип ы данных п редъявляю т разные требования к объему выделяемой для них п амяти. П оэтому, ког дадля доступ а к п еременной исп ользуется указатель, стартовый адрес размещ ения в п амяти этой п еременной является необходимым, но не достаточным условием для доступ ак этой области п амяти. Зная только стартовый адрес размещ ения вп амяти п еременной, ни комп илятор, ни п рог раммист не мог ут оп ределить, г де ж е заканчивается область п амяти, на которую ссылается указатель. Т акж е неизвестен тип данног о, содерж ащ ег ося в этой области п амяти. Д ля реш ения этих п роблем
33 необходимо оп исать указатели п еред их исп ользованием. У казатели оп исываю тся так ж е, как и данные друг их тип ов, заисклю чением тог о, что тип данног о воп исаниинеявляется тип ом указателя, аотносится к п еременной, накоторую ссылается указатель. Н ап ример: int (* р) [4]; - указатель намассивиз четырех ц елых; int *р[4]; - массив из четырех элементов, каж дый из элементов массиваявляется указателем нац елое; int *р; - указатель нац елое; int a; - ц елая п еременная. 3.4.2 О пе ра ц ияизме не ниязна ка О п ерац ия имеетвид: - (выра ж е ние ) О п ерац ия вып олняется сп рава налево и только над объектами арифметическог о тип а. Результатом является оп еранд, взятый с п ротивоп олож ным знаком. Т ип результатасохраняется. У нарный минус следуетотличать отоп ерац иивычитания. Н ап ример, оп ератор а=b--с; мож ет вызвать ош ибку в некоторых реализац иях, так как оп ерац ии вычитания и унарный минус, следую щ ие друг за друг ом, мог ут быть ош ибочно ассоц иированы с оп ерац ией уменьш ения. 3.4.3 О пе ра ц ии а втоуве л иче нияи а втоуме ньш е ния О п ерац ииимею твид: ++ а дре сное выра ж е ние или а дре сное выра ж е ние ++ --а дре сное выра ж е ние или а дре сное выра ж е ние -О п ерац иивып олняю тся сп раваналево. О п ерац ия увеличения увеличивает значение своег о оп еранда на единиц у, оп ерац ия уменьш ения уменьш аетег о значениенаединиц у. Различаю т п рефиксную и п остфиксную формы оп ерац ий. Е сли оп ерац ия п омещ ается п еред оп ерандом, онаназывается пре ф иксной, если п осле оп еранда, — постф иксной. В результате вып олнения п рефиксной оп ерац ии значением всег о выраж ения является измененное значение
34 оп еранда, в результате вып олнения п остфиксной оп ерац ии- п реж нее, неизменноезначениеоп еранда. Д ля п римерасравним результаты вып олнения оп ераторов: int а=5; b=++а; (1) П еременная b п олучитзначение6. int a=5; b=a++; (2) П еременная b п олучитзначение5. О п ерац ии увеличения и уменьш ения мог ут п рименяться только к одиночным п еременным. В ыраж ение вида(а+b)++ недоп устимо, так как (a+b) неявляется адресным выраж ением. Следуетзап омнить, что оп ерац ии увеличения и уменьш ения вотличие от больш инстваоп ерац ий языкаС, действительно изменяю ттекущ еезначениеп еременной благодаря неявной оп ерац иип рисваивания. 3.4.4 опе ра ц ияпре обра зова ниятипа О п ерац ия имеетвид: (тип) (выра ж е ние ) О п ерац ия вып олняется сп раваналево. Заклю ченное вкруг лые скобки обозначение тип аданных, стоящ ее п еред выраж ением, вызываетп реобразованиезначения этог о выраж ения к заданному тип у. О бозначение тип азап исывается п о тем ж е п равилам, что и обозначение объекта в оп исаниях, за исклю чением тог о, что здесь отсутствуетидентификатор объекта. П римеры обозначений тип а: int -ц елый; int* - указатель нац елое; int *[4] — массивиз четырех указателей нац елое; int (*)[4 ] - указатель намассивиз четырех ц елых; int *() - функц ия, возвращ аю щ ая указатель нац елое; int (*)()- указатель нафункц ию , возвращ аю щ ую ц елое. В ыраж ение (int).359е02 дает ц елое значение 35, так как п ри п реобразовании к ц елому дробная часть отбрасывается. О п ерац ия п реобразованиетип аисп ользуется втех случаях, ког дап о контексту не п редп олагается автоматическог о п реобразования тип ов,
нап ример п ри сог ласовании п риобращ ениик функц ии.
35 тип ов арг ументов и п араметров
3.4.5 О пе ра ц ияsizeof - опре де л е ние ра зме ра па мяти (в ба йта х) О п ерац ия имеетвид: sizeof (выра ж е ние ) sizeof(тип) . О п ерац ия вып олняется сп раваналево. О п ерац ия sizeof выдаетразмер своег о оп ерандавбайтах. О п ерандом мож ет быть лю бое выраж ение или тип . Е сли значением выраж ения является составной объект, выдается размер всег о объекта. Е сли оп ерандом является обозначение тип а, выдается размер лю бог о объекта данног о тип а. Результатоп ерац ииsizeof имееттип int. 3.5. Бинарны е операции 3.5.1 М ул ьтипл ика тивные опе ра ц ии - умнож е ние , де л е ние , де л е ние по модул ю О п ерац ииимею твид: выра ж е ние 1 * выра ж е ние 2 выра ж е ние 1 / выра ж е ние 2 выра ж е ние 1 % выра ж е ние 2 О п ерац иивып олняю тся слеванап раво. О п еранды воп ерац иях умнож ения и деления мог ут иметь лю бой арифметический тип , авоп ерац ии деления с остатком оп еранды только ц елог о тип а. Результатоп ерац ий имеетарифметический тип int илиdouble всоответствиис п равиламип реобразования тип ов. О п ерац ия умнож ения * вып олняется п о обычным п равилам ц елочисленной и п лаваю щ ей арифметики. Е сли результат оп ерац ии п ревыш ает максимально доп устимое для данног о тип а значение, п роисходит п отеря старш их битов, и результат п олучается неоп ределенный. О п ерац ия деления / вып олняется п о обычным п равилам ц елочисленной и п лаваю щ ей арифметики. Д ля ц елых чисел результат всег да усекается в сторону нуля. Результат оп ерац ии неоп ределенный,
36 если делитель (второй оп еранд) равен нулю (обычно в такой ситуац иип роисходитаварийноезаверш ениеп рог раммы). О п ерац ия модульное деление % п рименяется только к ц елочисленным тип ам оп ерандов. Результат имеет значение остаткаот деления п ервог о оп еранданавторой. Знак остаткавсег дасовп адает со знаком п ервог о оп еранда. Н ап ример: 9%5 - результат4;-9% 5 - результат-4; 9%-5-результат4; 9%3 -результат0. 3.5.2 Аддитивные опе ра ц ии - сл ож е ние и вычита ние О п ерац ииимею твид: выра ж е ние 1 + выра ж е ние 2 выра ж е ние 1 - выра ж е ние 2 О п ерац иивып олняю тся слеванап раво. О п ерандами мог ут быть лю бые скалярные выраж ения. Результат будет арифметическог о тип а либо тог о ж е тип а, что и у оп еранда указателя. О п ерац ия слож ения вычисляет сумму оп ерандов, оп ерац ия вычитания — разность п ервог о и второг о оп ерандов. Е слиобаоп еранда арифметическог о тип а, оп ерац ии вып олняю тся п о обычным п равилам ц елочисленной арифметики. В языке п редусмотрены оп ерац ии над указателями, которые п озволяю тп рибавить к указателю (иливычесть из нег о) лю боевыраж ение ц елог о тип а. Результатом такой адресной оп ерац ии будет значение указателя п лю с (или минус) значение второг о оп еранда, умнож енное на размер объекта, накоторый ссылается указатель (т.е. п рип рибавленииили вычитаниииз указателя ц елог о числаn, п олучаем адрес объектаданног о тип а, смещ енног о наn элементоввп раво иливлево относительно объекта, накоторый ссылается указатель). К роме слож ения и вычитания с ц елым, возмож на оп ерац ия вычитания двух указателей одинаковог о тип а. Результат п реобразуется к количеству объектов данног о тип а, расп олож енных в области п амяти меж ду двумя указателями, п утем деления разностинаразмер объекта, на который ссылаю тся указатели. П одробнее этивоп росы рассмотрены вп . 6.2.
37 3.5.3 О пе ра ц ии сдвига О п ерац ииимею твид: выра ж е ние 1 << выра ж е ние 2 выра ж е ние 1 >> выра ж е ние 2 О п ерац иивып олняю тся слеванап раво. В ыра ж е ние 2 долж но быть ц елог о тип а, оно не мож ет быть отриц ательным или быть больш е, чем длиналевог о оп ерандавбитах. В ыра ж е ние 1 долж но п реобразовываться к ц елому тип у. О п ерац ия сдвиг а влево начинается с размещ ения левог о оп ерандаво временную область п амяти, достаточную для размещ ения тип аint. Биты внутриэтой области п амятисдвиг аю тся влево начисло п озиц ий, заданноеп равым оп ерандом. О п ерац ия сдвиг а вп раво вып олняется аналог ично, но сдвиг п роисходитвп раво. П ри сдвиг е влево освобож даемые биты зап олняю тся нулями. П ри сдвиг евп раво освобож даемые биты зап олняю тся нулями, еслитип левог о оп ерандаunsigned. Д ля друг их тип оврезультатзависитотреализац ии. Т ип результатавсег дасовп адаетс тип ом левог о оп еранда. 3.5.4 О пе ра ц ии отнош е нияи ра ве нства - ме ньш е , бол ьш е , ме ньш е ил и ра вно, бол ьш е ил и ра вно, ра вно, не ра вно О п ерац ииимею твид: выра ж е ние 1 < выра ж е ние 2 выра ж е ние 1 > выра ж е ние 2 выра ж е ние 1 <= выра ж е ние 2 выра ж е ние 1 >= выра ж е ние 2 выра ж е ние 1 == выра ж е ние 2 выра ж е ние 1 != выра ж е ние 2 О п ерац иивып олняю тся слеванап раво. О п ерац ииравенствареализую тся так ж е, как иоп ерац ииотнош ения, различиемеж ду нимисостоиттолько вп риоритете: у оп ерац ий отнош ения он выш е. О п ерандами мог ут быть лю бые скалярные тип ы. В ычисляю тся значения обоих выраж ений, п риводятся к одному тип у и сравниваю тся. Результат оп ерац ии - ц елое значение 1, если отнош ение истинно, или ц елое значение 0, если отнош ение лож но. О п еранды - указатели п еред
38 сравнением п реобразую тся к ц елому тип у, п оэтому в сравнениивэтом случае участвую т значения адресовп амяти. У казатели, следовательно, мог утсравниваться с ц елымичислами. 3.5.5 Побитовые опе ра ц ии - отриц а ние , ил и, и, искл юча ющ е е ил и О п ерац ииимею твид: ^выра ж е ние выра ж е ние | выра ж е ние выраж ение& выра ж е ние выра ж е ние ^ выра ж е ние О п ерац ии вып олняю тся слева нап раво, кроме оп ерац ии (~). П обитовая оп ерац ия отриц ания (~) имеет самый высокий п риоритет из всех оп ерац ий над битами. Д ля вып олнения этих оп ерац ий мог ут исп ользоваться только выраж ения, п риводимыек ц елому тип у. У казанные оп ерац ии манип улирую т со значениями своих оп ерандов на уровне битовог о п редставления. Т ри бинарные оп ерац ии ( | , & , ^ ) формирую т каж дый бит результата сог ласно значениям каж дой п ары бит своих оп ерандов в соответствиисо следую щ ей схемой: & 0 1 | 0 1 ^ 0 1 0 0 0 0 0 1 0 0 1 1 0 1 1 1 1 1 1 0 У нарная оп ерац ия (~) формируетрезультат, вкотором каж дому биту оп еранда, равному 1, соответствует0 инаоборот(п обитовоеотриц ание). 3.5.6 Л огиче ские опе ра ц ии - И и ИЛ И О п ерац ииимею твид: выра ж е ние && выра ж е ние выра ж е ние || выра ж е ние В лог ической оп ерац ии И (&&) оп ерандами мог ут быть лю бые скалярные выраж ения. О п ерац ия вып олняется слева нап раво. Сначала вычисляется выраж ениеслева. Е слионо равно нулю , то выраж ениесп рава не вычисляется и результатом оп ерац ии будет нуль; вп ротивном случае вычисляется выраж ение сп рава. Е сли оно равно нулю , результатом оп ерац иибудетнуль; еслинеравно нулю , результатом будетединиц а.
39 В лог ической оп ерац ии И Л И ( || ) оп ерандамимог утбыть лю бые скалярные выраж ения. О п ерац ия вып олняется слева нап раво. Сначала вычисляется выраж ение слева. Е сли оно не равно нулю , выраж ениесп раваневычисляется ирезультатом оп ерац иибудетединиц а. В п ротивном случае вычисляется выраж ение сп раваи, если оно равно нулю , результатом оп ерац иибудет нуль; есливыраж ение сп раване равно нулю , результатом будетединиц а. П риоритет лог ической оп ерац ии И выш е п риоритета лог ической оп ерац ииИ Л И . 3.5.7 О пе ра ц ии присва ива ния-простого и соста вного О п ерац ииимею твид: а дре сное выра ж е ние опе ра ц ия выра ж е ние г деопе ра ц ия— однаиз оп ерац ий п рисваивания: =, *=, /=, %=, +=, - =, &=, ^=, |=, >>=, <<= О п ерац иип рисваивания вып олняю тся сп раваналево. В левой части оп ерац ии п рисваивания мож ет исп ользоваться адресное выраж ение: п еременная базовог о тип аданных; п еременная п роизводног о тип аданных; элемент массива; имя структурной п еременной или элемент структуры; выраж ение, ссылаю щ ееся нап еременную одног о из п еречисленных выш е тип ов, которой мож етбыть п рисвоено значение. Е слиобаоп ерандаарифметическог о тип а, атип выраж ения вп равой частинесовп адаетс тип ом объектавлевой части, то он п риводится к тип у левой частидо вып олнения оп ерац ии. Зап ись составной оп ерац иип рисваивания х опе ра ц ия= у эквивалентназап иси х = х опе ра ц ияу г де опе ра ц ия - однаиз бинарных оп ерац ий; х, у — выраж ения. Н ап ример, зап ись d* = 4+6; эквивалентназап исиd=d*(4+6); И сп ользование составной оп ерац ии п рисваивания сокращ ает время кодирования исоздаетболееэффективный объектный код.
40 Составноеп рисваиваниене п олностью эквивалентно п ростому п рисваиванию . В составном п рисваивании выра ж е ние 1 опе ра ц ия= выра ж е ние 2 оп еранд выра ж е ние 1 вычисляется только один раз, а в п ростом п рисваивании выра ж е ние 1 = выра ж е ние 1 опе ра ц иявыра ж е ние 2 выра ж е ние 1 вычисляется дваж ды. Т ак как п рисваивание является выраж ением, оно мож ет исп ользоваться всоставеболееслож ног о выраж ения, нап ример: s:=n+(j=k++); m=n=p=0; 3.5.8 О пе ра ц ияза пята я О п ерац ия имеетвид: выра ж е ние , выра ж е ние В ыраж ение с зап ятой вычисляется слева нап раво. Сначала вычисляется левоевыраж ение, ирезультатег о вычисления отбрасывается. Затем вычисляется п равое выраж ение. Значение и тип результата вычисления п равог о выраж ения и будут результатом оп ерац ии зап ятая. Н ап ример: s=(3.14,i%9,200); П еременной s п рисваивается значение200. s=3,i%9, t=100 Э то выраж ение п рисваивает три независимые величины трем различным п еременным. 3.5.9 У сл овна яопе ра ц ия О п ерац ия имеетвид; выра ж е ние 1 ? выра ж е ние 2 : выра ж е ние 3 О п ерац ия имеетфиксированный п орядок вычисления. П ервым вычисляется выра ж е ние 1. Е сливыра ж е ние 1 — "истина" (не нуль), вычисляется выра ж е ние 2. Значениевыра ж е ния2 будетрезультатом условной оп ерац ии. Е сли выра ж е ние 1 — "лож ь" (нуль), вычисляется выра ж е ние 3. Значениевыра ж е ния3 будетрезультатом оп ерац ии.
41 3.6. А риф м ет ические преоб разования П ри вып олнении арифметических оп ерац ий вязыке С действую т следую щ иеп равилап реобразования тип ов: 1) оп еранды тип аchar иshort п реобразую тся к тип у int, атип аfloat — к тип у double; 2) если один из двух оп ерандовимеет тип double, друг ой оп еранд п реобразуется к тип у double (п редп олагается, что второй оп еранд неимеет тип double) ирезультатоп ерац иибудеттакж етип аdouble; 3) если один из двух оп ерандовимеет тип long, друг ой оп еранд п реобразуется к тип у long (п редп олагается, что он не имеет тип long), и результатбудеттакж еиметь тип long; 4) если один из оп ерандов имеет тип unsigned, тог да и друг ой оп еранд п реобразуется к тип у unsigned (п редп олагается, что он не был тип аunsigned),. ирезультаттакж ебудетиметь тип unsigned; 5) еслиневып олнены условия 1 -4, обаоп ерандадолж ны быть тип а int, ирезультатимееттип int. Т аким образом, значения п риводятся к тому тип у, который п озволяет п редставить больш ий диап азон значений (во избеж ание п ереп олнения). 3.7. К онст ант ны е вы раж ения К онста нтным называется выраж ение, которое всег да дает единственноезначение. В языкеС константныевыраж ения требую тся: п ри иниц иализац иивнеш них статических п еременных; п ослеклю чевог о слова case воп ераторе switch; п ри оп ределении г раниц массива. В п оследних двух случаях константное выраж ение мож ет состоять из ц елых и/или символьных константиоп ерац ииsizeof. Д ля объединения констант в выраж ения мог ут исп ользоваться бинарныеоп ерац ии, унарный минус итройная оп ерац ия. П ри иниц иализац ии внеш них или статических п еременных мож ет такж еисп ользоваться оп ерац ия взятия адреса( & ), еслионап рименяется к п редварительно оп ределенным внеш ним или статическим объектам и внеш ним или статическим массивам, индексированным константными выраж ениями.
42 Т аким образом, иниц иализирую щ ее значение долж но сводиться либо к константе, либо к адресу п редварительно оп исанног о внеш нег о илистатическог о объектап лю с/ минус п остоянное значение(смещ ение). § 4. О ПЕ РА Т О РЫ 4.1. О б щ ие сведения О пе ра тор - единиц авып олнения п рог раммы. О п ераторы делятся на п ростыеисоставные. К простым относится оп ератор выраж ения, который состоит из лю бог о выраж ения, заканчиваю щ ег ося точкой с зап ятой. Н ап ример: ++j; Ч ащ евсег о исп ользую тся п ростыеоп ераторы, содерж ащ иеоп ерац ии п рисваивания значений п еременным и/иливызовы функц ий, нап ример: а=10; funl(argl, arg2); П олезным действием таких оп ераторовявляется изменениезначений п еременных и/или действия, вып олняемые внутри функц ии п осле ее вызова. Е щ е один вид п ростог о оп ератора- оп ератор return, рассмотренный п . 1.2.2. К п ростым относится такж е пустой оп ератор, который состоит только из точкис зап ятой. П устой оп ератор нег енерируетникаког о кодаи исп ользуется обычно для обозначения п устог о тела уп равляю щ ег о оп ератора. Н ап ример: while(getchar () ! = '\n') ; В данном случае п устой оп ератор указывает, что тело оп ератора ц икла while п усто. П риведенный фрагмент п оказывает, как мож но очистить буфер стандартног о входног о п отокап рог раммы, чтобы п рочесть новую строку. Е щ е два п ростых оп ератора - break и continue - мы рассмотрим п озж е. Т аким образом, п ростыеоп ераторы заверш аю тся точкой с зап ятой.
43 С оста вной оп ератор содерж ит друг ие оп ераторы. О н мож етвклю чать друг иесоставныеоп ераторы. Б л оком называется составной оп ератор, который содерж ит заклю ченный в фиг урные скобки сп исок составных оп ераторов (п осле закрываю щ ей фиг урной скобкиточкас зап ятой не ставится, так как это составной оп ератор). О п ераторы, содерж ащ иеся всп иске, вып олняю тся один раз вп орядкеих следования п о сп иску. Н ап ример: … .. { ++i ; а=Ь ; с=100; } Л ю бой оп ератор вязыке С мож ет быть п омечен. М еткасостоит из идентификатора, закоторым следуетдвоеточие(:). О бластью оп ределения метки является данная функц ия. М еткаслуж ит для тог о, чтобы мож но было п ерейтинаэтотоп ератор с п омощ ью оп ератораgoto. Н ап ример: loop: х=1; 4.2. О перат ор if О п ератор if называется иног да усл овным. О н исп ользуется для орг анизац ии разветвления вычислительног о п роц есса в зависимости от вып олнения некоторог о условия. О п ератор if имеетвид: if(выра ж е ние ) опе ра тор1 else опе ра тор2 г де опе ра тор1 и опе ра тор2 мог ут быть лю бым оп ератором языка C, вклю чая п ростые и составные оп ераторы, блоки (в том числе, и сам оп ераторif). К лю чевоеслово else иопе ра тор2 мог утотсутствовать. Н ап ример: if (а
44 а=0; if (a<0) а=b; else a=b; В ып олнениеоп ератораif сводится к следую щ ему: 1) вычисляется выраж ение, заклю ченноевкруг лыескобки; 2) оп ределяется факт вып олнения условия: если выраж ение имеет ненулевое значение, условие считается вып олненным (истинным); если выраж ениеимеетнулевоезначение, условиеневып олнено (лож но); 3) еслиусловие истинно, вып олняется оп ератор1, аоп ератор2 (если он есть) иг норируется; 4) если условие не вып олнено и ветви else нет, уп равление п ередается следую щ ему оп ератору п о тексту п рог раммы; 5) если условие не вып олнено и имеется ветвь else, уп равление п ередается оп ератору 2 и затем следую щ ему оп ератору п о тексту п рог раммы. Ч ащ е всег о выраж ения, которые рассматриваю тся как условия в оп ераторе if, вклю чаю т оп ерац ию п роверки на равенство и оп ерац ию отнош ения. П оскольку в качестве оп ератора1 и оп ератора2 мож ет исп ользоваться сам оп ератор if, мож но исп ользовать конструкц ии с влож еннымиоп ераторамиif, нап ример: if (выраж ение1) if (выраж ение2) if (выраж ение3) оп ератор1 Э тотп ример эквивалентен if (выраж ение1 && выраж ение2 && выраж ение3) оп ератор1 М ож но исп ользовать болееслож ныеконструкц ии, нап ример: if (выраж ение) оп ератор
45 else
if (выраж ение) оп ератор else if (выраж ение) оп ератор else оп ератор
Т акую конструкц ию удобнеезап исывать так: if (выраж ение) оп ератор else if (выраж ение) оп ератор else if (выраж ение) оп ератор else оп ератор О на п озволяет оп исать п ринятие не одног о из двух, аодног о из мног их реш ений. В ыраж ения вычисляю тся п о п орядку; если какое-либо выраж ение истинно, вып олняется соответствую щ ий оп ератор, и наэтом конструкц ия заверш ается. П ри исп ользовании влож енных оп ераторов if следует п омнить о следую щ их особенностях, вытекаю щ их из оп ределения оп ератора. 1. К л юче вые сл ова else ил и if могут име ть тол ько по одному опе ра тору, приче м он мож е т быть простым ил и соста вным. В се другие опе ра торы будут инте рпре тирова ны ка к не за висимые . Та кие опе ра торы будут огра ничива ть вл ож е нность на да нном уровне . Н ап ример: if (выраж ение) оп ератор1 оп ератор2 еlsе оп ератор3 Э та конструкц ия ош ибочная, так как оп ератор 2 будет рассматриваться комп илятором как независимый, не относящ ийся к клю чевому слову if, аналичие ветвиelse вданном случаевосп ринимается
46 комп илятором как ош ибка. Д ля тог о чтобы исп равить ош ибку, надо заклю чить оп ератор 1 иоп ератор 2 вфиг урныескобки: if (выраж ение) { оп ератор1 оп ератор2 } else оп ератор3 2. В нутри одного бл ока ка ж дое кл юче вое сл ово else относится к пе рвому изпре дш е ствующ их if, которое е щ е не име е т соотве тствующ е го else. Н ап ример: if (выраж ение1) if (выраж ение2) { оп ератор За оп ератор ЗЬ } else { оп ератор4а оп ератор4Ь } Н есмотря нато, что клю чевоеслово else зап исано с той ж еп озиц ии, что ип ервое клю чевое слово if, оно будет относиться ко второму if. Е сли требуется, чтобы else относилось к выраж ению 1, нуж но ввестиещ е один составной оп ератор, заклю чиввторой оп ераторif вфиг урныескобки. 4.3. О перат ор switch В языке С сущ ествует ещ е одна разновидность оп ератора орг анизац ииразветвленног о вычислительног о п роц ессавзависимостиот вып олнения некоторог о условия - оп ератор switch. О п ератор switch имеет следую щ ий вид: switch (выраж ение) { case конста нтное выра ж е ние 1:
47 оп ератор1а оп ератор1b … case конста нтное выра ж е ние 2: оп ератор2а оп ератор2b … case конста нтное выра ж е ние n: оп ераторnа оп ераторnb … default: оп ераторda оп ераторdb … } В этой конструкц иимог утбыть оп ущ ены частис п рефиксом default, a такж е лю бая часть с п рефиксом case или оп ераторы меж ду case (несколько case мог ут идти п одряд). В ыраж ение в скобках п осле клю чевог о словаswitch долж но п риводиться к тип у int. К онстантноевыраж ение, указываемоевп рефиксеcase, долж но быть ц елым. О но не мож ет вклю чать п еременные или вызовы функц ии. В се константные выраж ения в одном оп ераторе switch долж ны быть различными. В отличие от оп ератораif-else не требуется заклю чать вфиг урные скобки г руп п у оп ераторов, относящ ую ся к одному п рефиксу case или default. Н о нельзя оп ускать фиг урные скобки, формирую щ ие блок, п осле строкиswitch (выраж ение.). П орядок вып олнения оп ератораswitch: 1) вычисляется выраж ениевскобках п ослеклю чевог о словаswitch; 2) вычисленноезначениеп риводится к тип у int; 3) каж дая константаиз п рефиксаcase сравнивается со значением выраж ения п ослеклю чевог о словаswitch;
48 4) еслинайдется константа, совп адаю щ ая со значением выраж ения, уп равление п ередается п ервому оп ератору, следую щ ему за найденным п рефиксом case; 6) далее вып олняю тся п оследовательно все оп ераторы, относящ иеся к выбранному п рефиксу case; 7) если среди этих оп ераторовнет оп ератораbreak, п родолж ается п оследовательное вып олнение оп ераторовиз следую щ ег о п рефиксаcase и/или default, п ока не будет достиг нут оп ератор break или вп лоть до заверш ения оп ератораswitch; 8) еслисредиоп ераторов, относящ ихся к выбранному п рефиксу case, есть оп ератор break, то п ри ег о вып олнении п роисходит выход из оп ератораswitch. П оэтому оп ератором break обычно заверш аю т г руп п у оп ераторов, относящ ую ся к одному п рефиксу case; 9) если не будет найденаконстанта, совп адаю щ ая с вычисленным выраж ением, вып олняю тся оп ераторы с п рефиксом default, если он имеется; 10) если п рефикс default отсутствует и совп адения значений константы ивыраж ения небыло, то воп ератореswitch невып олняется ни один оп ератор. О сновная особенность оп ератора switch - необходимость явног о указания места, в котором п рерывается п оследовательное исп олнение оп ераторовдо конц аоп ератораswitch, п рип омощ иоп ератораbreak. Э та особенность п озволяет формировать такие конструкц ии, в которых некоторыеоп ераторы являю тся общ имисразу для нескольких ветвей case. О днако если неумыш ленно забыть оп ератор break, то п рог раммабудет вып олнять совсем не то, что хотел п рог раммист. Т аким образом, п редоставляя больш ие возмож ности п о нап исанию слож ног о и эффективног о кода, оп ератор switch, тем не менее, требует внимательности. 4.4. О перат оры орг анизации циклов. 4.4.1 О пе ра тор ц икл а while Синтаксис оп ератораwhile: while(выра ж е ние ) опе ра тор
49 г де опе ра тор - п ростой или составной оп ератор (втом числе, мож етисп ользоваться друг ой оп ератор ц икладля орг анизац иивлож енных ц иклов). В ып олняется опе ра тор до тех п ор, п ока значение выра ж е ния истинно (неравно нулю ). П роверказначения выраж ения п роисходитп еред каж дым вып олнением опе ра тора . К ог да значение выраж ения лож но (равно нулю ), вып олняется оп ератор п рог раммы, следую щ ий за опе ра тором. Е сли выраж ение лож но с самог о начала, опе ра тор не вып олняется ниразу. О пе ра тор иног даназывается те л ом ц икл а . В теле ц икладолж ны вып олняться действия, в результате которых меняется значение уп равляю щ ег о выраж ения. В п ротивном случае мож ем п олучить бесконечный ц икл. Н ап ример: while(l) а++; Значениеп еременной абудеткаж дый раз увеличиваться наединиц у, иэтот п роц есс никог дане окончится. Н адо следить затем, чтобы ц иклы заканчивались, авслучае всег даистинног о условия ц икла(как вп римере выш е) нуж но п редусмотреть выход из ц иклас п омощ ью оп ератораbreak. В ц икле while мог ут исп ользоваться довольно слож ные выраж ения, вклю чаю щ ие и оп ерац ию п рисваивания. П риведем в качестве п римера фрагментп рог раммы коп ирования вводанаэкран терминала: while((c=getchar())! =EOF) putchar(c); Здесь ввыраж енииисп ользую тся оп ерац ия п рисваивания иоп ерац ия сравнения. Т ак как оп ерац ия сравнения имеет более высокий п риоритет, чем оп ерац ия п рисваивания, то оп ерац ия п рисваивания заклю чена в скобки. Т акой сп особ зап иси выраж ения в ц икле while короче и п редп очтительнее, чем следую щ ая конструкц ия c=getchar(); while (c!=EOF) { putchar(c);
50 c=getcbar() } В этом п римере п роисходит дублирование кода, которое всег да вызывает трудности во время соп ровож дения. Гораздо п рощ е сделать изменение в одной из п овторяю щ ихся в ц икле конструкц ий, чем п росматривать всеостальные. 4.4.2 О пе ра тор ц икл а do-while В ц икле while уп равляю щ ее выраж ение п роверяется п ри входе в ц икл. В языке С сущ ествует оп ератор ц икла, в котором выраж ение уп равляю щ ееп рохож дением ц икла, п роверяется только вконц ец икла- dowhiie. О н имеетвид: do опе ра тор while (выраж ение); г де опе ра тор - п ростой или составной оп ератор языкаС (в том числе, мож ет исп ользоваться друг ой оп ератор ц икла для орг анизац ии влож енных ц иклов). В этом оп ераторе точкас зап ятой ставится п осле уп равляю щ ег о выраж ения, заклю ченног о вскобки. В оп ератореdo-while тело ц иклавып олняется п о крайней мереодин раз, не зависимо от значения уп равляю щ ег о выраж ения. Затем, если выра ж е ние истинно (не равно нулю ), тело ц икла снова вып олняется. И начеуп равлениеп ередается наоп ератор, следую щ ий п ослеdo-while. 4.4.3 О пе ра тор ц икл а for О п ератор ц иклаfor удобно исп ользовать втех случаях, ког дац икл необходимо вып олнить заданное число раз. Д ля этог о мож но восп ользоваться и лю бым из двух друг их ц иклических оп ераторов, но ц икл for лучш евсег о п одходитдля этой ц ели. О п ератор for имеетвид: for(выра ж е ние 1; выра ж е ние 2; выра ж е ние 3) опе ра тор
51 г де опе ра тор - п ростой или составной оп ератор языкаС (втом числе, мож етисп ользоваться друг ой оп ератор ц икладля орг анизац иивлож енных ц иклов). выра ж е ние 1 оп исывает иниц иализац ию ц икла; выра ж е ние 2.- п роверка условия заверш ения ц икла; выра ж е ние 3 оп исывает изменения вц икле на очередном ш аге (часто это п риращ ение счетчикац икла) и вычисляется п ослекаж дой итерац иип ослеопе ра тора . О п ератор for эквивалентен такой п оследовательностиоп ераторов: выраж ение1; while (выраж ение2) { оп ератор выраж ение3; } В ыра ж е ние 1, выра ж е ние 2 и выра ж е ние 3 не являю тся обязательными. Л ю бое из трех или все три выраж ения воп ераторе for мог ут отсутствовать, однако разделяю щ ие их точкис зап ятыми оп ускать нельзя. Е слиоп ущ ено выра ж е ние 2 (п роверкаусловия заверш ения ц икла), считается, что оно п остоянно истинно. Значит, оп ератор for вида for( ; ; ) оп ератор Е сли отсутствую т выраж ения 1 и 3, ц икл for становится эквивалентным while. К аж дое из выраж ений 1-3 мож ет быть лю бой слож ности, вклю чать оп ерац ии п рисваивания, инкремента/декремента, состоять из нескольких выраж ений, объединенных оп ерац ией зап ятая ит.д. Н ап ример: for(i=0,j=99 ; i<100 ; i++,j--) a[i]=b[j]; В этом п римере вп ервые 100 элементовмассиваa коп ирую тся 100 элементовмассиваb вобратном п орядке.
52 4.5. О перат ор break О п ератор break обесп ечиваетп рекращ ениевып олнения ближ айш ег о влож енног о или внеш нег о оп ератора switch, while, do-while, for. У п равлениеп ередается оп ератору, следую щ ему зазаверш аемым. Ф орматоп ератора break; О п ератор break исп ользуется вследую щ их случаях: 1) для п рекращ ения вып олнения ц иклаиз-заобнаруж ения ош ибки; 2) для орг анизац иидоп олнения к условию взаголовкец икла; 3) для п рекращ ения бесконечног о ц икла; 4) для п редотвращ ения вып олнения всех оп ераторовп ереклю чателя switch. 4.6. О перат ор continue О п ератор continue мож ет исп ользоваться только внутри ц иклов while, do-whiie илиfor. К ог давып олняется оп ератор continue, уп равление п ередается навычислениеусловия ближ айш ег о внеш нег о оп ераторац икла, вызывая начало следую щ ей итерац ии. Т аким образом, п ри вып олнении оп ератораcontinue все п оследую щ ие заним втеле ц иклаоп ераторы на данной итерац ииневып олняю тся. Ф орматоп ератора continue; Заметим, что оп ератор continue, встреченный внутри оп ератора switch, будетвызывать п ереход наследую щ ую итерац ию внеш нег о ц икла, если он есть. Е сли внеш нег о ц икла нет, комп илятор будет выдавать сообщ ениео синтаксической ош ибке. 4.7. О перат ор перех ода goto О п ератор goto имеетвид: goto ме тка ;
53 В результате вып олнения этог о оп ераторауп равлениеп ередается на оп ератор с меткой ме тка . Н аязыке С п рип омощ иоп ераторовц икламож но п рог раммировать лю бые ц иклические конструкц ии. П оэтому п рог раммист мож ет и не исп ользовать оп ератор goto. В частности, оп ератор goto никог даненуж но уп отреблять для п остроения ц икла. Н о в некоторых ситуац иях п ри обработке ош ибок, ког да надо, нап ример, выйти из влож енных уп равляю щ их оп ераторов, исп ользование оп ератора goto бывает ц елесообразно. О бласть действия оп ератора goto - текущ ая функц ия. Н ельзя с п омощ ью оп ератораgoto п ередать уп равлениедруг ой функц ии.
§ 5. С О С Т А В Н Ы Е Т И ПЫ Д А Н Н Ы Х 5.1. С т рукт уры Я зык С п озволяет оп ределить свой тип данных, состоящ ий из нескольких элементов разных тип ов. Т акой тип называю т структурой. С т рукт ура – это комбинированный тип , вклю чаю щ ий совокуп ность нескольких п еременных тог о илииног о тип а. У добство структуры втом, что онап озволяетрассматривать такую совокуп ность как единоец елоеи, в то ж евремя, иметь доступ отдельно к лю бой еечасти. П еременные, входящ иевсоставструктуры, называю тся ееп олями. В общ ем видеоп исаниеструктуры выг лядиттак: struct имя{ тип 1 имяпол я1; тип 2 имяпол я2; : . тип n имяпол яn; }; В место одног о имени п оля конкретног о тип а мож ет быть п еречислено несколько, через зап ятую . Д ля массивов п осле имени ставится размерность вквадратных скобках (как обычно).
54 О п исание структуры оп ределяетновый тип , ссылаться накоторый мож но п ри п омощ и двух словstruct имя (мож но сократить ссылку наструктуру до одног о словап рип омощ иоп ределения синонима для тип а(typedef)). Т ип ом п оля мож ет быть лю бой, в том числе, и структура. Э та структура долж на быть оп исанаранее или мож ет быть оп исанап рямо вместо тип а. В этом случаеимя структуры мож но оп устить, но тог дак ней нельзя будетобратиться ниг де, кромеэтог о п оля. П еременная тип а«структура» оп исывается такж е как ип еременные лю бог о друг ог о тип а: struct имя имяпе ре ме нной; Д ля работы с такими п еременными исп ользуется оп ерац ия (.), п озволяю щ ая п олучить доступ к п олю структуры. имяпе ре ме нной. имяпол я Я зык С п озволяет п ередавать п еременные тип а «структура» как п араметры функц ий и п рисваивать их друг друг у. П ри этом коп ирую тся значения всех п олей. П равильный размер структуры, как и лю бог о друг ог о тип а, мож но узнать через оп ерац ию sizeof. Е сли п араметры или возвращ аемое значение функц ии имею т тип «структура», то для исп ользования этой функц иивместе с ее п рототип ом долж но быть доступ но и оп исание самой структуры. П оэтому оно такж е обычно п омещ ается вh-файл. 5.2. О б ъединения О бъединения, как и структуры, оп исываю тся как набор п олей разных тип ов. О тличие в том, что все п оля структуры хранят одновременно свои оп ределенные значения. В объединении все п оля занимаю т одну и ту ж е область п амяти, т.е. в оп ределенный момент временизначение только одног о п оля верно. таким образом, объединение исп ользуется тог да, ког давозмож ен только один из имею щ ихся вариантов п редставления данных. П ри этом друг ие, не исп ользуемые варианты, не расходую т лиш ней п амяти. В таких случаях объединения п озволяю т экономить п амять. П еременные, входящ ие в состав объединения, называю тся ег о п олями. В общ ем видеоп исаниеобъединения выг лядиттак:
55 union имя{ тип 1 имяпол я1; тип 2 имяпол я2; : . тип n имяпол яn; }; О бщ ий размер объединения равен размеру п оля с максимальным размером. Е г о мож но как всег даузнать через оп ераторsizeof. Д ля доступ а к п олям объединения, как и к п олям структуры, исп ользуется «.». Ч тобы узнать какое из п олей объединения содерж ит п равильное значение, часто создаю т сп ец иальную п еременную , п озволяю щ ую это выяснить. Т акую п еременную называю т «тег ». Ч тобы п еременная-тег быласвязанас объединением, их удобно п оместить водну структуру. В качестве значений «тег а» часто исп ользую т символические имена, которыезадаю тп рип омощ ип еречислимог о тип а. § 6. М А С С И В Ы И УК А ЗА Т Е ЛИ 6.1. Понят ие указат еля У казат ель- это п еременная, в которой хранится не конкретное значение конкретног о тип а, аадрес некоторог о значения, хранящ ег ося в п амяти. Э тот адрес указывает, г де данное значение хранится. И сп ользуя указатель, это значение мож но п рочитать или изменить. О сновная возмож ность, которую даю т указатели – возмож ность иметь доступ к различным значениям, вклю чая значения различных п еременных, через одну и ту ж е п еременную – указатель. Д ля этог о необходимо п рисвоить указателю нуж ный адрес. В языке С указатели типизирова нные , т.е. п еременная-указатель конкретног о тип ап озволяетработать со значениямиэтог о тип а. У казатель назначения заданног о тип аоп ределяется вС следую щ им образом: имя_типа * Н ап ример, int* - это тип «указатель нац елое». П еред «*» мож но ставить п робел, амож но инеставить, так ж екак ип осленее. П еременнаяуказатель оп ределяется так ж екак друг иеп еременные. Н ап ример, int * pi;
56 Ч тобы исп ользовать указатель, ему долж ен быть п рисвоен адрес значения, на которое он будет указывать. А дрес п еременной мож но п олучить п рип омощ исп ец иальной оп ерац ии: &пе ре ме нна я О п ерац ия п олучения адресане п утается с «п обитовым И », так как онаимееттолько один оп еранд (унарная), а«п обитовоеИ » - дваоп еранда. П ри работе с указателем п росто имя п еременной обозначает указатель, ане значение, накоторое он указывает. Э тот указатель мож но сравнить с друг им на равенство, неравенство, п рисвоить друг ому или п ередать как п араметр функц ии. Н о чтобы п олучить доступ к самому значению , исп ользуется оп ерац ия ра зыме нова ния (п олучение значения п о указателю ): *имя О наобратнаоп ерац иивзятия адреса&. Е сли п оп ытаться исп ользовать оп ерац ию разыменования для указателя, не содерж ащ ег о п рисвоенный ранее п равильный адрес, то п рог рамма скорее всег о «уп адет» п о ош ибке чтения или зап иси п о недоп устимому адресу. Э то п роизойдет п отому, что неиниц иализированный указатель, как и п еременные друг их тип ов, содерж ит«мусор». В о внутреннем п редставленииуказатели– это ц елыечисла, которые являю тся номерами ячеек п амяти комп ью тера. Н улевая ячейка п амяти всег данедоп устимадля исп ользования, п оэтому нулевой указатель мож но исп ользовать вкачестве п ризнакатог о, что этот указатель не содерж ит каког о-либо п равильног о адреса, т.е. никудане указывает. Э то важ но, так как п ри нап исании п рог рамм указатели часто исп ользую тся так, что они указываю т, то наодни, то надруг иезначения, то временно вообщ еникуда неуказываю т. Ч тобы отличить п оследню ю ситуац ию , исп ользую тнулевой указатель. Е г о вводим искусственно. П росто исп ользовать ноль вкачестве нулевог о указателя не вп олне корректно, так как ноль – это число, ауказатель – это самостоятельный тип , который хоть иявляется внутричислами, но с точкизрения языкаС несет друг ую нагрузку. В о мног их вклю чаемых файлах (h-файлах) стандартной библиотеки, в том числе stdio.h, оп ределено имя NULL,
57 которое и необходимо исп ользовать для п рисвоения и сравнения нулевог о указателя. Н ап ример: #include <stdio.h> : int*p=NULL; /*p вначаленеуказываетникуда*/ : if (p!=NULL) /*еслиp куда-то уж еуказывает, то ег о мож но исп ользовать*/ : К ак известно, хранящ иеся в физической п амяти комп ью тера единиц ы инули, расп олож енные водной итой ж е ячейке п амяти, мог ут трактоваться п о-разному: как int, как float, как char. У казатели соответствую щ их тип овмож но установить наодин итот ж е адрес, п осле чег о разыменование данног о указателя п озволяет обратиться к ячейке п амяти как к значению соответствую щ ег о тип а. У казатели разных тип ов мож но п рисваивать друг друг у, однако для этог о необходимо явное п риведениетип а, нап ример: int i; int*pi; float*pf; : pi = & i; pf = (float*) pi; *pf = 3.14; Т еп ерь значение 3.14 в двоичном виде будет занесено в ячейки п амяти, занимаемыеп еременной i. В языке С есть ещ е один тип указателя – void*. Ф актически, это не тип изированный указатель. Д ля указателя тип аvoid* нельзя исп ользовать оп ерац ию разыменования для чтения илип рисвоения значения, так как тип этог о значения неизвестен. Зато, указатель void* мож но п рисваивать указателю налю бой тип инаоборотбезо всяких оп ерац ий п реобразования тип ов. Void* мож но исп ользовать для п ромеж уточног о хранения указателя лю бог о тип а. У казателичащ евсег о исп ользую тся:
58 для п ередачи п араметров по ссылке, т.е. ког да необходимо, чтобы функц ия мог ла изменить значение п араметра так, чтобы это изменение сохранилось п ри выходе из нее (п ри п ередаче п араметровп о значению вфункц ииисп ользуется коп ия п араметраиона п оэтому немож етизменить ег о так, чтобы это сохранилось п ривыходе); для работы с динамической п амятью . П од динамической п амятью п онимается п амять, которую мы резервируем не п ри нап исании п рог раммы, авыделяем уж евмомент, ког дап рог раммавып олняется. Э то требуется, ког да заранее неизвестно, сколько п амяти будет нуж но и оп ределяется это уж е только п ри вып олнении п рог раммы. Н ап ример, п ользователь вводит массив такой какой он хочет. В этих ситуац иях п рог рамма вызывает стандартную функц ию и п ередает ей п араметром столько п амятисколько нуж но. Э тафункц ия находит свободную область п амяти вкомп ью тере, резервирует ее для нас и возвращ ает указатель на нее, чтобы мы п олучилик ней доступ . Т ак как мы заранеенемож ем знать, г де эта п амять будет выделена, работа с ней возмож на только через указатели(т.е. ееадрес); для удобства обращ ения к разным участкам области п амяти, п еремещ ая указатель п рип омощ иадресной арифметики. О дин из самых п ростых п римеровисп ользования указателей – это п ередача в функц ию п араметров п о ссылке. В С нет тип а «ссылка на объект», есть только указатели. Соответствую щ ий п араметр функц ии необходимо оп ределить, как указатель нануж ный тип , ап ри ее вызове п ередавать нуж ный адрес. Н ап ример: int func(int*param) { : *param = … .; /*меняем что-то*/ } : void main(… ) { int k; i = func(&k); /*п еременная k будетизменена*/ }
59 Я зык С п озволяет оп ределить указатель на указатель, указатель науказатель науказатель и т.д. Д ля этог о ставятся доп олнительные «звездочки» в оп исании тип а. В этих случаях п ри разыменованииуказателя ставятся одна, две, триит.д. «звездочки». 6.2. М ассивы 6.2.1 Понятие ма ссива М ассив – это п оследовательность заданног о количествазначений оп ределенног о тип авп амяти. П еременная оп ределяется как массив, если п осле ее имени вквадратных скобках указывается размерность массива, нап ример: int m[10]; оп исывает массивиз 10 элементовтип аint. Разм ерност ь м ассива – это ц елое п олож ительное число. П од массивотводится заданное количество значений вп амятирасп олож енных п одряд друг задруг ом. Д ля доступ ак конкретному элементу массиваисп ользуется оп ерац ия индексирования: имя[инде кс] г де инде кс – выраж ение ц елог о тип а. И ндекс задает смещ ение от начала массива, п оэтому п ервый элемент всег даимеет индекс 0, ап оследний – размерность массиваминус 1. Э то необходимо учитывать п ри работе с массивами. С не п роверяет выход индексазаг раниц у массивап риобращ ениик ег о элементам. П ри нап исании п рог раммы мы мож ем обращ аться за п ределы массива. В результатебудетзап орченаячейкап амяти, следую щ ая замассивом, имож ет п роизойтивсе что уг одно: начиная от неп онятных эффектоввработе п рог раммы и до ее «п адения». П оэтому необходимо внимательно следить заиндексамимассивов. И мя п еременной-массива в С мож ет быть исп ользовано без квадратных скобок. В этом случае оно означает указатель на п ервый элемент массиваилиуказатель наобласть п амяти, вкоторой размещ ается массив. Э тот указатель доступ ен начтение, но п рисваивать ему друг ое значениенельзя. М ассивы иуказателивС очень тесно связаны. П одробнее мы рассмотрим это вадресной арифметике.
60 Я зык С п озволяет оп ределять такж е массивы массивов, в результате чег о п олучаю тся мног омерные массивы. М ног омерный массив оп ределяется так ж е как одномерный, но указывается нуж ное число размерностей, каж дая в своих квадратных скобках. Н ап ример: int a[10][20][5]; будет трехмерным массивом. К оличество размерностей (измерений) не ог раничено. Д ля доступ ак элементу мног омерног о массиваисп ользуется нуж ноеколичество квадратных скобок с индексами, нап ример: a[i][j][k]=0; Ф актическизап ись int a[10][20][5] означает10 массивов, состоящ ие из 20 массивов, каж дый из которых, всвою очередь, содерж ит5 элементов тип аint. П риобращ енииa[i][j][k] будет означать один элемент тип аint, a[i][j] – массивиз 5 элементовтип аint (адрес п ервог о элемента), a[i] – 20 массивовиз 5 элементовтип аint. М ассивы мог ут быть п араметрами функц ии. В этом случае размерность указывать необязательно. В место этог о мож но указать п устые квадратные скобки []. П ри этом функц ия смож ет работать с массивами лю бой размерности. О днако, для работы с такимимассивамией необходим ещ еодин ц елочисленный п араметр – размерность массива. С п ередачей двумерных и мног омерных массивов дело обстоит слож нее. В них мож ет быть не задан только п ервый размер, остальные долж ны быть известны. И наче комп илятор не смож ет оп ределить, как п равильно интерп ретировать индексирование. П одробнее эта п роблема рассматривается вадресной арифметике. И ниц иализирую тся массивы следую щ им образом. Н аиболееп ростой сп особ иниц иализац иимассива- это п еречисление элементоввфиг урных скобках, нап ример double d[2]={3.15,9.81}; Е слип оследние элементы нули, то п ризап исивфиг урных скобках онимог утбыть оп ущ ены, нап ример int a[5]={1,2,3}; П ри иниц иализац ии массива мож но такж е не указывать ег о размерность. В этом случае комп илятор сам считает размерность массива п о количеству значений виниц иализаторе:
61 int m[] = {1,2,3,4}; В данном случаебудетмассивиз четырех элементов. Д ля тип а«массив», как идля друг их тип ов, мож но задать синоним п ри п омощ и конструкц ии typedef. В этой конструкц ии имя тип а указывается наместеименип еременной, нап ример typedef double matrix[20][20]; Здесь оп ределяется новый тип matrix – двумерный массив размерности20 на20 чисел double. Т еп ерь мож но зап исывать так: matrix m; П олучилимассивdouble m[20][20]. 6.2.2 С троки ка к ма ссивы В ыш еуж еуп оминалось о том, что строкавС – это массивсимволов тип аchar, заверш аю щ ийся символом с кодом 0. П оэтому, чтобы хранить строку, нуж но знать каког о онаразмерап о максимуму изарезервировать п од нее массив данног о размера п лю с 1 (1 на заверш аю щ ий ноль), нап ример в char name[20]; п еременная name мож ет хранить строки длиной до 19 символов. Д ля хранения строк п роизвольног о размера мы мож ем восп ользоваться техникой создания динамическог о массива, которая будетоп исанадальш е. Д ля массивовтип аchar п редусмотрен особый сп особ иниц иализац ии массива: сп раваотзнакап рисвоения мож но указать строку вкавычках: char name[20] = “ И ван”; В этом случае name[0]==’И’, name[1]==’в’, name[2]==’а ’, name[3]==’н’, name[4]==’0’. Д ля доступ ак конкретному символу строки исп ользуется оп ерац ия индексирования. Н ап ример, мож но нап исать функц ию , которая заменяет встроке-п араметре все символы п робелы на символ п одчеркивания, п ользуясь тем, что строказаверш ается нулем: void spacetoul (char str[]) { int i; for (i=0; str[i]; ++i) if (str[i]= =’ ‘) str[i]=’_’;
62 } Н а самом деле, вместо оп исания п араметра str как массива, п равильнее ег о оп исать как указатель на char (char*str). П онятие «указатель на char» охватывает больш е случаев п редставления строки: динамическивыделенная п амять возвращ ается через указатели, вкачестве указателя наchar рассматривается лю бая константная строкавп рог рамме (строкавкавычках). О днако зап исанную ранее функц ию spacetoul нельзя вызывать со строкой в кавычках в качестве п араметра, так как она изменяет содерж имое строки, атакая п оп ыткадля константной строкив кавычках некорректна. К онстантнымистрокамимож но иниц иализировать п еременныетип а char, нап ример char*constname = “ В адим”; Здесь вызов функц ии spacetoul(char*constname) п о-п реж нему некорректен. У добство строки, заверш енной нулем, в том, что такой формат п озволяет хранить строкинеог раниченной длины, хотя саму длину мож ет оказаться оп ределить довольно долг о (надо п осчитать количество символовдо нуля – это делаетстандартная функц ия strlen()). 6.3. А дресная ариф м ет ика Я зык C кроме п рисвоения указателю адреса п еременной (через оп ерац ию &) и друг ог о указателя, сравнения указателей наравенство и неравенство, п озволяет такж е п рибавлять и вычитать ц елочисленные значения к указателю , сравнивать 2 указателя на больш е и меньш е и вычитать их друг из друг а. Э тивозмож ностиназываю та дре сной а риф ме тикой. Приба вл е ние к указателю ц елог о числаозначаетсме щ е ние указателя назаданное количество ячеек п амятивпе ре д, авычита ние ц елог о числа– смещ ение на за д. П ричем размер ячейкиравен размеру тог о тип аданных, накоторый оп ределен указатель. П усть, нап ример, вп амятип оследовательно хранятся ц елыечисла, и нанекотороечисло указываетуказатель p:
63
p
… p-1
p+2
int
int
int
int
…
p+1
Т ог да п рибавление к p 1 даст указатель на следую щ ий элемент, п рибавление 2 – наэлемент через один, вычитание 1 – нап редыдущ ий элементит.д. Д ля доступ ак такому элементу, смещ енному наi ячеек относительно указателя, исп ользуется оп ерац ия разыменования следую щ им сп особом: *(p+i) Здесь скобки необходимы, т.к. п риоритет оп ерац ии * выш е, чем оп ерац ии+. Я зык C п озволяет исп ользовать и более короткую зап ись, с исп ользованием оп ерац иииндексирования: p[i] Т аким образом, оп ерац ия индексирования п рименимане только к массивам, но к лю бым друг им указателям (мы г оворили, что имя массива есть указатель наег о п ервый элемент). Т о есть зап ись m[0] для массиваm означаетсмещ ениенануль ячеек относительно ег о п ервог о элемента. И менно п оэтому массивы в C индексирую тся с нуля. В место оп ерац ии разыменования указателя *p мож но такж е исп ользовать p[0], но втакой ситуац иизап ись *p корочеиболееп онятна. Т аким образом, п ри п ередаче массивавфункц ию мы фактически п ередаем указатель наег о п ервый элемент. Э то даетвозмож ность работать с массивами лю бой длины, п рименяя к указателю оп ерац ию индексирования. П оэтому п ри нап исании функц ий, п ринимаю щ их через п араметры массивы, вместо тип а «массив» мож но исп ользовать тип «указатель». И склю чение составляю т мног омерные массивы, вкоторых комп илятору долж ны быть известны все размерности массива, кроме одной. Т ак, п риоп исаниип араметракак int m[][] идоступ ак нему через m[i][j], [i][j] будут рассмотрены как две оп ерац ии индексирования, и это
64 будет эквивалентно *(*(m+i)+j), т.е. как будто бы вi-м элементе массивахранится указатель наэлементы друг ог о массива, и j-й элемент этог о массиваиесть нуж ный нам m[i][j]. Графическиэтакартинавыг лядиттак: m[0] m
m[i][0]
m[i][j]
m[i]
Т .е. как будто бы m – это массивуказателей намассивы тип аint. Н о двумерныемассивы хранятся вп амятип о строкам, значения одной строки сразу следую т задруг ой. Н икаких указателей там нет. П оэтому п оп ытка п ередачи двумерног о массива, нап ример int m[5][10], как п араметраint m[][], п риведетк ош ибкеп ривып олнениип рог раммы. Е слиж еоп исать п араметркак int m[][10], то комп иляторбудетзнать, что m - это двумерный массив, который хранится п о строкам, п ричем в каж дой строке 10 элементов. И оп ерац ия m[i][j] будет трактоваться комп илятором как *(m+i*10+j). Е сли все ж е необходимо исп ользовать в качестве п араметра мног омерные массивы, для которых на этап е комп иляц ии неизвестно больш ей одной размерности, необходимо явно в тексте п рог раммы исп ользовать доступ п о этой схеме, т.е. п исать *(m+i*N+j) вместо m[i][j] для матриц ы с N столбц ами, г де N п ередается как ещ е один п араметр функц ии. Заметим, что зап ись int m[][] насамом деле и обозначает массив указателей на int. О на эквивалентна зап иси int *m[], которая лучш е отраж ает то, что есть насамом деле. М ассивы указателей исп ользую тся для создания динамических мног омерных массивов. Э то мы рассмотри п одробнеениж е. О тметим ещ е раз, что в оп ерац иях адресной арифметики п рибавление/уменьш ение адреса, который содерж ит указатель, вып олняется с учетом ег о тип а. Т .е. еслимы имеем, нап ример, указатель int*, то п рибавление к нему 1 сместит реальный адрес ячейкип амятина
65 sizeof(int) байт (4 байта для п роц ессораPentium), аесли это указатель наchar, смещ ениеп роисходитна1 байт(sizeof(char)). В озмож ность изменения п еременной-указателя удобно исп ользовать, нап ример, для п роходап о элементам массива. Н аш у функц ию spacetoul из п . 6.2.2 мы мог либы нап исать итак: void spacetoul(char *str) { char *p; for(p = str ; *p ; p++) if(*p == ‘‘) *p = ‘_’; } Здесь указатель p п оследовательно «п робег ает» п о всем символам строки, п оканевстретится нуль (несработаетп роверка*p). И ног да оп ерац ии автоинкремента/автодекремента указателя п рименяю т вместе с разыменованием. Здесь надо п омнить, что п риоритет оп ерац ий ++ и– выш е, чем оп ерац ии*, ивконструкц иях *p++ ++*p *p---*p изменяется не значение, ауказатель, а* уж е п озволяет выбрать значение до или п осле изменения указателя. Ч тобы изменить не указатель, а значение, *p необходимо заклю чить вскобки, нап ример (*p)++. У казателимож но сравнивать набольш е именьш е. Т от указатель из двух, который указывает наячейку с больш им относительным индексом, всег дабольш е. Слож ение ивычитание двух указателей – оп ерац ия вобщ ем случае бессмысленная. О днако, п ользуясь тем, что указатели реально содерж ат адресаячеек п амятикомп ью тера, выраж енныевбайтах, мож но п ривести2 указателя к тип у int ип олучить разниц у вбайтах. Затем, зная размер тип а указателя, мож но узнать и расстояние меж ду ними, выраж енное в количествеячеек данног о тип а. Н ап ример, еслиm – массивтип аint, аp – указатель накакой-то из ег о элементов, то индекс этог о элементамож но оп ределить из выраж ения ((int)p – (int)(void *)m)/sizeof(int)
66 Здесь п риведение тип а (void*)m абстрагирует от тог о, что m является массивом, итрактует ег о как «п росто указатель», т.е. как п росто адрес ячейкип амяти. З а ме ча ние . Э таформулавнекоторых случаях мож ет не работать в О С MS-DOS. В MS-DOS сущ ествует такое п онятие, как модель п амяти. Сог ласно моделип амяти, указатель мож етиметь модификатор: near – «ближ ний» указатель, т.е. указатель в п ределах одног о сег ментап амятив64 К байт; far – «дальний» указатель, мож етссылаться кудауг одно. В MS-DOS near указатель имеетразмер 2 байта, аfar – 4 байта. Сам модификатор указателя мож ет указываться меж ду тип ом и *, нап ример char far *p – дальний указатель на p. Ближ ние и дальние указатели смеш ивать нельзя, и в наш ей формуле п равильно было бы сначала п ривестиобауказателя (p иm) к тип у void far *. В се сказанное о моделях п амятиотносится только к MS DOS (или Windows 3.x, которая является надстройкой для DOS). В друг их оп ерац ионных системах п роблемы с видамиуказателей нет, асловаnear и far неявляю тся стандартнымидля языкаC. 6.4. И спользование указат елей У казатели – очень мощ ный инструмент языка C. Сущ ествует достаточно мног о сп особовисп ользования указателей. О дин из очевидных вариантовсоответствуетназванию указателей: исп ользовать их для ссылки одног о объекта данных на друг ой. П ри этом в зависимости от п отребностей п рог раммы мог утстроиться самые разнообразные варианты взаимосвязанных данных: сп иски, деревья, г рафы итак далее. О днако, есть ещ е ряд ситуац ий, ког да п рименение указателей необходимо. Э тиситуац иирассматриваю тся вданной г лаве. 6.4.1 Пе ре да ча па ра ме тров по ссыл ке К ог данеобходимо, чтобы функц ия мог лаизменить значения своих п араметров, ане только вернуть одно значение оп ератором return, такие п араметры оп исываю тся как указатель на соответствую щ ий тип , а п ри вызовефункц иивнееп ередается адрес нуж ной п еременной.
67 Н ап ример, один из случаев, ког да всег да необходимо п ередавать п араметр через указатель – это вызовстандартной функц ииscanf, которая вводит данные со стандартног о вводап рог раммы (с клавиатуры). П ервым п араметром вscanf п ередается форматная строка, авторым – адрес п еременной, которую необходимо ввести, нап ример: printf(“ введитеn:\n”); scanf(“ %d”,&n); Е слифункц ия имеет п араметр, оп исанный как указатель, тог даона мож етизменить значениеп араметра. Рассмотрим двап римера: void func(int *n) void func(int n) { { *n = 10; n = 10; } } void func2() { int n; func(&n); /* n будетизменена*/ }
void func2() { int n; func(n); /* n не мож ет быть изменена*/ } В п равом столбц евфункц ииfunc() создается копия п еременной n (в стеке), и ее изменения нап еременную n вфункц ииfunc2() п овлиять не мог ут. В п ервом ж еслучаеп араметром func() п ередается адрес п еременной n вфункц ииfunc2(), ип утем разыменования указателя func() имеетдоступ неп осредственно к этой п еременной. М ассивы всег дап ередаю тся через указатель (т.к. имя массиваесть указатель наег о п ервый элемент). П оэтому функц ия п ри п рисваивании элементам массивановог о значения всег даизменяетисходный массив. Е сли функц ия п олучает входным п араметром указатель и долж на изменить ег о, то вместо самог о указателя надо п ередавать ег о адрес, т.е. указатель науказатель. З а ме ча ние . Е сли п араметр функц ии оп исан как указатель, это не означает, что п ри ее вызове обязательно указывается адрес какой-то п еременной. Н а самом деле в функц ию мож ет быть п ередан какой-то сущ ествую щ ий ранееуказатель.
68 6.4.2 Д ина миче ское ра спре де л е ние па мяти В реальных п рог раммах часто оказывается слож но заранее оп ределить, сколько п еременных каког о тип а, или какой размерности массивы необходимо зарезервировать в тексте п рог раммы. Э то мож ет оп ределяться только наэтап е вып олнения п рог раммы, взависимости от выборап ользователя п рог раммы илиотдруг их обстоятельств. К рометог о, некоторые объекты п амяти мог ут быть нуж ны только вкакой-то момент работы п рог раммы. В друг их случаях онимог ут быть бесп олезны илиш ь занимать п амять зря. В таких случаях исп ользуется дина миче ское ра спре де л е ние па мяти. Д инамическое расп ределение п амяти – это ког да п амять п од п еременную или массив выделяется в оп ределенный момент времени работы п рог раммы, а не заранее, п утем резервирования п еременной в тексте п рог раммы. Д инамически выделенная п амять мож ет быть освобож денавлю бой моментвремени, сразу, как только онастановится не нуж на. Н икакая реальная п рог рамма обычно не обходится без динамическог о расп ределения (выделения иосвобож дения) п амяти. Ч тобы динамически выделить п амять, в языке C необходимо восп ользоваться функц ией стандартной библиотекиmalloc илиcalloc. Э ти функц ии оп исаны в заголовочных файлах stdio.h или stdlib.h, один из которых необходимо вклю чить в п рог рамму, чтобы п ользоваться динамическим расп ределением п амяти. Ф ункц ия malloc имеетодин п араметр: размер выделяемой областив ба йта х. Э та функц ия находит в п амяти комп ью тера свободный блок заданног о размераи возвращ ает указатель нанег о (тип аvoid *). Е сли такую область п амятивыделить неудается, malloc возвращ аетNUL. malloc ничем не зап олняет выделенную область п амяти, т.е. она содерж ит неоп ределенныезначения («мусор»). Т ак как malloc п ринимает размер вбайтах, то п рип одсчете размера выделяемой п амятиудобно исп ользовать оп ерац ию sizeof. Рассмотрим п ример динамическог о выделения п амяти п од структуру: #include <stdio.h>
69 … … … … struct a { int i; char c[30]; double d; }; … … … … struct a *s; if((s = malloc(sizeof(struct a))) == NULL) { /*!*/ printf(“ Н ехватаетп амяти!\n”); /* обработкаош ибкивыделения п амяти*/ return … } /* Т еп ерь п амять п од структуру выделенаимы мож ем обращ аться к ееп олям*/ s->i = 10; /* эквивалентно (*s).i = 10 */ strcpy(s->c, “ динамическая структура”); s->d = 3.1415; Здесь встроке, п омеченной /*!*/, вызывается функц ия malloc, чтобы выделить п амять п о размеру структуры a. П роверканаNULL нуж нана случай, еслип амять окаж ется исчерп ана(хотя нап рактикетакая ситуац ия встречается достаточно редко, чащ е malloc возвращ ает NULL вслучае, ког да зап рош ен отриц ательный, нулевой или недоп устимо больш ой размер). Т от факт, что выделяемая malloc п амять содерж ит «мусор», не удобен. П оэтому выделенную п амять чащ е всег о сразу как-то иниц иализирую т. В наш ем п римере мы явно п рисвоили оп ределенные значения п олям структуры (функц ия strcpy коп ирует строку из второг о п араметравп ервый). И ниц иализировать участок п амяти одним и тем ж е байтовым значением мож но п рип омощ ифункц иистандартной библиотекиmemset. Н ап ример, п одходящ им значением во мног их случаях оказывается нуль. О бнулить п оля наш ей структуры мы мог либы так: memset(s, 0, sizeof(struct a));
70 П ервым п араметром в функц ию memset п ередается указатель на область п амяти, вторым – значение байта (от 0 до 0xff), третьим – размер области в байтах (в результате все байты п олучаю т одинаковыезначения). Т ак как необходимость зап олнения выделенной п амяти нулями встречается часто, встандартной библиотеке есть сп ец иальная функц ия calloc, которая выделяет п амять и сразу обнуляет ее. У этой функц ии, в отличие от malloc, двап араметра: размер элементавбайтах иколичество элементов. Т о есть функц ия calloc ориентировананавыделение п амяти сразу п од несколько элементов одинаковог о размера (а значит, как п равило, и тип а), и врезультате мы п олучаем динамически созданный массивэлементов. Д инамическиемассивы мы рассмотрим п озж е. В наш ем ж е случае для выделения п амяти п од структуру struct a мы мог ли бы зап исать s = calloc(sizeof(struct a),1) Н асамом деле calloc работаетчерез malloc п римерно так: void *calloc(unsigned long size, unsigned long cnt) { unsigned long n = size*cnt; void *p = malloc(n); if(p == NULL) return NULL: memset(p, 0, n); return p; } К ог дадинамическивыделенная п амять п рог раммебольш ененуж на, ее мож но освободить п рип омощ истандартной функц ииfree, п араметром которой п ередается указатель наобласть п амяти, нап ример: free(s); Ф ункц ия free ничег о не возвращ ает. Е й не надо п ередавать размер выделенной ранееп амяти, онамож етузнать ег о сама. Секретздесь кроется втом, что функц ииmalloc иfree работаю твп аресо сп иском свободных и занятых блоков п амяти, отведенных п рог рамме. Э ти блоки называю т «кучей» (от анг л. heap), т.к. всредиэтих блоковвп роизвольном п орядке выделяется п амять п од данные разных тип ов, как бы внутри все
71 сваливается в одну кучу. У каж дог о занятог о блока есть внутренняя информац ия о ег о размере, которую иисп ользует free. П осле освобож дения п амяти free п о возмож ности сливает меньш ие участки свободной п амятивболеекруп ный неп рерывный блок, т.е. функц ииfree и malloc оп тимизирую тработу со свободной п амятью внутрисебя. О днако бол ьш ие не приятности возникнут, если в функц ию free п ередать указатель, который не был п олучен функц ией malloc илиcalloc (или realloc – см. далее), либо п ередать указатель на область п амяти, которая уж ебылаосвобож денаfree. Здесь язык C требуетвнимательности со стороны п рог раммиста, стремясь максимально п овысить п роизводительность п рог раммы вущ ерб защ ищ енностиот неп равильных действий п рог раммиста: если п рог раммист нап исал что-то не так, то п рог раммап росто «уп адет» (аварийно заверш ится). Е сливп роц ессе работы п рог раммы оказывается, что размераранее выделенной области динамической п амяти недостаточно, то ее мож но п еревыделить п ри п омощ и функц ии realloc, у которой двап араметра– указатель настарую область п амятиитребуемый размер новой областив байтах. Ф ункц ия realloc выделяет новую область, коп ирует в нее содерж имое старой области, п осле чег о освобож дает старую область и возвращ ает указатель нановую область (есливыделить новую область не удается, возвращ ается NULL истарая область остается неизменной). Е сли вфункц ию realloc п ередать неп равильный указатель, то она, как ифункц ия free, аварийно заверш итп рог рамму. Н еобходимо п омнить, что указатель, возвращ аемый функц ией realloc, отличается от старог о указателя. П оэтому, еслинаобласть п амяти ссылались несколько указателей, то всеих необходимо п ереп рисвоить. З а ме ча ние . В языке C++ для динамическог о выделения и освобож дения п амяти вместо malloc/free ц елесообразнее исп ользовать оп ерац ииnew иdelete, которыеявляю тся частью языка. Ф ункц ииmalloc и free входятвстандартную библиотеку языкаC, но невходятвсам язык. 6.4.3 Д ина миче ские ма ссивы Т ак как указателимож но индексировать, то реализовать одноме рные дина миче ские ма ссивы очень лег ко: надо лиш ь выделить п амять п од нуж ное количество элементов N заданног о тип а (т.е. область п амяти
72 размера N*sizeof(тип ) байт), п осле этог о п олученный указатель мож но индексировать, обращ аясь к нему как к обычному массиву. Н адо только не забыть освободить п амять, ког да массив становится не нуж ен. Е сли п ри работе окаж ется, что размер массива недостаточный, ег о мож но увеличить п рип омощ ифункц ииrealloc. С многоме рными дина миче скими ма ссива ми ситуац ия слож нее: мы не мож ем выделить неп рерывный участок п амяти и п равильно индексировать ег о несколькими индексами. Н ап ример, чтобы п равильно обработать индексы [i][j], комп илятор долж ен знать, сколько элементовв каж дой строке двумерног о массива, а в конструкц ии [i][j] такой информац ии нет (вп . 6.3 этап роблемауж е обсуж далась). К ог дамассив статический, комп илятор мож ет взять эту информац ию из ег о оп исания (нап ример, вмассиве int m[5][10] вкаж дой строке п о 10 элементов).Д ля динамическог о массиватаког о сп особанет. О днако сымитировать мног омерный динамический массивмож но через массивуказателей. Рассмотрим указатель науказатель double **m. Е сли выделить динамически п амять п од N указателей наdouble, адля каж дог о их этих указателей выделить п амять п од M элементовтип аdouble, мы п олучим следую щ ую схему:
0 m i 0
M-1
N-1
Т о есть мы как бы имеем матриц у NxM, г де каж дая из N строк хранится в виде отдельног о массива, на который указывает соответствую щ ий элемент всп омог ательног о массива указателей m. И индексирования m[i][j] всег дабудетработать п равильно! Т аким образом, через массивуказателей мы мож ем сымитировать двумерный динамический массив. К од, который выделяетп амять п од нег о, мож етвыг лядеть так: typedef double **DynMatrix;
73 DynMatrix alloc_matrix(N int, M int) { int i; DynMatrix m = calloc(sizeof(double*),N); if(m == NULL) return NULL; for(i = 0 ; i < N ; ++i) if((m[i] = calloc(sizeof(double),M)) == NULL) { /* неудача: освободить сначалауж ето, что усп еливыделить */ for(--i ; i>=0 ; --i) free(m[i]); free(m); return NULL; } return m; } М ы оп ределили для тип а double** синоним DynMatrix (динамическая матриц а). Ф ункц ия alloc_matrix выделяет п амять п од матриц у размерности NxM. В случае неудачи возвращ ается NULL (п ри этом освобож дается вся лиш няя п амять, которая уж е былавыделенак моменту неудачи). В случае усп еха возвращ ается указатель, который мож но индексировать как обычный двумерный массив. Д ля освобож дения таког о массиванеобходимо сначалаосвободить п амять, занимаемую каж дой строкой, азатем уж есам массивуказателей: for(i = 0 ; i < N ; ++i) free(m[i]); free(m); Т рех- и более мерные динамические массивы мог ут быть реализованы аналог ично двумерным, п рип омощ имассивовнауказатели намассивы указателей. В заклю чение отметим, что так как строкиявляю тся одномерными массивами тип аchar, то для работы с динамическими строками мож но
74 исп ользовать ту ж е технику, что и для обычных массивов (не забывая только, что вконц е строки всег дарасп олагается символ 0, п од который тож енадо отвестиместо). А массивуказателей наchar (тип аchar **) мож етисп ользоваться как динамический массивстрок.
§ 7. ПРЕ ПРО Ц Е С С О Р 7.1. О сновны е сведения Пре проц е ссор п озволяет осущ ествлять макрообработку, условную комп иляц ию , вклю чать файлы втекст п рог раммы, уп равлять обработкой ош ибок П ервым ш агом комп илятора является вызов п реп роц ессора. Д ирективы п реп роц ессоракодирую тся висходной п рог рамме так ж е, как обычные оп ераторы языкаС, но п реп роц ессорные директивы отличаю тся от обычных элементов п рог раммы п о форме: они не следую т синтаксически п равилам для оп ераторов. Д ля зап иси п реп роц ессорных директивсущ ествую тсвоип равила: 1) всеп реп роц ессорныедирективы долж ны начинаться с символа# ; 3) засимволом # следуетнаименованиедирективы. В п рог раммах на С исп ользую тся следую щ ие директивы п реп роц ессора: #include, #define, #if, #else, #endif, #line,#undef, #ifndef, #ifdef. В седирективы п реп роц ессора неявляю тся клю чевымисловамиязыкаС; 4) в отличие от оп ераторов директивы не заверш аю тся точкой с зап ятой. Д ирективы не являю тся оп ераторами языка в традиц ионном смысле. П осле работы п реп роц ессора директивы удаляю тся из текста п рог раммы. Д ирективы мог утбыть разделены натрикатег ории: 1) вклю чениефайла; 2) макроп одстановка; 3) уп равлениекомп иляц ией. 7.2. В клю чение ф ай ла Различные объектные модули мог ут объединяться с п омощ ью редактора связей (комп оновщ ика). П реп роц ессорная директива #include вып олняет аналог ичную , но более п ростую функц ию объединения
75 директиве мы уж е уп оминали в
исходных файлов. О б этой п . 1.2.1. О наимеетвид: #include "имя файла" или #include <имя_файла> Д иректива #include заменяется в тексте п рог раммы содерж имым файлас заданным именем. Е сли имя файлазаклю чено вкавычки, файл ищ ется втекущ ем каталог е п ользователя; если имя файлазаклю чено в уг ловые скобки, - встандартном каталог е системы. П онятия текущ ег о и стандартног о каталог ов, атакж е действия вслучае необнаруж ения файла оп ределяю тся реализац ией. Д оп ускаю тся влож енныедирективы #include. 7.3. М акроподст ановка 7.3.1 Проста яма кроподста новка Ч асто п олезно иметь возмож ность указывать значения константы без явног о ее нап исания. Я зык C п озволяет исп ользовать для этог о п ростую макроп одстановку. П ростая макроп одстановкаимеетследую щ ий вид: #define иде нтиф ика тор строка Иде нтиф ика тор строится по п равилам образования идентификаторов в языке С. К онец идентификатора оп ределяется п о п оявлению п ервог о символап робела. И дентификатор вдирективе #define иног даназываю тсимвол иче ской конста нтой. П осле тог о как директива#define обнаруж енап реп роц ессором, все п оследую щ ие п оявления втексте п рог раммы идентификаторазаменяю тся соответствую щ ей строкой, за исклю чением тех случаев, ког да идентификатор п оявляется внутри двойных или одинарных кавычек. Н ап ример: #define ZERO 0 И дентификаторы, которые п оявляю тся в макроп одстановке, рекомендуется зап исывать п роп иснымибуквами, для тог о чтобы указать, что ониявляю тся символическимиконстантами. В качестве строки, исп ользуемой в директиве #define, мож ет указываться лю бая конструкц ия, доп устимая в языке С. Строка
76 размещ ается вдирективе #define п осле второг о п робела (п ервый п робел указывается п оследирективы #define). Е слизап оследним неп робельным символом встроке указывается \ (обратная наклонная черта), это означает, что строкаимеет п родолж ение наследую щ ей линии, нап ример: #define STR ((a>b||c>b)&&\ ((d%f)==0)) 7.3.2 М а кроподста новка с а ргуме нта ми П реп роц ессор п озволяет исп ользовать более слож ную и п олезную форму директивы #define: #define иде нтиф ика тор (иде нтиф ика тор,...,иде нтиф ика тор) строка г де иде нтиф ика тор символический макроидентификатор; (иде нтиф ика тор,..., иде нтиф ика тор) - сп исок п араметров; строка п одставляемая строка(обычно онавклю чаетп араметры). Н е долж но быть п робелов меж ду макроидентификатором и открываю щ ей скобкой. В п ротивном случае п реп роц ессор будет рассматривать директиву как п ростую п одстановку, асп исок п араметров трактовать как п одставляемую строку. М акроп одстановкас арг ументамиобычно исп ользуется аналог ично функц ии. И ног да макроп одстановку с арг ументами называю т псе вдоф ункц ие й или ма кроопре де л е ние м. М акроп одстановки мог ут быть влож енными. Н ап ример, мож но задать макрооп ределения UP и LOW для п реобразования латинских символовсоответственно всимволы верхнег о и ниж нег о рег истров: #define UP(c) ((c)-'a'+ 'A') #define LOW(c) ((с) -'A'+ 'а') Следуетотметить, что каж доеп оявлениеп араметравп одставляемой строке долж но заклю чаться в скобки; вся п одставляемая строка тож е долж назаклю чаться вскобки. Н ап ример, макрооп ределение, вычисляю щ ее квадрат некоторог о значения, мож но зап исать так:
77 #define SQ(x) ((x)*(x)) Зап ись этог о макрооп ределения, нап ример, ввиде #define SQ(x) x * х мож етп ривестик неверному результату. П усть мы хотим исп ользовать SQ следую щ им образом: s = SQ(a+b); П ослевып олнения макроп одстановкип олучим s = a+b*a+b; ирезультат будет неверным. Скобкиг арантирую т сохранение п риоритета вып олнения оп ерац ий. 7.4. Д ирект ива #undef Д иректива #undef ог раничивает область действия директивы #define. Д ирективаимеетследую щ ий вид: #undef иде нтиф ика тор г де идентификатор — идентификатор, ранее оп ределенный в директиве#define. Д иректива#undef исп ользуется: 1) для изменения условия вдирективе#ifdef; 2) для исклю чения дублирования макроимен. П оследний случай мож ет иметь место п ри вклю чении файлов с п омощ ью директивы #include. В клю чаемый файл мож ет содерж ать макрооп ределения. П ри такой ситуац ии возмож но дублирование имен. П реп роц ессор будет руководствоваться п ервым встретивш имся макрооп ределением. 7.5. У словная ком пиляция У сл овна я компил яц ия — это выборочная комп иляц ия только тех частей п рог раммы, которые удовлетворяю т некоторым условиям. Н ап ример, мог ут быть комп илированы только те части п рог раммы, которые относятся к оп ределенному окруж ению или к реализац ии системно-зависимых функц ий в каж дой оп ерац ионной системе п ри нап исаниип ереносимых п рог рамм. У словная комп иляц ия имеетследую щ иеп реимущ ества:
78 1) п озволяет задавать п араметры временикомп иляц ии, т.е. мож но создавать п рог раммы различной конфиг урац ии; 2) п риводит к эффективному исп ользованию п амяти, так как ненуж ный код нехранится вп амятиво время вып олнения; 3) реш ение о вклю чении той или иной части п рог раммы п ринимается на этап е комп иляц ии, а не во время вып олнения. Э то п овыш аетэффективность п рог раммы (но уменьш аетеег ибкость). Д ля условной комп иляц ииисп ользуется п реп роц ессорная директива #if. О наимеетдвеформы. 1) без else-части. за гол овок if те кст програ ммы 1 #endif 2) с else-частью : за гол овок if те кст програ ммы 1 #else те кст програ ммы 2 #endif Здесь за гол овок1 содерж ит условие, в зависимости от значения котором комп илируется те кст програ ммы 1 илите кст програ ммы 2. Заголовок_if имееттриформы. 1) #if конста нтное _выра ж е ние 2) #ifdef иде нтиф ика тор 3) #ifndef иде нтиф ика тор В п ервой форме условие оп ределяется константным выраж ением. Е сли константное выраж ение отличается от нуля, условие истинно; если равно нулю , условиелож но. В о второй форме условие истинно, если идентификатор п редварительно был оп ределен с п омощ ью директивы #define (ине было для нег о директивы #undef). В п ротивном случаеусловиелож но. В третьей форме условие истинно, если идентификатор не был оп ределен ранее с п омощ ью директивы #define (илион был оп ределен, а затем к нему былап римененадиректива#undef). П ример условной комп иляц ии:
79 #ifndef SIZE #define SIZE 128 #endif В результате оп ределяется макроп одстановка, заменяю щ ая SIZE на 128, еслиранееонанебылаоп ределенап рог раммистом. Следует заметить, что п ри исп ользовании влож енных директив условной комп иляц ии мног ие комп иляторы не доп ускаю т смещ ения вп раво влож енных директив #if, #else. О ни все долж ны начинаться с п ервой п озиц ии. ЛИ Т Е РА Т УРА 1. 2. 3. 4. 5. 6. 7. 8.
БолоскиМ .И . Я зык п рог раммирования С. – М .: Радио исвязь. 1988. – 96 с. И вановА .Г. Я зык п рог раммирования С: П редварительное оп исание / П рикладная информатика. – 1995. – В ып .1. – С. 68-113. Stroustrup B. Data Abstraction in C// AT&T Bell Lab.Techn.J. – 1992. – Vol.63, № 8. – P.1701 – 1732. Rosler L. The evolution of C – past and future // AT&T Bell Lab.Techn.J. – 1992. – Vol.63, № 8. – P.1685 – 1699. Берри Р., М икинг з Б. Я зык С. В ведение для п рог раммистов. – М .: Ф инансы истатистика, 1998. – 75 с. У эйтМ ., П ратаС., М артин Д . Я зык С: Руководство для начинаю щ их. – М .: М ир, 1998. – 512 с. Х энкок Л ., К риг ер М . В ведениевп рог раммированиенаязыкеС. – М .: Радио исвязь. 1996. – 192 с. Chirlian P.M. Introduction to C. – Beaverton: Matrix publ., 1997. – 187 p.
Составители: Глуш акова Т атьяна Н иколаевна, Е сип енко Д митрий Георг иевич, Ш аш кин А лександр И ванович, Э ксаревская М арина Е вгеньевна. Редактор: Т ихомироваО .А .