книги / Практикум по программированию на языке Си
..pdfint main ()
{
printf("symbol: %c, code: %u\n",'"','"'); return 0;
}
Результаты выполнения программы:
symbol: ", code: 34
Результаты экспериментов демонстрируют "неполноту" сообщений, выдаваемых компилятором при наличии нескольких ошибок в программе. Для получения безошибочного текста программы пришлось дважды вносить в нее исправления. Итак, выяснилось, что из нестандартных констант компилятор DJGPP смог воспринять только кавычки (в апострофах).
ЗАДАЧА 02-13. Получите изображения, "длины" и коды особых графических символов, представляя их эскейп-последова-
тельностями: \', \”, \?, \\.
/* 02_13.c – эскейп-представления особых символов */ #include <stdio.h>
int main ()
{
printf
("symbol: %c, sizeof(\'\\'\')=%d, code: %u\n", '\'', sizeof('\''), '\'');
printf
("symbol: %c, sizeof(\'\\\"\')=%d, code: %u\n", '\"', sizeof('\"'),'\"');
printf
("symbol: %c, sizeof(\'\\?\')=%d, code: %u\n", '\?', sizeof('\?'),'\?');
printf
("symbol: %c, sizeof(\'\\\\')=%d, code: %u\n", '\\', sizeof('\\'),'\\');
return 0;
}
Результаты выполнения программы:
51
symbol: ', sizeof('\'')=4, code: 39 symbol: ", sizeof('\"')=4, code: 34 symbol: ?, sizeof('\?')=4, code: 63 symbol: \, sizeof('\\')=4, code: 92
Отметим, что длина кода символа, записанного в виде эскейппоследовательности (например ‘\?’), равна четырем байтам, как и для обычного представления символа.
В тексте программы надо обратить внимание на разную запись эскейп-последовательностей внутри форматной строки и вне ее. Внутри форматной строки символ ' заменен двумя символами: \’, для изображения кавычки использована пара \”, а каждый отдельный символ \ должен быть изображен парой символов \\.
ЗАДАЧА 02-14. Получите "изображения" и коды неграфических символов, представляемых эскейп-последовательностями: '\a', '\b', '\f', '\n', '\r', '\t', '\v'.
// 02_14.c - коды неграфических символьных констант
#include <stdio.h> int main ()
{
printf("symbol: %c, code: %u\n",'\a','\a'); printf("symbol: %c, code: %u\n",'\b','\b'); printf("symbol: %c, code: %u\n",'\f','\f'); printf("symbol: %c, code: %u\n",'\n','\n'); printf("symbol: %c, code: %u\n",'\r','\r'); printf("symbol: %c, code: %u\n",'\t','\t'); printf("symbol: %c, code: %u\n",'\v','\v'); return 0;
}
Результаты выполнения программы:
symbol: , code: 7 symbol:, code: 8 symbol:, code: 12 symbol:
, code: 10 |
|
|
, |
code: 13 |
, code: 9 |
symbol: |
||
symbol: |
|
|
' |
code: 11 |
|
52
При исполнении программы воспроизводится звуковой сигнал, "инициатор" которого – эскейп-последовательность.
Стандарт языка не определяет результата, если в эскейппоследовательности после наклонной черты \ будет использован символ, отличающийся от перечисленных в предыдущей задаче.
ЗАДАНИЕ. Проведите такой же эксперимент, как в предыдущей программе, с "нестандартными" эскейп-последователь- ностями, например, '\A' и '\z'.
/* 02_14_1.c - нестандартные представления */ |
*/ |
||
#include |
<stdio.h> |
/* 02 |
|
int main |
() |
/* 03 |
*/ |
{ |
|
/* 04 |
*/ |
printf("symbol: %c, code: %u\n",'\A','\A');/* 05 |
*/ |
||
printf("symbol: %c, code: %u\n",'\z','\z');/* 06 |
*/ |
||
return 0; |
/* |
07 |
*/ |
} |
/* |
08 |
*/ |
Трансляция с предупреждениями:
02_14_1.c: In function `main':
02_14_1.c:5: warning: unknown escape sequence `\A' 02_14_1.c:5: warning: unknown escape sequence `\A' 02_14_1.c:6: warning: unknown escape sequence `\z' 02_14_1.c:6: warning: unknown escape sequence `\z'
Результаты выполнения программы:
symbol: A, code: 65 symbol: z, code: 122
Полученные значения десятичных кодов совпадают с соответствующими кодами символов ‘A’ и ‘z’, но транслятор "возражает", выдавая предупреждающие сообщения (warning).
ЗАДАЧА 02-15. Получите длину и код символа, представляемого как '\0', и сравните с длинами и кодами символа '0' (ноль) и символа ' ' (пробел).
53
/* 02_15.c - символы '\0', '0' и ' ' */ #include <stdio.h>
int main ()
{
printf("sizeof(\'\\0\')=%d, symbol: %c", sizeof('\0'),'\0');
printf(", codes: %u(10), %o(8), %x(16)\n", '\0','\0','\0');
printf("sizeof(\'0\')=%d, symbol: %c", sizeof('0'),'0');
printf(", codes: %u(10), %o(8), %x(16)\n", '0','0','0');
printf("sizeof(\' ')=%d, symbol: %c", sizeof(' '),' ');
printf(", codes: %u(10), %o(8), %x(16)\n", ' ',' ',' ');
return 0;
}
Результаты выполнения программы:
sizeof('\0')=4, symbol: , codes: 0(10), 0(8), 0(16) sizeof('0')=4, symbol: 0, codes: 48(10), 60(8), 30(16)
sizeof(' ')=4, symbol: , codes: 32(10), 40(8), 20(16)
Результаты, особенно различие между кодами символов '0' и '\0', рекомендуется запомнить.
ЗАДАЧА 02-16. Выбрав из таблицы кодов ASCII коды какихлибо символов, напечатайте с помощью эскейп-последователь- ностей их изображения, длины внутренних представлений и числовые значения, представленные с разными основаниями счисления.
Нужно обратить внимание, что при записи эскейп-последова- тельностей с числовыми кодами не применимы десятичные цифры (только восьмеричные и шестнадцатеричные). В следующей программе рассматривается представление символов '#' и 'L'.
/* 02_16.c - изображения и коды эскейппоследовательностей */
54
#include <stdio.h> int main ()
{
printf("sizeof(\'\\043\')=%d, symbol: %c\n", sizeof('\043'),'\043');
printf("\tcodes: %u(10), %o(8), %x(16)\n", '\043','\043','\043');
printf("sizeof(\'\\x4c\')=%d, symbol: %c\n", sizeof('\x4c'),'\x4c');
printf("\tcodes: %u(10), %o(8), %x(16)\n", '\x4c','\x4c','\x4c');
return 0;
}
Результаты выполнения программы:
sizeof('\043')=4, symbol: #,
codes: 35(10), 43(8), 23(16) sizeof('\x4c')=4, symbol: L,
codes: 76(10), 114(8), 4c(16)
В результатах обратите внимание на "длины" констант, представленных эскейп-последовательностями. В тексте программы отметим разную запись эскейп-последовательностей в форматной строке и вне ее.
Остановимся на ошибках в записи эскейп-последовательностей.
ЭКСПЕРИМЕНТ. Опустите признаки оснований системы счисления в записи эскейп-последовательностей с числовыми кодами, представляющих символы '#' и 'L', т.е. вместо '\043' запишите '\43', а вместо '\x4c' используйте '\4c'.
Не приводя текста программы (см. файл 02_16_1.с в электронной поддержке Практикума), отметим, что трансляция пройдет с предупреждениями. На каждое появление неверной эскейп-после- довательности будет выдано сообщение:
"Warning: multi-character constant"
("Предупреждение: мульти-символьная константа"). Результаты выполнения программы будут такими:
sizeof('\43')=4, symbol: #
codes: 35(10), 43(8), 23(16)
55
sizeof('\4c')=4, symbol: c
codes: 1123(10), 2143(8), 463(16)
Из результатов исполнения видно, что компилятор воспринял '\43' как правильную запись константы, представляющей символ '#', а последовательность '\4c' трактует как мультибайтовую (мультисимвольную) константу, значение которой отличается от 'L'.
ЗАДАЧА 02-17. Выведите символ и коды мультисимвольной константы 'ab'.
/* 02_17.c - мультибайтовые символы */ |
/* 2*/ |
|
#include |
<stdio.h> |
|
int main |
() |
/* 3*/ |
{ |
|
/* 4*/ |
printf("sizeof(\'ab\')=%d, symbol: %c\n", |
/* 5*/ |
|
|
sizeof('ab'),'ab'); |
/* 6*/ |
printf(",\tcodes: %u(10), %o(8), %x(16)\n", |
/* 7*/ |
|
return |
'ab','ab','ab'); |
/* 8*/ |
0; |
/* 9*/ |
|
} |
|
/*10*/ |
Трансляция с предупреждениями:
02_17.c: In function `main':
02_17.c:6: warning: multi-character character constant
02_17.c:6: warning: multi-character character constant
02_17.c:8: warning: multi-character character constant
02_17.c:8: warning: multi-character character constant
02_17.c:8: warning: multi-character character constant
Результаты выполнения программы:
sizeof('ab')=4, symbol: b
codes: 24930(10), 60542(8), 6162(16)
56
Длина мультибайтовой константы 'ab' равна четырем байтам. По спецификации %c из константы выведен только символ 'b'. Шестнадцатеричный код содержит коды обоих символов 61 для 'a' и 62 для 'b'. Десятичное и восьмеричное представления кода мультисимвольной константы не так наглядны.
ЗАДАЧА 02-18. Длина мультисимвольной константы равна четырем байтам. Проверьте допустимость размещения в апострофах четырех символов. Пусть это будут цифра 4 (код \x34) и
знаки: ? (код \x3f), = (код \x3d) и @ (код \x40):
/* 02_18.c - мультибайтовые символьные константы */ #include <stdio.h>
int main ()
{
printf("sizeof(\'4?=@\')=%d, symbol: %c", sizeof('4?=@'),'4?=@');
printf(", code: %x(16)\n",'4?=@'); return 0;
}
Трансляция с теми же предупреждениями, что и в программе
02_17.с.
Результаты выполнения программы:
sizeof('4?=@')=4, symbol: @, code: 343f3d40(16)
Шестнадцатеричный код представляет собой конкатенацию шестнадцатеричных кодов символов '4', '?', '=', '@'.
ЭКСПЕРИМЕНТ. Попытаемся разместить в мультибайтовой символьной константе более четырех символов.
/* 02_18_1.c - мультибайтовые недопустимые |
|
|
#include |
символьные константы */ |
/* 3*/ |
<stdio.h> |
||
int main |
() |
/* 4*/ |
{ |
|
/* 5*/ |
printf("sizeof(\'12345\')=%d, symbol: %c", |
/* 6*/ |
|
|
sizeof('12345'),'12345'); |
/* 7*/ |
|
|
57 |
printf(", code: %x(16)\n",'12345'); |
/* |
8*/ |
return 0; |
/* |
9*/ |
} |
/*10*/ |
Аварийное завершение трансляции:
02_18_1.c: In function `main':
02_18_1.c:7: character constant too long
02_18_1.c:7: character constant too long
02_18_1.c:8: character constant too long
Ничего не получилось – константу из пяти (и более) символов компилятор воспринимает как фатальную ошибку.
2.6. Символьные строки (строковые константы)
Прежде всего напомним, что символьные строки Стандарт не относит к базовым константам языка. Однако у символьных строк нет имен (они сами себя представляют). Каждая символьная строка никак не может быть изменена в процессе исполнения программы, и поэтому их удобно рассматривать наряду с другими константами.
Изучая строковые константы, нужно обратить внимание:
!на их длину (в памяти ЭВМ);
!на особенности их записи в тексте программы;
!на изображение строки при выводе (например, на экран дисплея).
ЗАДАЧА 02-19. Сравните длины символьной константы 'A', символьной строки из одного символа "A" и строки из нескольких символов "12345".
// 02_19.c - символьные строки (строковые константы) #include <stdio.h>
int main ()
{
printf("sizeof(\"12345\")=%d\n",sizeof("12345"));
printf("sizeof(\"A\")=%d\n",sizeof("A"));
printf("sizeof(\'A\')=%d\n",sizeof('A')); return 0;
}
58
Результаты выполнения программы:
sizeof("12345")=6
sizeof("A")=2
sizeof('A')=4
Строковая константа представляется в памяти последовательностью байтов, каждый из которых содержит код символа строки. В конце этой последовательности размещается код "тернарного" символа '\0', автоматически добавляемый компилятором. Именно поэтому длина строки "A" равна 2, а длина строки "12345" равна шести байтам. C тем, что одному символу 'A' выделен участок памяти 4 байта, мы уже знакомы – символ отнесен Стандартом к типу int.
ЭКСПЕРИМЕНТ. Используя выражение sizeof(char) и sizeof(wchar_t), оцените размеры памяти, выделяемые вашим транслятором для данных типов char и wchar_t соответственно. Напоминаем, что тип wchar_t не является базовым, а определен в заголовочном файле <stddef.h>.
/* 02_19_1.c - символьные типы char и wchar_t */ #include <stdio.h>
#include <stddef.h> int main ()
{
printf("sizeof(char)=%d\n",sizeof(char)); printf("sizeof(wchar_t)=%d\n",sizeof(wchar_t)); return 0;
}
Результаты выполнения программы:
sizeof(char)=1 sizeof(wchar_t)=4
ЗАДАЧА 02-20. Сравните размеры памяти, выделенной для обычной строковой константы (с символами типа char), и для константы из символов расширенного набора:
// 02_20.c - строка из символов расширенного набора
#include <stdio.h> int main ()
59
{
printf("sizeof(\"12345\")=%d\n",sizeof("12345")); printf
("sizeof(L\"12345\")=%d\n",sizeof(L"12345")); return 0;
}
Результаты выполнения программы:
sizeof("12345")=6
sizeof(L"12345")=24
Как подтверждают результаты, строка с символами типа wchar_t занимает (k+1)#4 байта, для строки с символами типа char выделяется (k+1) байтов, где k – количество явно использованных символов. Отметим, что символ '\0' в строке с элементами типа char занимает 1 байт, а в строке из символов расширенного набора его длина равна 4 байта. В то же время sizeof('\0') равно 4.
Обратим внимание на некоторые особенности записи строковых констант в тексте программы.
ЗАДАЧА 02-21. Запишите фразу “Repetitio est mater studiorum!” ("Повторение – мать учения!"), разместив каждое слово на отдельной строке текста программы.
Первый вариант (одна строковая константа):
/* 02_21.c - строковая константа в нескольких строках */
#include <stdio.h> int main ()
{
puts("Repetitio \ est \
mater \ studiorum!");
return 0;
}
Символ '\', не видимый при печати код '\n', и все пробелы между ними компилятор автоматически удаляет из текста.
60