Язык Си - Уэйт, Прата, Мартин. M. уэит с. Прата д. Мартин
Скачать 4.69 Mb.
|
ИСПОЛЬЗОВАНИЕ ТИПОВ ДАННЫХ Далее Содержание Во время разработки программы вам необходимо составить список требуемых переменных и указать при этом, какого они должны быть типа. Скорее всего вы будете использовать тип int или, возможно, float для определения чисел и тип char для символов. Описывайте эти данные в самом начале тела функции, в которой они используются. Имена переменных выбирайте таким образом, чтобы они указывали на их смысл. При инициализации переменной следите за тем, чтобы тип константы соответствовал типу переменной. int apples = 3; /* ПРАВИЛЬНО */ int oranges = 3.0; /* НЕПРАВИЛЬНО */ Язык Си "рассматривает" такие несоответствия менее жестко, чем, скажем, Паскаль, но в любом случае лучше учиться избегать дурных привычек. ЧТО ВЫ ДОЛЖНЫ БЫЛИ УЗНАТЬ В ЭТОЙ ГЛАВЕ Далее Содержание В данной главе мы рассмотрели довольно большой материал. Суммируя его, мы обратим основное внимание на практическую сторону тех вопросов, которые здесь обсудили. Так же как и в предыдущей главе, мы дадим краткие примеры. Ниже приводится сводка тех фактов, которые вы должны были узнать из этой главы. Что такое основные типы данных языка Си: int, short, long, unsigned, char, float, double. Как описать переменную любого типа: int beancount, float root-beer; и т. д. Как зависать константу типа int: 256, 023, OXF5 и т. д. Как записать константу типа char: 'r', 'U', '\007', '?' и т. д. Как записать константу типа float: 14,92, 1.67е-27 и т. д. Что такое слова байты и биты. В каких случаях используются различные типы данных. ВОПРОСЫ И ОТВЕТЫ Содержание Рассмотрение приводимых ниже вопросов должно помочь вам глубже УСВОИТЬ материал данной главы. Вопросы 49 1. Какими типами вы будете пользоваться при обработке данных следующего вида а. Население Рио Фрито б. Средний вес картины Рембрандта в. Наиболее часто встречающаяся буква в тексте данной главы г. Сколько раз указанная буква встречается в тексте 2. Определите тип и смысл (если он есть) каждой из следующих констант а. '\b' б. 1066 в. 99 44 г. OXAA д. 20е30 3. Вирджила Анн Ксенопод (ВАКС) 3) написала программу с множеством ошибок Помогите ей обнаружить их: #include < stdio h> main ( float g, h, float tax, rate, g = e21, tax = rate*g, ) Ответы 1. a. int, возможно short, население выражается целым числом б. float, маловероятно, что среднее окажется целым числом в. char г. int, возможно unsigned 2. a. char, символ "шаг назад" б. int, историческая дата 4) в. float, степень чистоты после мытья г. Шестнадцатеричное число типа int, десятичное значение 170 д. float, масса Солнца в кг 3. Строка 1: правильная Строка 2: должна содержать пару круглых скобок вслед за именем main, т. е. main( ) Строка 3: нужно использовать {, а не ( Строка 4: g и h должны разделяться запятой, а не точкой с запятой Строка 5: правильная Строка 6: (пустая) правильная Строка 7: перед е должна стоять по крайней мере одна цифра: например, 1е21 или 1 0е21 Строка 8: правильная Строка 9: нужно использовать }, а не ) Недостающие строки: первая - переменной rate нигде не присваивается значеиие. вторая - переменная h нигде не используется. Кроме того, программа ни как не информирует нас о результатах вычислений. Ни одна из этих ошибок не будет служить препятствием для выполнения программы (хотя при компиляции может 50 быть выдано предупреждение о неиспользуемой переменной), но все ошибки существенно снижают эффективность программы и без того уже ограниченную. 1) В программе используются следующие единицы 1 фунт - 454 г, 1 тройская унция 31 г - Прим ред 2) Одометр - прибор для определения пройденного расстояния - Прим перев. 3) Аббревиатура этого имени совпадает с обозначением широко используемой сейчас вычислительной машины VAX (ВАКС) фирмы DEC - Прим ред. 4) Год битвы при Гастингсе - Прим перев. В этой главе мы продолжим нашу "игру" с данными покопаемся в вопросах, выходящих за пределы тех, которые были связаны с типами данных, и рассмотрим символьную строку Сначала опи шем важное средство языка - препроцессор Си - и узнаем, как задавать и использовать символические константы. Затем вновь об судим способы ввода и вывода данных, при этом более полно ис следуем возможности функций printf( ) и scanf( ). Ну, а теперь вы вероятно, ожидаете примера программы, который должен быть помещен в начале главы; мы не будем вас разочаровывать и приве дем его /* непринужденный разговор */ # define DENSITY 62 4 /* плотность тела человека в фунтах на кубический фут */ main( ) /* любопытствующая программа*/ { float weight, volume; int size, letters; char name [40]; /* или попробуйте "static char name [40], */ printf(" Привет! Как вас зовут?\n" ); scanf(" %s" , name); printf("%s, Каков ваш вес в фунтах?\n", name); scani("%f", &weight); size = sizeof name; letters = strlen (name); volume = weight/DENSITY; printf(" Прекрасно, %s, ваш объем %2 2f кубических фута.\n", name, volume); printf(" Кроме того, ваше имя состоит из %d букв,\n", letters); printf(" и для его размещения в памяти у нас есть %d байт.\n", size); } Результат работы программы "непринужденный разговор" может, например, выглядеть следующим образом: Привет ! Как вас зовут? Анжелика Анжелика Каков ваш вес в фунтах? 102,5 Прекрасно, AНЖЕЛИКА ваш объем 1,64 кубических фута Кроме того, ваше имя состоит из 8 букв и для его размещения в памяти у нас есть 40 байт 51 Перечислим основные новые черты этой программы: 1. Мы использовали "массив" для хранения "символьной строки" - в данном случае для некоторого имени. 2. При вводе и выводе строки была использована "спецификация преобразования" %s. 3. Для определения символической константы DENSITY был использован препроцессор языка Си. 4. Для нахождения длины строки была использована функция strlen( ). Способ ввода-вывода, реализованный в языке Си, может показаться вначале несколько более сложным по сравнению с вводом-выводом, предусмотренным, например, в Бейсике. Однако эта сложность окупается улучшенными возможностями управления вводом-выводом и большей эффективностью получаемых программ. Указанная трудность - не единственная, с которой вы столкнетесь в дальнейшем. Давайте исследуем все новые моменты более детально. СИМВОЛЬНЫЕ СТРОКИ - ВВЕДЕНИЕ Далее Содержание "Символьная строка" - это последовательность, состоящая из одного или более символов В качестве примера рассмотрим следующую строку: "Строки изливались прямо из сердца!" Кавычки не являются частью строки. Они вводятся только для того, чтобы отметить ее начало и конец, т.е. играют ту же роль, что и апострофы в случае одиночного символа. В языке Си нет специального типа, который можно было бы использовать для описания строк Вместо этого строки представля ются в виде "массива" элементов типа char. Это означает, что символы в строке можно представить себе расположенными в со седних ячейках памяти - по одному символу в ячейке (рис. 41). РИС. 4. 1. Строка как массив ячеек Необходимо отметить, что на рисунке последним элементом массива является символ \0. Это "нуль-символ", и в языке Си он используется для того, чтобы отмечать конец строки Нуль-символ - не цифра 0; он не выводится на печать и в таблице кода ASCII 1) имеет номер 0. Наличие нуль-символа означает, что количество ячеек массива должно быть по крайней мере на одну больше, чем число символов, которые необходимо размещать в памяти. Ну, а теперь спросим, что такое массив? Массив можно пред ставить себе как совокупность нескольких ячеек памяти, объединен ных в одну строку Если вы предпочитаете более формальные и строгие определения, то массив - это упорядоченная последова тельность элементов данных одного типа В нашем примере мы со здали массив из 40 ячеек памяти, в каждую из которых можно по местить один элемент типа char. Мы осуществили это с помощью оператора описания char name [40]; Квадратные скобки указывают, что переменная name - массив, 40 - число его элементов, a char задает тип каждого элемента. (В комментариях к программе было отмечено, что при желании вы можете воспользоваться более сложным оператором описания). static char name [40], Ввиду некоторой специфики, связанной с реализацией функции scanf( ) в нашей системе, мы 52 вынуждены использовать эту вторую РИС.4.2. Описание имени массива типа char форму, но весьма вероятно, что вы сможете выбрать любую из них. Если обнаружится, что при работе с первой формой оператора описания у вас возникнут трудности при решении наших примеров, попробуйте воспользоваться второй В действительности вторая форма должна работать в любой системе, но мы не хотим применить тип static до тех пор, пока не рассмотрим в гл 10 понятие классов памяти). На первый взгляд все это выглядит довольно сложным: вы должны создать массив, расположить символы в виде строки и не забыть добавить в конце \0. К счастью, о большинстве деталей компилятор может "позаботиться" сам. Попробуйте выполнить приведенную ниже программу, чтобы посмотреть, как просто все происходит на практике: /* похвала 1*/ #define PRAISE " Вот эта да, какое великолепное имя" main( ) { char name [50]; printf(" Как вас зовут? \n" ); scanf(" %s", name); printf(" Привет, %s %s\n" , name, PRAISE); } Символ %s служит указанием функции printf( ) напечатать строку. Результат выполнения программы похвала 1 может выглядeть, например, так Как вас зовут ? Элмо Бланк Привет, Элмо, Вот эта да, какое великолепное имя ! Как видите, нам не пришлось самим помещать нуль символ в конец массива. Эта задача была выполнена за нас функцией scanf( ) при чтении вводимой строки. PRAISE - "символическая строковая константа". Ниже мы рассмотрим директиву #define более подробно, а пока вы должны знать, что кавычки, в которые за ключена фраза, следующая за строковой константой PRAISE, иден тифицируют эту фразу как строку, и поэтому в ее конец будет помещен нуль-символ. Заметим (и это очень важно), что функция scanf( ) при вводе строки "Элмо Бланк" читает только имя Элмо. Дело в том, что, встретив какой-нибудь разделитель (пробел, символ табуляции или перевода строки), функция scanf( ) прекращает ввод символов, т е в данном случае она прекращает опрос переменной name в тот момент, когда доходит до пробела между "Элмо" и "Бланк". Вообще говоря, функция scanf( ) вводит только одиночные слова, а не целую фразу в качестве строки. Для чтения входной информации в языке Си имеются другие функции, например функция gets( ), предназначенная для обработки строк общего вида. Более полно работу со строками мы рассмотрим в последующих главах. 53 Необходимо заметить также, что строка "х" не то же самое, что символ 'x'. Первое различие: 'х' - объект одного из основных типов (Char), в то время как "х" - объект производного типа (массива элементов типа char). Второе различие: "х" на самом де ле состоит из двух символов - символа 'x' и нуль-символа. РИС.4.3. Символ 'х' и строка "х" Длина строки - функция strlen( ) Далее Содержание В предыдущей главе мы практически без объяснений использовали операцию sizeof, которая дает нам размер объектов в байтах Функция strlen( ) позволяет определять длину строки числом символов. Поскольку для размещения одного символа в памяти отводится 1 байт, можно было бы предположить, что в результате применения любой из этих двух операций к одной строке будет получен одинаковый результат. Оказыватся, это не так. Давайте немного изменим нашу предыдущую программу (добавим к ней несколько строк), и тогда мы поймем, в чем дело. /*похвала 2*/ #define PRAISE " Вот это да, какое великолепное имя!" main( ) { char name [50]; printf(" Как вас зовут?\n"); scanf(" %s", name); printf(" Привет, %s. %s\n" , name, PRAISE); printf(" Ваше имя состоит из %d букв и занимает %d ячеек памяти. \n", strlen (name), sizeof name); printf(" Хвалебная фраза состоит из %d букв", strlen (PRAISE)); printf(" и занимает %d ячеек памяти. \n", sizeof PRAISE); } Заметим, что случайно мы воспользовались двумя методами для обработки длинных операторов printf(). В первом случае мы записав один оператор печати в двух строках программы 2) . Мы сделали это, поскольку разрешается разбивать строку между аргументами, но не посередине строки. В другом случае использовались два оператора printf() для печати одной строки; мы указали символ "новая строка" (\n) только во втором из них. Представленный ниже результат работы данной программы поможет понять подобную ситуацию: Как вас зовут ? Перки Привет, Перки. Вот это да, какое великолепное имя! Ваше имя состоит из 5 букв и занимает 50 ячеек памяти. Хвалебная фраза состоит из 35 букв и занимает 36 ячеек памяти. Давайте посмотрим, в чем дело. Массив name занимает 50 ячеек памяти, и именно об этом сообщает операция sizeof. Но для хранения имени Перки требуются только первые пять ячеек, и как раз об этом нас информирует функция strlen( ). В шестой ячейке массива name содержится 54 нуль-символ, и его появление служит сигналом для функции strlen( ) прекратить подсчет символов РИС.4.4. Распознавание функцией strlen( ) конца строки При переходе к обработке константы PRAISE обнаруживается, что функция strlen( ) опять дает нам точное число символов (включая пробелы и знаки пунктуации) в строке. Результат операции sizeof оказывается на единицу большим, поскольку при этом учи тывается и "невидимый" нуль-символ, помещенный в конец строки. Мы не указываем компилятору, какой объем памяти он должен отвести для размещения всей фразы, он сам подсчитывает число символов между кавычками. Еще одно замечание в предыдущей главе была использована операция sizeof со скобками, а в этой - без них. Решение, исполь зовать ли скобки или нет, зависит от того, что вы хотите знать объем памяти, отводимый под элементы конкретного типа, или объем памяти, занимаемый определенным объектом В первом слу чае вы писали бы sizeof(char) или sizeof(float), а во втором - sizeof name или sizeof 6.28. В данном разделе операции strlen( ) и sizeof использовались только для удовлетворения нашего любопытства, в действительности они представляют собой важные программные средства Функция strlen( ), например, полезна в любого сорта программах обра ботки строк или символов, в чем вы сможете убедиться, ознакомившись с гл 13. Приступим теперь к рассмотрению директивы #define. КОНСТАНТЫ И ПРЕПРОЦЕССОР ЯЗЫКА Си Далее Содержание Иногда возникает необходимость использовать в программах константы. Например, оператор, позволяющий определять длину окружности, можно было бы записать в следующем виде circ = 3.14 * diameter, Приведенная здесь константа 3. 14 - известное число p. Чтобы ввести ту или иную константу в программу, нужно указать ее фак тическое значение, как было сделано выше. Однако существуют веские причины использовать вместо этого "символические кон станты", например, мы могли бы применять оператор circ = pi * diameter, а позже компилятор подставил бы в него фактическое значение константы. В чем достоинства такого метода? Во-первых, имя говорит нам больше, чем число. Сравним два оператора owed = 0 015 * housevl, owed = taxrate * housevl, Если мы изучаем большую программу, то второй вариант будет нам более понятен. Во-вторых, предположим, что некоторая константа использова лась в нескольких местах программы 55 и впоследствии возникла не обходимость изменить ее значение - ведь в конце концов и налого вые тарифы (taxrate) меняются, и, к примеру, некое законодатель мое собрание приняло однажды закон впредь считать число p равным 3 1 / 7 . (Весьма вероятно, что окружности пришлось при этом скрываться от правосудия). В таком случае требуется только изменить определение символической константы, а не отыскивать каждый случай ее появления в программе. Теперь осталось выяснить, как можно создать такую символическую константу? Первый способ заключается в том, чтобы описать некоторую переменную и положить ее равной требуемой константе. Мы могли бы сделать это следующим образом float taxrate, taxrate = 0 015, Такой способ подходит для небольшой программы, в других же случаях он несколько неэкономичен, поскольку каждый раз при использовании переменной taxrate компьютер должен будет обращаться к той ячейке памяти, которая отведена данной переменной Это служит примером подстановки "во время выполнения", так как она производится именно при выполнении программы. К счастъю, в языке Си имеется и другой, лучший способ. Этот способ реализуется с помощью препроцессора языка Си В гл. 2 мы уже видели, как препроцессор использует директиву #include для включения информации из другого файла в программу. Кроме того, препроцессор дает нам возможность задавать константы Для этого в начало файла, содержащего вашу программу, необходимо добавить только одну строку, аналогичную следующей #define TAXRATE 0.015 При компиляции программы каждый раз, когда появится переменная TAXRATE, она будет заменяться величиной 0.015. Это называ ется подстановкой "во время компиляции". К тому моменту, когда вы начнете выполнение своей программы, все подстановки будут уже сделаны. Несколько замечаний по поводу формата. Сначала идет ключевое слово |