Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Практикум по программированию на языке Си

..pdf
Скачиваний:
23
Добавлен:
12.11.2023
Размер:
3.53 Mб
Скачать

printf

("The value 123456789.987654321F equals %24.12f\n", 123456789.987654321F);

printf

("The value 123456789.987654321F equals %24.12e\n", 123456789.987654321F);

return 0;

}

Результаты выполнения программы:

The value 123456789.987654321F equals 123456792.000000000000

The value 123456789.987654321F equals 1.234567920000e+08

Теперь результаты отражают именно конечную точность представления в памяти вещественных констант.

ЗАДАНИЕ. Подобные эксперименты проведите с константа-

ми типа double и long double.

Примечание. При выводе значений типа long double следует использовать спецификации преобразования в виде %Lf и %Le.

2.3. Целые константы

Используя целые константы, необходимо понимать следующие особенности:

1) возможность выбирать основание системы счисления;

2)приписывание типа константе (явное или по умолчанию);

3)существование граничных значений для каждого типа констант. Для вывода целых значений в форматной строке функции printf()

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

!%d – для десятичного целого со знаком;

!%i – для десятичного целого со знаком;

!%u – для десятичного целого без знака;

!%o – для восьмеричного целого без знака;

!– для шестнадцатеричного целого без знака;

!%X – для шестнадцатеричного целого без знака.

41

ЗАДАЧА 02-06. Напечатайте значение целого числа, например 1234, с разными основаниями системы счисления.

/* 02_06.c - основания счисления целых при выводе */ #include <stdio.h>

int main ()

{

printf

("The forms of 1234: %i(10), %o(8), %x(16)\n", 1234,1234,1234);

return 0;

}

Результаты выполнения программы:

The forms of 1234: 1234(10), 2322(8), 4d2(16)

В приведенной программе мы получили разные формы представления одного целого значения. Решим обратную задачу.

ЗАДАЧА 02-07. Выведите с помощью одной и той же спецификации преобразования значения целых констант, представленных с разными основаниями систем счисления.

Для записи целого значения с разными основаниями систем счисления нужно вспомнить соответствующие правила записи целых чисел (см. [3]). Чтобы не затрудняться переводом чисел из одной системы счисления в другую, используем результаты программы 02_06.с, т.е. выведем значения числа 1234. В следующей программе это продемонстрировано:

/* 02_07.c - основания счисления целых констант */ #include <stdio.h>

int main ()

{

printf("The value of 1234 is %i(10)\n",1234); printf("The value of 02322 is %i(10)\n",02322); printf("The value of 0x4d2 is %i(10)\n",0x4d2); return 0;

}

Результаты выполнения программы:

42

The value of 1234 is 1234(10)

The value of 02322 is 1234(10)

The value of 0x4d2 is 1234(10)

Итак, мы убедились, что спецификация %i %d) выводит целое число с основанием 10 независимо от того, с каким основанием системы счисления записана в программе представляющая это число целочисленная константа.

ЭКСПЕРИМЕНТ. Выведите с помощью функции printf() значения 2322 (восьмеричное) и 4d2 (шестнадцатеричное), полученные в результате представления числа 1234, не добавляя к ним префиксов '0' и '0x'. Посмотрите на реакцию системы при трансляции и исполнении программы.

/* 02_07_1.c

– ошибки

в записи целых констант

*/

#include <stdio.h>

 

 

 

/*02*/

int main ()

 

 

 

 

/*03*/

