printf(" Привет, %s. %s\n" , name, PRAISE);
printf(" Ваше имя состоит из %d букв и занимает %d ячеек памяти. \n",
strlen (name), sizeof name);
printf(" Хвалебная фраза состоит из %d букв", strlen (PRAISE));
printf(" и занимает %d ячеек памяти. \n", sizeof PRAISE);
}
Заметим, что случайно мы воспользовались двумя методами для обработки длинных операторов printf(). В первом случае мы, записав один оператор печати в двух строках программы. Мы сделали это, поскольку разрешается разбивать строку между аргументами, но не посередине строки. В другом случае использовались два оператора printf() для печати одной строки; мы указали символ "новая строка" (\n) только во втором из них. Представленный ниже результат работы данной программы поможет понять подобную ситуацию:
Как вас зовут ?
Перки
Привет, Перки. Вот это да, какое великолепное имя!
Ваше имя состоит из 5 букв и занимает 50 ячеек памяти.
Хвалебная фраза состоит из 35 букв и занимает 36 ячеек памяти.
Давайте посмотрим, в чем дело. Массив name занимает 50 ячеек памяти, и именно об этом сообщает операция sizeof. Но для хранения имени Перки требуются только первые пять ячеек, и как раз об этом нас информирует функция strlen( ). В шестой ячейке массива name содержится нуль-символ, и его появление служит сигналом для функции strlen( ) прекратить подсчет символов
РИС.4.4. Распознавание функцией strlen( ) конца строки
При переходе к обработке константы PRAISE обнаруживается, что функция strlen( ) опять дает нам точное число символов (включая пробелы и знаки пунктуации) в строке. Результат операции sizeof оказывается на единицу большим, поскольку при этом учитывается и "невидимый" нуль-символ, помещенный в конец строки. Мы не указываем компилятору, какой объем памяти он должен отвести для размещения всей фразы, он сам подсчитывает число символов между кавычками.
Еще одно замечание в предыдущей главе была использована операция sizeof со скобками, а в этой - без них. Решение, использовать ли скобки или нет, зависит от того, что вы хотите знать объем памяти, отводимый под элементы конкретного типа, или объем памяти, занимаемый определенным объектом В первом случае вы писали бы sizeof(char) или sizeof(float), а во втором - sizeof name или sizeof 6.28.
КОНСТАНТЫ И ПРЕПРОЦЕССОР ЯЗЫКА Си
Иногда возникает необходимость использовать в программах константы. Например, оператор, позволяющий определять длину окружности, можно было бы записать в следующем виде:
circ = 3.14 * diameter;
Приведенная здесь константа 3. 14 - известное число Пи. Чтобы ввести ту или иную константу в программу, нужно указать ее фактическое значение, как было сделано выше. Однако существуют веские причины использовать вместо этого "символические константы", например, мы могли бы применять оператор
circ = pi * diameter;
а позже компилятор подставил бы в него фактическое значение константы.
В чем достоинства такого метода?
Во-первых, имя говорит нам больше, чем число. Сравним два оператора
owed = 0 015 * housevl, owed = taxrate * housevl;
Если мы изучаем большую программу, то второй вариант будет нам более понятен.
Во-вторых, предположим, что некоторая константа использовалась в нескольких местах программы и впоследствии возникла необходимость изменить ее значение - ведь в конце концов и налоговые тарифы (taxrate) меняются, и, к примеру, некое законодательное собрание приняло однажды закон впредь считать число p равным 31/7. (Весьма вероятно, что окружности пришлось при этом скрываться от правосудия). В таком случае требуется только изменить определение символической константы, а не отыскивать каждый случай ее появления в программе.
Теперь осталось выяснить, как можно создать такую символическую константу? Первый способ заключается в том, чтобы описать некоторую переменную и положить ее равной требуемой константе. Мы могли бы сделать это следующим образом
float taxrate, taxrate = 0 015;
Такой способ подходит для небольшой программы, в других же случаях он несколько неэкономичен, поскольку каждый раз при использовании переменной taxrate компьютер должен будет обращаться к той ячейке памяти, которая отведена данной переменной. Это служит примером подстановки "во время выполнения", так как она производится именно при выполнении программы. К счастъю, в языке Си имеется и другой, лучший способ.
Этот способ реализуется с помощью препроцессора языка Си. В гл. 2 мы уже видели, как препроцессор использует директиву #include для включения информации из другого файла в программу. Кроме того, препроцессор дает нам возможность задавать константы. Для этого в начало файла, содержащего вашу программу, необходимо добавить только одну строку, аналогичную следующей:
#define TAXRATE 0.015
При компиляции программы каждый раз, когда появится переменная TAXRATE, она будет заменяться величиной 0.015. Это называется подстановкой "во время компиляции". К тому моменту, когда вы начнете выполнение своей программы, все подстановки будут уже сделаны.
Несколько замечаний по поводу формата.
Сначала идет ключевое слово #define. Оно должно начинаться с самой левой позиции. Потом следует символическое имя константы, а затем ее величина. Символ "точка с запятой" не используется, поскольку это не оператор языка Си. Почему имя TAXRATE пишется прописными буква ми? В процессе использования языка Си выработалась традиция писать константы прописными буквами. Если при просмотре программы вам встретится имя, написанное прописными буквами, вы сразу поймете, что имеете дело с константой, а не с переменной. Это еще один способ улучшить читаемость программы. Ваша программа будет работать даже и тогда, когда вы будете писать константы строчными буквами, но при этом вы должны чувствовать свою вину, поскольку нарушаете традицию.
Приведем простой пример:
/* пицца */
#define PI 3,14159
main( ) /* изучение вашей пиццы */
{
float area, circum, radius;
printf("Чемy равен радиус вашей пиццы? \n");
scanf("%f", &radius);
area = PI * radius * radius;
printf(" Основные параметры вашей пиццы следующие \n");
printf(" длина окружности = %1.2f, площадь =%1.2f \n circum, area);
}
РИС.4.5. Обработка текста программы препроцессором
Использование спецификации %1.2f в операторе printf( ) приведет к тому, что при печати результаты будут округлены до двух десятичных цифр. Мы понимаем, конечно, что написанная выше программа может и не отражать ваши собственные вкусы, касающиеся пиццы, но во множестве программ, посвященных этому вопросу, она займет свое скромное место. Вот один из примеров ее выполнения: