C
существуют другие (модифицированные) целочисленные типы:
•
short
— отводится меньше байтов, чем на int
;
•
long
— отводится больше байтов, чем на int
(не всегда, зависит от системы);
•
unsigned
— столько же байт как у int
, но без отрицательных чисел; в результате чего знаковый разряд освобождается, и количество положительных значений увеличивается;
9
•
unsigned shot
;
•
unsigned long
Вот по-моему и все. При выводе длинных чисел следует дополнять спецификацию формата буквой l перед буквой формата. Например:
printf("%ld\n",i);
printf("%15ld\n",i);
Символы
Под символьный тип данных отводится 1 байт памяти. Также, как вам должно быть известно, у каждого символа есть соответствующее ему целое число по таблице символов (в данном случае, ASCII).
Тип char языка программирования
C
включает диапазон чисел от -128 до 127. Значения от 0 до 127 могут быть заданы или выведены на экран в виде соответствующих символов (на самом деле не все). Если значение переменной определяется в виде символа, то символ заключается в одиночные кавычки, например, так: 'w'. Также в языке существует тип unsigned char с диапазоном чисел от 0 до 255.
С другой стороны, если переменная задана как int или short и ей присвоено значение в диапазоне, где оно может быть представлено символом, то значение можно вывести как символ. Соответственно целочисленной переменной можно присвоить символ.
Если в программе вы будете использовать целые числа со значениями до 127 или 255 и хотите сэкономить память, то объявите переменную как char или unsigned char
Получается, что в программе символы — это числа, а числа — символы. Тогда как указать, что мы хотим видеть на экране: символ или число? Для вывода на экран символов используется спецификация формата вида
%c
Задание
Спишите программу представленную ниже. Выполните ее, объясните результат.
Самостоятельно поэкспериментируйте, изменяя значения переменных и их тип.
#include
main() {
char ch = 63;
unsigned char uch = 'r';
short j = 'b', k = 99;
printf("%c == %d\n", ch, ch);
printf("%c == %d\n", uch, uch);
printf("%c, %c\n", j, k);
}
Вещественные числа
В языке
C
существует три типа чисел с плавающей точкой: float и double
(двойной точности) и long double
. Также существует три формата вывода вещественных чисел, причем они не связаны с типом, а связаны с удобством представления числа. Вещественные числа могут иметь высокую точность, очень маленькое или очень большое значение. Если выполнить функции printf()
с такими параметрами:
double a = 0.0005;
printf("%f\n", a);
printf("%g\n", 0.0005);
10
printf("%g\n", 0.00005);
printf("%e\n", 0.0005);
, то на экране мы увидим следующее:
0.000500 0.0005 5e-05 5.000000e-04
В первом случае (
%f
) выводится число в обычном виде. По умолчанию точность представления числа равна шести знакам после точки.
Во втором случае (
%g
)
число выводится как обычно, если количество значащих нулей не больше четырех. Если количество значащих нулей четыре и больше, то число выводится в нормализованном виде (третий случай). Запись 5e-5 означает 5 * 10
-5
, что равно 0.00005. А, например, запись 4.325e+3 является экспоненциальной записью 4.325 * 10 3
, что равно 4325.
Если с такой формой представления чисел вы сталкиваетесь первый раз, то почитайте дополнительные источники, например, статью в Википедии "Экспоненциальная запись".
Четвертый формат (
%e
) выведет число исключительно в нормализованном виде, каким бы это вещественное число ни было.
Если при выводе требуется округлить число до определенной точности, то перед буквой- форматом ставят точку и число-указатель точности. Например, printf("%.2f", 0.23) выведет на экран 0.23, а не 0.230000. Когда требуется указать еще и поле, то его ширину прописывают перед точкой, например,
%10.3f
Задание
Напишите программу, в которой должны быть две переменные любых вещественных типов.
Одной переменной присвойте достаточно маленькое, а другой — большое значение. Выведите на экран значения этих переменных с использованием различных форматов. При использовании форматов
%f и %e округлите числа до трех знаков после точки.
МассивыПеременные, содержащие массивы, в языке программирования
C объявляются, например, так:
int arr[5], nums[N];
float f_arr[100];
char str[80];
При этом если используется константа, то она должна быть определена до своего использования следующим образом (чаще константы определяют вне функций):
#define N 100
На самом деле
#define является командой препроцессора, используемой не только для определения констант. Когда препроцессор обрабатывает исходный файл программы, он подставляет во все места, где была упомянута константа ее значение.
Запомните, индексация массивов в языке программирования
C начинается с нуля.
Присваивание значений элементам массивов можно произвести сразу или в процессе выполнения программы. Например:
char vowels[] = {'a', 'e', 'i', 'o', 'u', 'y'};
float f_arr[6];
11
f_arr[0] = 25.3;
f_arr[4] = 34.2;
printf("%c, %.2f\n", vowels[4], f_arr[0]);
Когда переменная-массив объявляется и сразу определяется (как в случае
vowels), то размер массива можно не указывать, т.к. он
вычисляется по количеству элементов, переданных в фигурных скобках.
СтрокиВ языке программирования
С нет такого типа данных как строки, хотя формат вывода строки есть (
%s
). Под словами "нет такого типа данных" я подразумеваю отсутствие специального ключевого слова, которое бы определяло переменную строкового типа (по аналогии с переменными типа int или float
). Строки в языке программирования
C интерпретируются как массивы символов, последний элемент которых является самым первым (с номером 0) символом в таблице ASCII. В этом месте в таблице стоит "ничто", имеющее символьное обозначение '\0'.
С другой стороны, строки — это необычные массивы в том смысле, что работа с ними в языке программирования
C несколько отличается от работы с числовыми массивами. В этом мы убедимся позже.
Выше мы объявили и определили массив
vowels. Если бы мы его определили вот так:
char vowels[] = {'a', 'e', 'i', 'o', 'u', 'y', '\0'};
или так:
char vowels1[] = "aeiouy";
то он бы был строкой. Во втором случае сами двойные кавычки "говорят" что это строка, и символ окончания строки '\0' записывается в память.
Массивы символов можно выводить на экран просто указав имя переменной, а вот с массивами чисел такой номер не пройдет:
printf("%s\n", vowels);
printf("%f\n", f_arr); // ошибка
Функция sizeof()Функция sizeof()
языка
C принимает в качестве аргумента константу, тип данных или переменную и возвращает количество байт, которые отведено под этот объект в памяти
ЭВМ.
При выводе на экран значения, возвращаемого sizeof()
используется формат
%lu
(длинное целое без знака). Примеры:
int a = 10;
int b[100];
printf("Integer: %lu \n", sizeof(a));
printf("Float: %lu \n", sizeof(float));
printf("Array of 100 integers: %lu \n", sizeof(b));
12
Задание
Напишите программу, выводящую информацию о количестве байтов, отводимых в памяти под типы данных, которые были изучены на данном уроке. При работе с массивами символов, определенными строковыми константами (в двойных кавычках), обратите внимание, что
размер массива больше на единицу, чем количество видимых символов. Вспомните, почему?
Если у вас на компьютере есть вторая операционная система, то скомпилируйте программу и там; сравните полученные результаты. Вот что получилось у меня в результате компиляции с помощью GCC в Xubuntu и Fedora:
Урок 2. Символьный тип данных. Специальные символыЭтот урок будет совсем небольшим по количеству теории. Здесь мы более подробно рассмотрим символьный тип данных.
По таблице ASCII символы с номерами (кодами) от 0 до 127 жестко определены. В этом диапазоне номера присвоены символам цифр, латинским (английским) маленьким и большим буквам, а также используемым в языке иным символам ('!', '%', '' и т.п.). Здесь же заданы коды для различных управляющих символов, которые никак не экране не отображаются, а что-то делают (например, создают новою строку или отступ, подают звуковой сигнал и др.). Расширенная таблица ASCII кодирует символы национальных алфавитов (например, русского языка) числами лежащими в диапазоне от 128 до 255.
Символы цифр от '0' до '9' имеют последовательные коды от 48 до 57. Этот факт обычно используют, при "переводе" символов цифр в числа. Если мы знаем, что у '0' код 48, а был задан символ '5', имеющий код 53, то если вычесть из 53 число 48, получим число 5. Знание кодов символов цифр позволяет программировать извлечение чисел из текста.
Английские большие буквы (прописные) имеют последовательные коды от 65 (A) до 90 (Z), маленькие (строчные) — от 97 до 122.
Задания
1. Напишите программу, в которой объявлены только две переменные символьного типа.
Одной переменной присвоен, например, символ '4', а второй — '7'. Функция printf() должна выводить на экран разность и сумму чисел, которые были представлены символами и присвоены переменным. (Подсказка: все вычисления для получения результата следует выполнять непосредственно в выражении, которое будет являться одним из параметром функции printf().)
2. Переменная
not_num содержит строку из трех символов-цифр, например "528".
Необходимо получить из этой строки соответствующее ему число и присвоить его переменной
num. Вывести на экран результат выражения num – 10. (Подсказка: строка — это массив символов, следовательно, вы можете извлекать символы цифр по их индексам; при вычислении числа первый символ массива, преобразованный в
13
число,
будет означать количество сотен, второй — десятков, а третий — единиц.)
3. Известно, что символ A английского алфавита имеет код 65. Напишите программу, определяющую какие символы в этом алфавите стоят на 5, 12 и 19 местах.
Специальные символыСпециальные символы в программном коде обозначаются двумя символами, т.к. одним их обычно обозначить невозможно. Но по сути представляют собой один символ. Например, букву 'a' можно обозначить одним символом, а как обозначить символ создания новой строки, если ему не соответствует ни один знак? Приходится выкручиваться и представлять такой неординарный символ комбинацией пары других символов:
'\n'
. Помните при этом, что на самом деле это всего лишь один символ.
Ниже перечислен ряд управляющих символов (не все) и то, что они делают:
'\n'
— создание новой строки и переход на нее;
'\t'
— табуляция (отступ в несколько пробелов);
'\r'
— возврат каретки (перевод курсора в первую позицию текущей строки);
'\b'
— возврат курсора на один символ назад с удалением этого символа.
В программном коде, помимо управляющих, специальными символами могут записываться некоторые вполне обычные символы, такие как кавычки, одиночные кавычки, обратная косая черта и др. Некоторые из этих символов можно задать одним символом в одиночных кавычках. Но многие из них невозможно вставить просто так внутрь строки, т.к. они что-то значат с точки зрения синтаксиса языка. Например, обратная косая черта в строке сообщает, что начинается обозначение специального символа, двойная кавычка обозначает начало или конец строки. Поэтому такие символы также обозначаются парной комбинацией других символов:
'\\'
— обратный косая черта;
'\''
— одиночная кавычка;
'\"'
— двойная кавычка (не в строке можно просто '"'
);
'\0'
— пустота, символ с кодом 0 по таблице ASCII.
Задания
1. Напишите программу, в которой бы использовалась табуляция, вывод на экран строки в двойных кавычках, в одиночных кавычках (апострофах), затирание предыдущего символа и возврат каретки (для
последних двух случаев, чтобы увидеть результат, управляющие символы надо вставить внутрь строки). Проверьте, как выводится на экран строка, если в ее середине стоит нулевой символ.
2. Выведите на экран символьное обозначение управляющих символов и их номера по таблице ASCII. Пример вывода:
\n - 10
\t - 9
\b - 8
\r - 13 3. Выясните экспериментальным путем, как вывести на экран символ %. (Существует два способа.)
14
Урок 3. Операторы ветвления
if-else
В языке программирования
C
синтаксис оператора ветвления if-else выглядит так:
if (логич_выражение)
выражение1;
else
выражение2;
Как и в других языках ветка else не является обязательной.
В языке
С
в простых логических выражениях используются следующие знаки операторов: >,
<, >=, <=, ==, !=.
В случае если тело той или иной ветки состоит из нескольких законченных выражений, разделяемых точкой с запятой, то тело заключается в фигурные скобки:
if (логич_выражение) {
выражение1;
выражение2;
…
}
else {
выражениеN;
…
}
Задание
Напишите любую программу на языке
C
, в которой бы использовалась конструкция if-else.
В
C
можно использовать вложенные конструкции if-else
. При этом рекомендуют вкладывать во внешнюю ветку else
, а не if
, т.к. это позволяет избегать неоднозначности толкования инструкции. Посмотрите на такую конструкцию:
if (…)
if (…)
…;
else
…;
else if (…)
…;
else
…;
Для более легкого восприятия человеком отступами подчеркнуто, что куда вложено. Однако для компилятора с языка
C
отступы никакой роли не играют, и принадлежность первой
15
ветки else не очевидна. Ее можно было бы ошибочно отнести к первому if
, в результате чего второе else было бы вообще неуместным, т.к. не относилось бы ни к какому if
. В данном случае такой ошибки не будет, т.к. компилятор руководствуется правилом: ветка else относится к ближайшему к ней сверху if
, у которого еще нет ветки else
. Именно поэтому здесь первое else относится ко второму if
(т.к. оно к нему ближе), а второе else к первому if
, т.к. второе if уже "покрыто" предыдущим else
. Теперь посмотрите вот на такую конструкцию:
if (…)
if (…)
….;
else if (…)
….;
else
….;
Программист отступами показал, что он хочет, чтобы первое else относилось к внешнему if
. Однако компилятор, руководствуясь правилом отнесения веток else
, расценит программу вот так (если перевести на удобство чтения ее программистом):
if (…)
if (…)
….;
else if (…)
….;
else
….;
При этом программа будет делать не то, что хотел программист: если в выражении при первом if будет возвращаться ложь, то ни один else просто не сработает. Однако в таких сложных случаях есть выход — это
использование фигурных скобок, даже если тело условной инструкции состоит всего из одного законченного выражения:
if (…) {
if (…)
….;
}
else if (…)
….;
else
….;
В таком случае программа будет восприниматься компилятором именно так, как задумал программист.
16
Задание
Придумайте и напишите программу, в которой бы использовалась вложенная конструкция if- else.
Условное выражение
В языке программирования
C
существует сокращенная запись инструкции if-else в виде условного выражения, результат которого может быть присвоен переменной:
(логич_выражение) ? выражение1 : выражение2
Переводится это так. Если логич_выражение вернуло истину, то все выражение возвращает
выражение1; если логич_выражение вернуло ложь, то все выражение возвращает
выражение2. Например:
x = 12;
y = 16;
z = (x > y) ? x - 1 : y - 1;
Здесь z получит значение 15. Такое условное выражение бывает очень удобно, однако область его применения ограничена простейшими случаями ветвления, т.к. невозможно создавать сложные "тела" в такой конструкции.
Задание
Напишите программу, в которой бы использовалось условное выражение.
Операторы И (&&) и ИЛИ (||)
Как известно логическое выражение может быть сложным. Логические операторы И и ИЛИ в языке программирования
C
обозначаются соответственно парными знаками амперсанда
(&&) и вертикальной черты (||). Их приоритет меньше, чем у простых логических операторов, поэтому простые логические операции при их объединении в сложные логические выражения можно не заключать в скобки. Пример сложного логического выражения на языке
C
:
a > 100 && b != 0
Задания
1. Напишите программу, в которой при if использовалось бы сложное логическое выражение.
2. Проверьте и объясните, что выводит функция printf(), если ей передать простые или сложные логические выражения. Например:
printf("%d\n", a == b && c < d);
printf("%d\n", c < d);
Оператор switch
При организации множественного выбора бывает удобно использовать не вложенные if- else
, а оператор switch
. Его синтаксис можно описать так:
switch (целая_переменная) {
case константа1:
операции;
case константа2:
операции;
17
….default: опрации;}Это приблизительное, а не точное описание. В скобках после слова switch может стоять не только переменная, но и выражение, результат выполнения которого возвращает целое значение (может быть символ). Константы при case также могут быть результатом выполнения выражений. Константы можно группировать в одном case
(например, case 12,
13, 18
). Ветка default не обязательна.
При выполнении оператора switch
, заданное значение в круглых скобках сравнивается с константами. Как
только совпадение будет найдено, все последующие вложенные во все case операции начинают выполняться. Т.е. происходит нечто странное: выполняются операции веток case
(и default тоже), константы которых не совпадают со значением при switch
. Например, в результате выполнения вот такой программы:
int a=1;
switch (a) {
case 0: printf("%d ", 0);
case 1: printf("%d ", 1);
case 2: printf("%d ", 2);
default: printf("%d ", -1);
}
printf("\n");
на экране будет выведено:
1 2 -1
, т.к. как только совпадение было обнаружено, все нижеследующие инструкции были выполнены.
Чтобы этого не происходило, в конце операций, принадлежащих определенному case
, дописывают оператор break
, который осуществляет принудительный выход из всей конструкции (в данном случае switch
). Например:
int a=1;
switch (a) {
case 0: printf("%d\n", 0);
break;
case 1:
18
printf("%d\n", 1);
break;
case 2: printf("%d\n", 2);
break;
default: printf("%d\n", -1);
}
выведет только единицу, т.к. выполнение всей инструкции switch прервется после выполнения инструкции break при case 1
Задание
Придумайте свою программу с использованием оператора switch.