{

value of

1234

 

 

/*04*/

printf("The

is %i(10)\n",1234);/*05*/

printf("The

value of

2322

is

%i(10)\n",2322);/*06*/

printf("The

value of

4d2 is

%i(10)\n",4d2);

/*07*/

return 0;

 

 

 

 

/*08*/

}

 

 

 

 

/*09*/

Некорректная трансляция:

02_07_1.c: In function `main':

02_07_1.c:7: nondigits in number and not hexadecimal

Константу 2322 компилятор воспринимает без возражений, но только не как восьмеричную, а имеющую основание 10. А вот константа 4d2 воспринимается как ошибочная конструкция.

При записи целой константы ей можно с помощью суффиксов U, u, L, l явно приписать тип unsigned int либо long.

По размерам памяти, выделяемой для представления константы, можно иногда косвенно определять тип, который ей присваивает компилятор. Однако стандарт языка Си не накладывает ограничений

43

на "длины" внутренних представлений значений целых типов. В соответствии со Стандартом требуется только соблюдение неравенства:

sizeof(short) <= sizeof(int) <= sizeof(long)

ЗАДАЧА 02-08. Оценить "длины" участков памяти, выделяемых для значений целых типов конкретным компилятором.

// 02_08.c - размеры участков памяти целых констант

#include <stdio.h> int main ()

{

printf("sizeof(1) = %d\n", sizeof(1)); printf("sizeof(1L) = %d\n", sizeof(1L)); printf("sizeof(1U) = %d\n", sizeof(1U)); printf("sizeof(short) = %d\n", sizeof(short)); printf("sizeof(int) = %d\n", sizeof(int)); printf("sizeof(long) = %d\n", sizeof(long)); return 0;

}

Результаты выполнения программы (32-разрядный компилятор):

sizeof(1) = 4 sizeof(1L) = 4 sizeof(1U) = 4 sizeof(short) = 2 sizeof(int) = 4 sizeof(long) = 4

Как видите, размеры для int и long в данной реализации одинаковы, а константу типа short задать нельзя.

ЗАДАНИЕ. Выполните приведенную программу с 16-раз- рядным компилятором и проанализируйте полученные результаты.

После трансляции 16-разрядным компилятором получены результаты (компилятор Турбо Си):

sizeof(1) = 2 sizeof(1L) = 4

44

sizeof(1U) = 2 sizeof(short) = 2 sizeof(int) = 2 sizeof(long) = 4

Для тех, кто не изучал правила и особенности внутреннего (машинного) представления целых чисел, различие между signed int (по умолчанию int) и unsigned int непонятно. Однако для их корректного использования на практике достаточно общего знакомства со свойствами знаковых и беззнаковых чисел. Познакомимся с этими свойствами с помощью экспериментов.

Для константы типа int 32-разрядный компилятор выделяет 4 байта памяти (см. результаты программы 02_08.с). Следовательно, их предельные значения –2147483648 и +2147483647. Для беззнаковых значений типа unsigned int диапазон значений от 0 до

4294967295.

ЗАДАЧА 02-09. Выберите значение между максимальным int и максимальным unsigned int, представьте его как константу типа int и как константу unsigned int, и выведите соответствующие значения, используя спецификации %d и %u.

// 02_09.c - знаковые и беззнаковые целые константы

#include

<stdio.h>

/* 02 */

int main

()

/* 03 */

{

 

/* 04 */

printf("4000000000 = %d\n", 4000000000);

/* 05

*/

printf("4000000000U = %u\n", 4000000000U);/* 06

*/

return

0;

/* 07

*/

}

 

/* 08

*/

Некорректная трансляция (выдано предупреждение):

02_09.c: In function `main':

02_09.c:5: warning: decimal constant is so large that it is unsigned

Результаты выполнения программы:

4000000000 = -294967296

4000000000U = 4000000000

45

В константе типа int, выводимой по спецификации %d, старший бит внутреннего представления воспринят как признак отрицательного числа. Константа unsigned int по спецификации %u выведена без искажений.

2.4. Перечислимые константы

Перечисления позволяют вводить имена для целых констант.

ЗАДАЧА 02-10. Введя перечисление, содержащее название дней недели, напечатайте их числовые значения. С помощью операции sizeof оцените размер памяти, выделяемой для констант перечисления и для их типа, введенного перечислением.

/* 02_10.c - значения и размеры констант перечисления */

#include <stdio.h> int main ()

{

enum DAY { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY };

printf("SUNDAY=%d\n", SUNDAY); printf("MONDAY=%d\n", MONDAY); printf("FRIDAY=%d\n", FRIDAY);

printf("sizeof(enum DAY)=%d\n", sizeof(enum DAY)); printf("sizeof(MONDAY)=%d\n", sizeof(MONDAY)); printf("sizeof(FRIDAY)=%d\n", sizeof(FRIDAY)); return 0;

}

Результаты выполнения программы:

SUNDAY = 0

MONDAY = 1

FRIDAY = 5 sizeof(enum DAY) = 4 sizeof(MONDAY) = 4 sizeof(FRIDAY) = 4

ЗАДАНИЕ. Выполните приведенную программу, используя 16-разрядный компилятор.

46

Для компилятора Турбо Си получены такие результаты:

SUNDAY = 0

MONDAY = 1

FRIDAY = 5 sizeof(enum DAY) = 2 sizeof(MONDAY) = 2 sizeof(FRIDAY) = 2

Обратите внимание, что конструкция “enum DAY” есть имя типа. Именно для объектов этого типа операция sizeof вычисляет размер памяти. В компиляторе DJGPP этот размер совпадает с размерами для int и long.

ЗАДАЧА 02-11. Установлены следующие тарифные ставки (оклады) Единой тарифной сетки по оплате труда: 200 (разряд 1), 210 (разряд 2), 233 (разряд 3), 252 (разряд 4), 285 (разряд 5), 322 (разряд 6), 364 (разряд 7), 412 (разряд 8), 466 (разряд 9), 527 (разряд 10), 595 (разряд 11), 673 (разряд 12), 760 (разряд 13), 859 (разряд 14), 972 (разряд 15), 1078 (разряд 16), 1197 (разряд 17), 1329 (разряд 18). Определите перечисление, вводящее обозначения для констант – значений перечисленных окладов.

// 02_11.c – оклады Единой тарифной сетки

#include <stdio.h> int main ()

{

enum ETC { RANK01=200, RANK02=210, RANK03=233, RANK04=252, RANK05=285, RANK06=322, RANK07=364, RANK08=412, RANK09=466, RANK10=527, RANK11=595, RANK12=673, RANK13=760, RANK14=859, RANK15=972, RANK16=1078, RANK17=1197, RANK18=1329 };

printf("RANK09=%d\n", RANK09); printf("RANK16=%d\n", RANK16); printf("sizeof(RANK08)=%d\n", sizeof(RANK08)); printf("sizeof(enum ETC)=%d\n", sizeof(enum ETC)); return 0;

}

Результаты выполнения программы:

RANK09 = 466

RANK16 = 1078

47

sizeof(RANK08) = 4 sizeof(enum ETC) = 4

Программа 02_11.с иллюстрирует удобство использования именованных констант, вводимых перечислениями.

2.5. Символьные константы

Вначале дадим пояснения, выводящие читателя за рамки уже рассмотренного нами материала. Обратим внимание, что символьные константы, записанные без префикса L, относятся к типу int. Основной минимальной единицей памяти, с которой работают программы на языке Си, является байт. Традиционно байт – это последовательность из восьми бит. С помощью кодов, в которых каждый символ представлен одним байтом, можно отображать символы алфавитов многих европейских, но не всех языков мира. Иероглифические языки Востока требуют для представления своих идеограмм (иероглифов) большее число различных символов, чем представляет байт (256 различных значений). Поэтому стандарт языка требует, чтобы для представления символа было выделено не менее одного байта (больше можно). Когда применяется для кодирования символа участок памяти длиной более одного байта, то говорят о расширенном наборе литер, который не может быть охвачен типом char ([1] с. 186). Указанный целочисленный тип wchar_t определен в стандартном заголовочном файле <stdef.h>. При записи в тексте программы символы из расширенного набора представляются с префиксом 'L'.

Как уже было показано (программа 02_03.с), для изображения на экране или при печати символа (литеры) может использоваться функция printf() со спецификацией преобразования %c. Числовые значения кода символа можно вывести с помощью следующих спецификаций:

!%u – беззнаковое целое, представленное с десятичным основанием;

!%o – беззнаковое целое, представленное с восьмеричным основанием;

!%x – беззнаковое целое, представленное с шестнадцатеричным основанием.

ЗАДАЧА 02-12. Получить изображения, длины в байтах и числовые коды символа 'j' и такого же символа из расширенного набора, т.е. L'j'.

48

/* 02_12.c - коды и "длины" символьных констант */ #include <stdio.h>

int main ()

{

printf

("symbol: %c, sizeof(\'j\')=%d, codes: %u,%o,%x\n", 'j', sizeof('j'), 'j', 'j', 'j');

printf

("symbol: %c, sizeof(L\'j\')=%d, codes: %u,%o,%x\n", L'j', sizeof(L'j'), L'j', L'j', L'j');

return 0;

}

Результаты выполнения программы:

symbol: j, sizeof('j')=4, codes: 106,152,6a symbol: j, sizeof(L'j')=4, codes: 106,152,6a

Обратите внимание на длину представления обычных символьных констант. Компилятор DJGPP отводит им по четыре байта, как и константе типа int, что соответствует Стандарту.

ЭКСПЕРИМЕНТ. Поместите в апострофы: одну двойную кавычку “, пусто (апострофы рядом), один апостроф ', переход на новую строку. Попытайтесь вывести изображения и коды этих символов.

Стандарт языка обещает "непредсказуемый результат", но конкретный компилятор может достаточно корректно воспринять некоторые из таких изображений.

// 02_12_1.c - представления и коды особых символов

#include <stdio.h>

/* 02 */

int main ()

/* 03 */

{

/* 04 */

printf("symbol: %c, code: %u\n",'"','"');

/* 05 */

printf("symbol: %c, code: %u\n",'','');

/* 06 */

printf("symbol: %c, code: %u\n",''','''); /* 07

*/

printf("symbol: %c, code: %u\n",'

 

 

','

/* 10

*/

');

return 0;

/* 11

*/

}

/* 12

*/

 

 

49

Некорректная трансляция:

02_12_1.c:8: unterminated character constant

02_12_1.c:10: unterminated character constant

Параметры последнего обращения к функции printf() содержат в апострофах коды, полученные от клавиши ENTER, т.е. введен символ ', затем нажата клавиша ENTER и вновь введен символ '. Ничего другого внутри апострофов в этом случае не может быть, поэтому комментарии с номерами строк 8 и 9 опущены. При печати текста программы в этом месте выполнен соответствующий переход на новую строку. Именно так компилятор отреагировал на код символа "новая строка", помещенный нами с помощью текстового редактора в апострофы, ограничивающие символьную константу. Удалим из программы последнее обращение к функции printf():

// 02_12_2.c - представления и коды особых символов

#include

<stdio.h>

/* 02 */

int main

()

/* 03 */

{

 

/* 04 */

printf("symbol: %c, code: %u\n",'"','"');

/* 05 */

printf("symbol: %c, code: %u\n",'','');

/* 06

*/

printf("symbol: %c, code: %u\n",''','''); /* 07

*/

return

0;

/* 08

*/

}

 

/* 09

*/

Некорректная трансляция:

02_12_2.c: In function `main':

02_12_2.c:6: empty character constant

02_12_2.c:6: empty character constant

02_12_2.c:7: empty character constant

02_12_2.c:7: parse error before character constant 02_12_2.c:7: empty character constant

Компилятор "возражает" против изображений констант "пусто" и "апостроф". Удалим соответствующие вызовы функции printf() из программы. Останется только константа "кавычки":

// 02_12_3.c - представления и коды особых символов

#include <stdio.h>

50