Переменные. Основные типы данных. Форматный ввод-вывод
Любая программа, суть которой не есть вывод на экран некоторой текстовой информации, содержит описание переменных. Переменная - это пара “имя” - “значение”. Имени соответствует адрес участка памяти, выделенной переменной, а значением является содержимое этого участка. Именем переменной служит идентификатор. В С идентификатор - это последовательность из букв латинского алфавита, десятичных цифр и символов подчеркивания, начинающаяся не с цифры. Прописные и строчные буквы различаются. Примеры идентификаторов:
i, i2, i_2, stroka, STROKA, F_I_O
Каждая переменная и каждое выражение в программе имеет тип, определяющий операции, которые могут над ними производиться. Все типы языка С делят на основные и производные. Переменные типизируются с помощью описаний. Для описания переменных основных типов используют ключевые слова, содержащиеся в таблице 2.
Описание переменных заданного типа имеет следующий формат:
тип имя1 [=иницал._выражение1], имя2 [=иницал._выражение2],…;
где
тип– один из основных типов (таблица 2);
имя – идентификатор;
инициал._выражение – необязательный инициализатор, определяющий начальное значение соответствующего объекта.
Таблица 2. Основные типы данных
Тип данных | Диапазон значений |
char (символьный) | -128…127 |
short (короткий целый) | -32768…32767 |
int (целый) | -32768…32767 |
long (длинный целый) | -2147483648…2147483647 |
unsigned char (беззнаковый символьный) | 0…255 |
unsigned int (беззнаковый целый) | 0…65535 |
unsigned long (беззнаковый длинный целый) | 0…4294967295 |
unsigned short | 0…65535 |
float (вещественный) | 3.4Е-38…3.4Е+38 |
double (вещественный с удвоенной точностью) | 1.7Е-308…1.7Е+308 |
long double (длинный вещественный с удвоенной точностью) | 3.4Е-4932…3.4Е+4932 |
К основному типу можно применять спецификатор const. Это дает тип, имеющий те же свойства, что и исходный тип, за исключением того, что значение переменных типа const не может изменяться после инициализации.
Кроме типов, приведенных в таблице 2, к основным типам относят перечислимый тип enum и тип void (отсутствие значения) (подробнее – в лекциях).
Из основных типов с помощью операций *, &, [], () и механизмов определения структурированных типов (классов, структур, объединений) можно конструировать множество производных типов, которые будут рассмотрены позднее.
Для определения размера (в байтах) области памяти, выделяемой для переменной определенного типа, в С используется операция sizeof. Разрешены два формата операции:
sizeof выражение
или
sizeof (тип данных).
sizeoff не вычисляет значения выражения, а только определяет его тип, для которого затем вычисляется размер. Например, пусть определена переменная int i. Тогда операция sizeof(i) определит, сколько байт выделено для переменой i.
Соотношение между основными типами можно записать так:
1==sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <=sizeof(float) <= sizeof(double)
Для вывода информации используется функция printf().Ее описание содержится в заголовочном файле stdio.h. При этом имеется возможность форматировать данные, то есть влиять на их представление на экране дисплея. Оператор вызова функции можно представить так:
printf(форматная_строка, список аргументов)
Форматная строка записывается в двойных кавычках и может включать произвольный текст, управляющие символы и форматные спецификаторы. Они предназначены для управления формой внешнего представления значений аргументов функции printf() и начинаются с символа %. В список аргументов включают объекты, значения которых должны быть выведены из программы. Это выражения, переменные, константы и функции. Количество аргументов и их типы должны соответствовать последовательности спецификаций преобразования в форматной строке. Список аргументов может отсутствовать. Например:
printf(“\nHello, world!\n”) //здесь нет аргументов, а в форматной
//строке содержится два управляющих символа \n
Обобщенный формат форматного спецификатора:
%флажки ширина_поля.точность модификатор спецификатор
Здесь обязательными являются только два элемента – символ ’%’ и спецификатор.
Ширина_поля –целое положительное число, определяющее длину (в позициях на экране) представления выводимого значения.
Точность-целое положительное число, определяющее количество цифр в дробной части представления вещественного числа (с фиксированной точкой) или его мантиссы (при использовании представления с плавающей точкой)
Модификаторы . Возможные значения:
‘-‘ – выравнивание выводимого значения по левому краю
Модификатор ‘0’ – при использовании модификатора ширины поля пустые позиции слева от значения заполняются пробелами. Использование модификатора ‘0’ позволяет заменить их на нули.
Модификатор ‘l’ позволяет вывести на экран значения типа long int и double
Модификатор ‘h’ позволяет вывести на экран короткие значения (значения с модификатором short)
Спецификаторы. В задачах будем использовать следующие спецификаторы:
d- целое десятичное число (тип int)
c-символ
s-строка
u- беззнаковое целое
f- вещественное число с точностью до 6-го знака
e- вещественное число в экспоненциальной форме с точностью до 6-го знака
g-вещественное число (аналог f или e, но без лишних нулей в конце)
Для ввода данных используется функция scanf(). Так же, как и для функции printf(), для функции scanf() указываются управляющая строка и следующий за ней список аргументов.
Форматные команды, модификаторы и требования к списку аргументов, используемые для работы функции printf() остаются справедливыми и для scanf(), за исключением следующих отличий:
1. printf() работает с переменными, константами и выражениями, в то время как scanf() использует адреса переменных. Более подробно работа с адресами будет рассмотрена позднее. Важно запомнить два требования:
· Если нужно ввести некоторое значение и присвоить его переменной одного из основных типов, то перед именем переменной требуется писать символ &.
· Если требуется ввести значение строковой переменной, то использовать символ & не нужно.
2. Различия в форматных командах:
· Не используется спецификатор %g.
· Спецификаторы %f и %e работают абсолютно одинаково.
Операции и выражения
Выражение - это правило (например, формула) для вычисления нового значения. Выражения в Си могут быть арифметические, логические, условные, над символами и строками и над адресами. Тип выражения определяется типом результата, т. е. значением, которое формируется при выполнении последней операции выражения. Выражения формируются из операндов, операций и круглых скобок, с помощью которых можно задать требуемый порядок выполнения его операций. В качестве операндов могут быть константы, переменные и результаты функций. Результатом выполнения выражения может быть значение одного из допустимых типов: арифметического (целого или вещественного) или символьного. Тип результата определяется как типом операндов, так и типом операций, выполненных над операндами.
Операции делятся на унарные, которые выполняются над одним операндом, и бинарные – над двумя операндами.
Унарные операции:
& | операция получения адреса операнда; |
‘*’ | операция обращения по адресу; |
‘-‘ | унарный минус, изменяет знак арифметического операнда; |
+ | унарный плюс, введен для симметрии с унарным минусом; |
~ | инвертирует значение каждого бита операнда; |
! | НЕ – логическое отрицание операнда; |
++ | увеличение на 1. Эта операция имеет две формы – префиксная операция и постфиксная. Префиксная – увеличение значения операнда на 1 до его использования. Постфиксная – увеличение значения операнда на 1 после его использования; |
-- | уменьшение на 1; |
sizeof | операция вычисления размера (в байтах) для объекта того типа, который имеет операнд; |
Бинарные операции
Аддитивные | |||||||||||||||||||||||||||
+ | бинарный плюс; | ||||||||||||||||||||||||||
- | бинарный минус; | ||||||||||||||||||||||||||
* | умножение операндов арифметического типа; | ||||||||||||||||||||||||||
/ | деление операндов арифметического типа. При целочисленных операндах абсолютное значение результата округляется до целого; | ||||||||||||||||||||||||||
% | получение остатка от деления целочисленных операндов. При неотрицательных операндах остаток положительный. В противном случае – зависит от компилятора. В нашем случае 13%-4 равно 1, а -13%4 равно -1 | ||||||||||||||||||||||||||
Операции сдвига | |||||||||||||||||||||||||||
<< | Операции сдвига << и >> выполняют сдвиг левого операнда влево или вправо на количество разрядов, заданное правым операндом. Таким образом, выражение х << 2 сдвигает х влево на 2 разряда; это эквивалентно умножению х на 4. Таким образом, операции сдвига могут применяться для деления или умножения целого значения на число, равное степени 2. | ||||||||||||||||||||||||||
>> | |||||||||||||||||||||||||||
Поразрядные операции (битовые) Работают в двоичной системе | |||||||||||||||||||||||||||
& x&y | Поразрядная коньюнкция (И) битовых представлений целочисленных операндов. Каждый бит результата будет содержать 1, если в соответствующих битах операндов тоже стоят 1. Например 10&15 (1010&1111) будет 10 (1010) | ||||||||||||||||||||||||||
| | Поразрядная дизъюнкция (битовое ИЛИ). Каждый бит результата будет содержать 1, если хотя бы в одном из соответствующих битов операндов стоит 1. Например 10|15 (1010|1111) будет 15 (1111) | ||||||||||||||||||||||||||
^ | Поразрядное исключающее ИЛИ. Каждый бит результата будет содержать 1, если только в одном из соответствующих битов операндов стоит 1. Например 10^15 (1010^1111) будет 5 (0101) | ||||||||||||||||||||||||||
Операции отношений (сравнения) | |||||||||||||||||||||||||||
< | 1) Используются для сравнения значений. Результат целочисленный – 0(ложь) или 1(истина). Примеры операций отношения: int a, b,i,n; float с, d; а = d > с; b = i + n < 100; | ||||||||||||||||||||||||||
> | |||||||||||||||||||||||||||
<= | |||||||||||||||||||||||||||
>= | |||||||||||||||||||||||||||
== | |||||||||||||||||||||||||||
!= | |||||||||||||||||||||||||||
Логические бинарные операции | |||||||||||||||||||||||||||
&& | Коньюнкция арифметических операндов. Результат целочисленный – 0(ложь) или 1(истина) | ||||||||||||||||||||||||||
|| | Дизъюнкция арифметических операндов. Результат целочисленный – 0(ложь) или 1(истина) | ||||||||||||||||||||||||||
Операндами этих логических операций могут быть результаты выражений любого типа. Но перед выполнением логических операций значения результатов выражений-операндов преобразуются в логические значения истина - 1 или ложь - 0. Все значения, отличные от 0, интерпретируются как истинные - 1, а если значение равно 0, то оно ложно. Результат логической oneрации равен 1, если логическое выражение истинно, и результат равен 0, если логическое выражение ложно. Таблица 3. Результат логических операций
| |||||||||||||||||||||||||||
Операции присваивания | |||||||||||||||||||||||||||
= | Простое присваивание: присвоить значение выражения-операнда из правой части операнду левой части. p=10.3-2*x С помощью одного оператора присваивания могут получить новое значение несколько переменных. Например, переменные а, b, с, е получат значение, равное нулю: а = b = с = е = 0 ; В одном операторе операция присваивания может использоваться несколько раз. Например: а = ( b = с ) * d ; здесь сначала переменной b присваивается значение переменной с, а затем вычисляется выражение b*d и результат присваивается переменной а. | ||||||||||||||||||||||||||
*= | Присваивание после умножения: присвоить операнду левой части произведение значений обоих операндов. То есть p*=2 эквивалентно p=p*2 | ||||||||||||||||||||||||||
/= | Присваивание после деления. p/=2-x эквивалентно p=p/(2-x) | ||||||||||||||||||||||||||
%= | Присваивание после деления по модулю. присвоить операнду левой части остаток от целочисленного деления значения левого операнда на значение правого. p%=3 эквивалентно p=p%3 | ||||||||||||||||||||||||||
+= | Присваивание после суммирования | ||||||||||||||||||||||||||
-= | Присваивание после вычитания. p-=4-z эквивалентно p=p-(4-z) | ||||||||||||||||||||||||||
&= | Присваивание после поразрядной коньюнкции. e&=44 Û e=e&44 | ||||||||||||||||||||||||||
|= | Присваивание после поразрядной дизъюнкции. e|=c Û e=e|c | ||||||||||||||||||||||||||
^= | Присваивание после поразрядного исключающего ИЛИ | ||||||||||||||||||||||||||
<<= | Присваивание после сдвигов разрядов влево. a<<=4 Û a=a<<4 | ||||||||||||||||||||||||||
>>= | Присваивание после сдвигов разрядов вправо | ||||||||||||||||||||||||||
Операции выбора компонентов структурированного объекта | |||||||||||||||||||||||||||
. (точка) | Используются со сложными типами данных – структурами и объединениями. | ||||||||||||||||||||||||||
-> | |||||||||||||||||||||||||||
Запятая в качестве операции | |||||||||||||||||||||||||||
, | Несколько выражений, разделенных запятыми вычисляются слева направо. В качестве результата – значение и тип самого правого выражения. Например: int a,b; a=(b=3,3*b) printf(“%d”,a) //даст результат 9 | ||||||||||||||||||||||||||
Скобки | |||||||||||||||||||||||||||
(), [] | Играют роль бинарных операций при вызове функций и индексировании элементов массива. | ||||||||||||||||||||||||||
Условная трехместная операция | |||||||||||||||||||||||||||
?: | Используется с тремя операндами (тернарная). Синтаксис: Выражение1?выражение2:выражение3 Первым вычисляется значение выражения1. Если оно истинно, то есть не равно 0, то вычисляется значение выражения 2, которое и становится результатом. Если при высичлении выражения1 получится 0, то вычисляется и берется в качестве результата выражение3. Пример: x<0?-x:x // выражение возвращает абсолютную величину x |
При выполнении смешанных выражений автоматически производится преобразование операндов к одному типу в соответствии с приоритетами. Ниже приведен порядок следования типов по возрастанию их старшинства:
char<int<long<float<double
Автоматически выполняются следующие преобразования типов:
1. char преобразуется в int, float в double
2. если старшим типом является double, то все остальные типы преобразуются в double. Таким же будет и тип результата.
3. если старшим типом является long, то все остальные типы преобразуются в long. Таким же будет и тип результата.
4. если старшим типом является unsigned, то все остальные типы преобразуются в unsigned. Таким же будет и тип результата.
Если не выполняется ни одно из предыдущих условий и выражение содержит значение типа int, то результат будет int. Существует одно исключение из этих правил. Если выражение содержит типы long и unsigned, то unsigned не преобразуется к long. Типом результата будет usigned long.
Часто возникают ситуации, когда желательно вместо целых значений использовать вещественные.
Рассмотрим пример:
int x,y;
float z;
x=10;
y=100;
z=x/y;
В результате вычислений переменная z получит значение 0 как целое число, а не 0.1 как вещественное. В подобных ситуациях часто прибегают к явному преобразованию типов с помощью следующей конструкции:
(имя-типа) выражение
где тип –корректный тип данных С. Например, для получения правильного значения при вычислении выражения a/b, где a и b целые числа необходимо преобразовать результат к типу float:
(float)a/b;
Операторы ветвления
Условные выражения позволяют изменять порядок выполнения программных элементов. В зависимости от условия выполняются те, или иные альтернативные действия. Для проверки условных выражений и выбора альтернативного действия используются операторы ветвления.
К операторам ветвления в языке С относят условную конструкцию if и переключатель switch.
Конструкция if.Сокращенный оператор if имеет следующую структуру:
if (выражение_условие) оператор;
Выражение_условие может быть арифметическим выражением, отношением и логическим выражением. Оно должно записываться в круглых скобках. От его истинности зависит, будет или не будет выполняться действие, задаваемое следующим далее оператором. Операторы и в сокращенном, и в полном вариантах if могут быть как отдельными, так и составными (несколько действий внутри блочного оператора). Некоторые простые операторы if могут быть с удобством заменены условной трехместной операцией . Например,
if (a <= b) max = b;
else max = a;
лучше выражается так:
max = (a<=b) ? b : a;
Конструкция if… else.Полная форма оператора if:
if (выражение_условие) оператор1; else оператор2;
В полном операторе if оператор1 выполняется в том случае, если выражение ненулевое (то есть истинное), иначе выполняется оператор2или не выполняются никакие действия, если оператор2не задан, то есть отсутствует else. В частности, если a целое, то if (a) эквивалентно if (a != 0).
Множественный выбор – конструкция ‘else –if’.Оператор if позволяет выполнять, или не выполнять некоторое действие. Конструкция if…else дает возможность выбрать одно из двух действий. В то же время, очень часто удобно выбирать не одно из двух, а одно из нескольких условий. Для этой цели служит конструкция if-else. Она имеет следующий синтаксис:
if (выражение_условие) оператор;
else
if (выражение_условие) оператор;
else
if (выражение_условие) оператор;
.
.
else оператор;
Отступы справа при записи не являются обязательными, но считаются хорошим стилем программирования. Однако, если степеней вложения if много, то это не удобно. Поэтому, при использовании большой степени вложенности оператора if часто применяют следующую форму записи:
if (выражение_условие)
оператор;
else if (выражение_условие)
оператор;
else if (выражение_условие)
оператор;
else
оператор;
Если ни одно из условий не является истинным, то выполняется последняя “ветка” else. Если ее нет, то никаких действий не выполняется.
Вложенные операторы if.Вложенные операторы if представляют собой конструкцию, в которой внутрь ветви одного if вложен другой оператор if. В соответствии со стандартом ANSI компиляторы оюязаны поддерживать не менее 15 уровней вложенности. Но большинство позволяют и более. При этом подключенная ветвь else относится к ближайшему оператору if. В следующем примере
if (n>0)
if (a>b)
z=a;
else
z=b;
ветвь else относится к вложенному if, так как именно он является ближайшим. Если же необходимо, чтобы в этом примере ветвь else относилась к внешнему if, то необходимо воспользоваться блочным оператором {}:
if (n>0)
{
if (a>b)
z=a;
}
else
z=b;
Оператор switch.Оператор switch позволяет осуществить множественный выбор, сравнивая значение выражения с набором целочисленных или символьных констант. Этот оператор называют также переключателем. Переключатель является наиболее удобным средством для организации мультиветвления. Синтаксис переключателя:
switch (перключающее_выражение)
{
case константа1: оператор1; break;
case константна2: оператор2; break;
. . .
case константнаn: операторn; break;
default:оператор;
}
Здесь switch, case, default, break являются ключевыми словами, а оператор может быть и простым и составным, причем заключать последовательность операторов в фигурные скобки необязательно. Выражение, стоящее после switch должно быть заключено в круглые скобки, а все тело оператора switch в фигурные. Управляющая конструкция switchпередает управление к тому из помеченных с помощью case операторов, для которого значение константы совпадает со значением переключающего выражения. Переключающее_выражение должно быть целочисленным или его значение должно приводится к целочисленному. В одном переключателе все константы должны иметь различные значения, но быть одного типа. Любой из операторов может быть помечен одной или несколькими метками вида case константа: , например, может использовать конструкция вида
case константа1: case константа2: оператор;
Если значение переключающего_выражения не совпадает ни с одной из констант, то выполняется переход к оператору, отмеченному меткой default, которая может и отсутствовать (при этом не выполняются никакие действия). Если не предусмотрены переходы и выходы из переключателя, то в нем последовательно выполняются все операторы, начиная с той метки, на которую передано управление. Для выхода из переключателя обычно используют оператор break.