Форматы переменных в си

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

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

  • Статическая типизация — контроль типов осуществляется при компиляции.
  • Динамическая типизация — контроль типов осуществляется во время выполнения.

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

Различают простые, составные и прочие типы данных.

Простые данные

Простые данные можно разделить на

  • целочисленные,
  • вещественные,
  • символьные
  • логические.

Составные (сложные) данные

  • Массив — индексированный набор элементов одного типа.
  • Строковый тип — массив, хранящий строку символов.
  • Структура — набор различных элементов (полей записи), хранимый как единое целое и предусматривающий доступ к отдельным полям структуры.

Другие типы данных

  • Указатель — хранит адрес в памяти компьютера, указывающий на какую-либо информацию, как правило — указатель на переменную.

Программа, написанная на языке Си, оперирует с данными различных типов. Все данные имеют имя и тип. Обращение к данным в программе осуществляется по их именам (идентификаторам).

Идентификатор — это последовательность, содержащая не более 32 символов, среди которых могут быть любые буквы латинского алфавита a — z, A — Z, цифры 0 — 9 и знак подчеркивания (_). Первый символ идентификатора не должен быть цифрой.

Несмотря на то, что допускается имя, имеющее до 32 символов, определяющее значение имеют только первые 8 символов. Помимо имени, все данные имеют тип. Указание типа необходимо для того, чтобы было известно, сколько места в оперативной памяти будет занимать данный объект.

Компилятор языка Си придерживается строгого соответствия прописных и строчных букв в именах идентификаторов и лексем.

Верно Неверно
int a = 2, b;
b = a+3;
Int a=2; // правильно int
INT a=2; int a = 2, b;
b = A + 3; // идентификатор А не объявлен int a = 2;
b = a + 3; // идентификатор b не объявлен

Целочисленные данные

Целочисленные данные могут быть представлены в знаковой и беззнаковой форме.

Беззнаковые целые числа представляются в виде последовательности битов в диапазоне от 0 до 2 n -1, где n-количество занимаемых битов.

Знаковые целые числа представляются в диапазоне -2 n-1 …+2 n-1 -1. При этом старший бит данного отводится под знак числа (0 соответствует положительному числу, 1 – отрицательному).

Основные типы и размеры целочисленных данных:

Количество бит Беззнаковый тип Знаковый тип
8 unsigned char
0…255
char
-128…127
16 unsigned short
0…65535
short
-32768…32767
32 unsigned int int
64 unsigned long int long int

Вещественные данные

Вещественный тип предназначен для представления действительных чисел. Вещественные числа представляются в разрядной сетке машины в нормированной форме.

Нормированная форма числа предполагает наличие одной значащей цифры (не 0) до разделения целой и дробной части. Такое представление умножается на основание системы счисления в соответствующей степени. Например, число 12345,678 в нормированной форме можно представить как

12345,678 = 1,2345678·10 4

Число 0,009876 в нормированной форме можно представить как

0,009876 = 9,876·10 -3

В двоичной системе счисления значащий разряд, стоящий перед разделителем целой и дробной части, может быть равен только 1. В случае если число нельзя представить в нормированной форме (например, число 0), значащий разряд перед разделителем целой и дробной части равен 0.

Значащие разряды числа, стоящие в нормированной форме после разделителя целой и дробной части, называются мантиссой числа .

В общем случае вещественное число в разрядной сетке вычислительной машины можно представить в виде 4 полей.

  • знак — бит, определяющий знак вещественного числа (0 для положительных чисел, 1 — для отрицательных).
  • степень — определяет степень 2, на которую требуется умножить число в нормированной форме. Поскольку степень 2 для числа в нормированной форме может быть как положительной, так и отрицательной, нулевой степени 2 в представлении вещественного числа соответствует величина сдвига, которая определяется как

2 n -1,

где n — количество разрядов, отводимых для представления степени числа.

  • целое — бит, который для нормированных чисел всегда равен 1, поэтому в некоторых представлениях типов этот бит опущен и принимается равным 1.
  • мантисса — значащие разряды представления числа, стоящие после разделителя целой и дробной части в нормированной форме.
  • Различают три основных типа представления вещественных чисел в языке Си:

    Тип Обозна-
    чение в Си
    Кол-во бит Биты степени Мантисса Сдвиг
    простое float 32 30…23 22…0 127
    двойной точности double 64 62…52 51…0 1023
    двойной расширен- ной точности long double 80 78…64 62…0 16383
    Читайте также:  Как найти местоположение человека через телефон

    Как видно из таблицы, бит целое у типов float и double отсутствует. При этом диапазон представления вещественного числа состоит из двух диапазонов, расположенных симметрично относительно нуля. Например, диапазон представления чисел типа float можно представить в виде:

    Пример : представить число -178,125 в 32-разрядной сетке (тип float ).

    Для представления числа в двоичной системе счисления преобразуем отдельно целую и дробную части:

    178,12510 = 10110010,0012=1,0110010001·2 111

    Для преобразования в нормированную форму осуществляется сдвиг на 7 разрядов влево).

    Для определения степени числа применяем сдвиг:

    0111111+00000111 = 10000110.

    Таким образом, число -178,125 представится в разрядной сетке как

    Символьный тип

    Символьный тип хранит код символа и используется для отображения символов в различных кодировках. Символьные данные задаются в кодах и по сути представляют собой целочисленные значения. Для хранения кодов символов в языке Си используется тип char .
    Подробнее о кодировке символов

    Логический тип

    Логический тип применяется в логических операциях, используется при алгоритмических проверках условий и в циклах и имеет два значения:

    В программе должно быть дано объявление всех используемых данных с указанием их имени и типа. Описание данных должно предшествовать их использованию в программе.

    Основной задачей программирования является обработка информации, поэтому любой язык программирования имеет средства для ввода и вывода информации. В языке Си нет операторов ввода-вывода.

    Ввод и вывод информации осуществляется через функции стандартной библиотеки. Прототипы рассматриваемых функций находятся в файле stdio.h . Эта библиотека содержит функции

    • printf() — для вывода информации
    • scanf() — для ввода информации.

    Вывод информации

    Функция printf() предназначена для форматированного вывода. Она переводит данные в символьное представление и выводит полученные изображения символов на экран. При этом у программиста имеется возможность форматировать данные, то есть влиять на их представление
    на экране.

    Общая форма записи функции printf() :

    СтрокаФорматов состоит из следующих элементов:

    • управляющих символов;
    • текста, представленного для непосредственного вывода;
    • форматов, предназначенных для вывода значений переменных различных типов.

    Объекты могут отсутствовать.

    Управляющие символы не выводятся на экран, а управляют расположением выводимых символов. Отличительной чертой управляющего символа является наличие обратного слэша ‘’ перед ним.

    Основные управляющие символы:


    • ’ — перевод строки;
    • ‘ ’ — горизонтальная табуляция;
    • ‘v’ — вертикальная табуляция;
    • ‘’ — возврат на символ;

    • ’ — возврат на начало строки;
    • ‘a’ — звуковой сигнал.

    Форматы нужны для того, чтобы указывать вид, в котором информация будет выведена на экран. Отличительной чертой формата является наличие символа процент ‘%’ перед ним:

    • %d — целое число типа int со знаком в десятичной системе счисления;
    • %u — целое число типа unsigned int ;
    • %x — целое число типа int со знаком в шестнадцатеричной системе счисления;
    • %o — целое число типа int со знаком в восьмеричной системе счисления;
    • %hd — целое число типа short со знаком в десятичной системе счисления;
    • %hu — целое число типа unsigned short ;
    • %hx — целое число типа short со знаком в шестнадцатеричной системе счисления;
    • %ld — целое число типа long int со знаком в десятичной системе счисления;
    • %lu — целое число типа unsigned long int ;
    • %lx — целое число типа long int со знаком в шестнадцатеричной системе счисления;
    • %f — вещественный формат (числа с плавающей точкой типа float );
    • %lf — вещественный формат двойной точности (числа с плавающей точкой типа double );
    • %e — вещественный формат в экспоненциальной форме (числа с плавающей точкой типа float в экспоненциальной форме);
    • %c — символьный формат;
    • %s — строковый формат.

    Строка форматов содержит форматы для вывода значений. Каждый формат вывода начинается с символа % . После строки форматов через запятую указываются имена переменных, которые необходимо вывести.
    Количество символов % в строке формата должно совпадать с количеством переменных для вывода. Тип каждого формата должен совпадать с типом переменной, которая будет выводиться на это место. Замещение форматов вывода значениями переменных происходит в порядке их следования.
    Пример на Си

    Результат работы программы

    Тот же самый код может быть представлен с использованием одного вызова printf :

    Табличный вывод

    При указании формата можно явным образом указать общее количество знакомест и количество знакомест, занимаемых дробной частью:

    В приведенном примере 10 — общее количество знакомест, отводимое под значение переменной; 5 — количество позиций после разделителя целой и дробной части (после десятичной точки). В указанном примере количество знакомест в выводимом числе меньше 10, поэтому свободные знакоместа слева от числа заполняются пробелами. Такой способ форматирования часто используется для построения таблиц.

    Ввод информации

    Функция форматированного ввода данных с клавиатуры scanf() выполняет чтение данных, вводимых с клавиатуры, преобразует их во внутренний формат и передает вызывающей функции. При этом программист задает правила интерпретации входных данных с помощью спецификаций форматной строки.
    Общая форма записи функции scanf( ) :

    Строка форматов аналогична функции printf() .
    Для формирования адреса переменной используется символ амперсанд ‘&’ :
    адрес = &объект

    Читайте также:  Blu ray или dvd

    Строка форматов и список аргументов для функции обязательны.

    Результат работы программы:

    Функция scanf( ) является функцией незащищенного ввода, т.к. появилась она в ранних версиях языка Си. Поэтому чтобы разрешить работу данной функции в современных компиляторах необходимо в начало программы добавить строчку

    Другой вариант — воспользоваться функцией защищенного ввода scanf_s( ) , которая появилась несколько позже, но содержит тот же самый список параметров.

    Переменные

    П еременные используются для хранения значений (sic!). Переменная характеризуется типом и именем. Начнём с имени. В си переменная может начинаться с подчерка или буквы, но не с числа. Переменная может включать в себя символы английского алфавита, цифры и знак подчёркивания. Переменная не должна совпадать с ключевыми словами (это специальные слова, которые используются в качестве управляющих конструкций, для определения типов и т.п.)

    auto double int struct
    break else long switch
    register typedef char extern
    return void case float
    unsigned default for signed
    union do if sizeof
    volatile continue enum short
    while inline

    А также ряд других слов, специфичных для данной версии компилятора, например far, near, tiny, huge, asm, asm_ и пр.

    Например, правильные идентификаторы
    a, _, _1_, Sarkasm, a_long_variable, aLongVariable, var19, defaultX, char_type
    неверные
    1a, $value, a-long-value, short

    Си — регистрозависимый язык. Переменные с именами a и A, или end и END, или perfectDark и PerfectDarK – это различные переменные.

    Типы переменных

    Т ип переменной определяет

    • 1) Размер переменной в байтах (сколько байт памяти выделит компьютер для хранения значения)
    • 2) Представление переменной в памяти (как в двоичном виде будут расположены биты в выделенной области памяти).

    В си несколько основных типов. Разделим их на две группы — целые и числа с плавающей точкой.

    Целые

    • char — размер 1 байт. Всегда! Это нужно запомнить.
    • short — размер 2 байта
    • int — размер 4 байта
    • long — размер 4 байта
    • long long — размер 8 байт.

    Здесь следует сделать замечание. Размер переменных в си не определён явно, как размер в байтах. В стандарте только указано, что

    Указанные выше значения характерны для компилятора VC2012 на 32-разрядной машине. Так что, если ваша программа зависит от размера переменной, не поленитесь узнать её размер.

    Теперь давайте определим максимальное и минимальное число, которое может хранить переменная каждого из типов. Числа могут быть как положительными, так и отрицательными. Отрицательные числа используют один бит для хранения знака. Иногда знак необходим (например, храним счёт в банке, температуру, координату и т.д.), а иногда в нём нет необходимости (вес, размер массива, возраст человека и т.д.). Для этого в си используется модификатор типа signed и unsigned. unsigned char — все 8 бит под число, итого имеем набор чисел от 00000000 до 11111111 в двоичном виде, то есть от 0 до 255 signed char от -128 до 128. В си переменные по умолчанию со знаком. Поэтому запись char и signed char эквивалентны.

    Таб. 1 Размер целых типов в си.

    Тип Размер, байт Минимальное значение Максимальное значение
    unsigned char 1 255
    signed char
    ( char )
    1 -128 127
    unsigned short 2 65535
    signed short
    ( short )
    2 -32768 32767
    unsigned int
    ( unsigned )
    4 4294967296
    signed int
    ( int )
    4 -2147483648 2147483647
    unsigned long 4 4294967296
    signed long
    ( long )
    4 -2147483648 2147483647
    unsigned long long 8 18446744073709551615
    signed long long
    ( long long )
    8 -9223372036854775808 9223372036854775807

    sizeof

    В си есть оператор, который позволяет получить размер переменной в байтах. sizeof переменная, или sizeof(переменная) или sizeof(тип). Это именно оператор, потому что функция не имеет возможности получить информацию о размере типов во время выполнения приложения. Напишем небольшую программу чтобы удостовериться в размерах переменных.

    (Я думаю ясно, что переменные могут иметь любое валидное имя). Эту программу можно было написать и проще

    В си один и тот же тип может иметь несколько названий
    short === short int
    long === long int
    long long === long long int
    unsigned int === unsigned

    Типы с плавающей точкой

    • float — 4 байта,
    • long float — 8 байт
    • double — 8 байт
    • long double — 8 байт.

    Здесь также приведены значения для VC2012, по стандарту размер типов float Таб. 2 Размер типов с плавающей точкой в си.

    Тип Размер, байт Количество значащих знаков мантиссы Минимальное значение Максимальное значение float 4 6-7 1.175494351 E – 38 3.402823466 E + 38 double 8 15-16 2.2250738585072014 E – 308 1.7976931348623158 E + 308

    Переполнение переменных

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

    Вообще, поведение при переполнении переменной определено только для типа unsigned: Беззнаковое целое сбросит значение. Для остальных типов может произойти что угодно, и если вам необходимо следить за переполнением, делайте это вручную, проверяя аргументы, либо используйте иные способы, зависящие от компилятора и архитектуры процессора.

    Постфиксное обозначение типа

    П ри работе с числами можно с помощью литер в конце числа явно указывать его тип, например

    • 11 — число типа int
    • 10u — unsigned
    • 22l или 22L — long
    • 3890ll или 3890LL — long long (а также lL или Ll)
    • 80.0f или 80.f или 80.0F — float (обязательно наличие десятичной точки в записи)
    • 3.0 — число типа double

    Экспоненциальная форма записи также по умолчанию обозначает число типа double.

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

    Шестнадцатеричный и восьмеричный формат

    В о время работы с числами можно использовать шестнадцатеричный и восьмеричный формат представления. Числа в шестнадцатиричной системе счисления начинаются с 0x, в восьмеричной системе с нуля. Соответственно, если число начинается с нуля, то в нём не должно быть цифр выше 7:

    Экспоненциальная форма представления чисел

    Э кспоненциальной формой представления числа называют представление числа в виде M e ± p , где M — мантиса числа, p — степень десяти. При этом у мантисы должен быть один ненулевой знак перед десятичной запятой.
    Например 1.25 === 1.25e0, 123.5 === 1.235e2, 0.0002341 === 2.341e-4 и т.д.
    Представления 3.2435e7 эквивалентно 3.2435e+7
    Существеут и другое представление ("инженерное"), в котором степень должна быть кратной тройке. Например 1.25 === 1.25e0, 123.5 === 123.5e0, 0.0002341 === 234.1e-6, 0.25873256 === 258.73256e-3 и т.д.

    Объявление переменных

    В си переменные объявляются всегда в начале блока (блок — участок кода ,ограниченный фигурными скобками)

    При объявлении переменной пишется её тип и имя.

    Можно объявить несколько переменных одного типа, разделив имена запятой

    Здесь объявлены переменные a и b внутри функции main, и переменная z внутри тела цикла. Следующий код вызовет ошибку компиляции

    Это связано с тем, что объявление переменной стоит после оператора присваивания. При объявлении переменных можно их сразу инициализировать.
    int i = 0;
    При этом инициализация при объявлении переменной не считается за отдельный оператор, поэтому следующий код будет работать

    Начальное значение переменной

    О чень важно запомнить, что переменные в си не инициализируются по умолчанию нулями, как во многих других языках программирования. После объявления переменной в ней хранится "мусор" — случайное значение, которое осталось в той области памяти, которая была выделена под переменную. Это связано, в первую очередь, с оптимизацией работы программы: если нет необходимости в инициализации, то незачем тратить ресурсы для записи нулей (замечание: глобальные переменные инициализируются нулями, почему так, читайте в этой статье).

    Если выполнять эту программу на VC, то во время выполнения вылетит предупреждение
    Run-Time Check Failure #3 — The variable ‘i’ is being used without being initialized.
    Если нажать "Продолжить", то программа выведет "мусор". В многих других компиляторах при выполнении программы не будет предупреждения.

    Область видимости переменной

    П еременные бывают локальными (объявленными внутри какой-нибудь функции) и глобальными. Глобальная переменная видна всем функциям, объявленным в данном файле. Локальная переменная ограничена своей областью видимости. Когда я говорю, что переменная "видна в каком-то месте", это означает, что в этом месте она определена и её можно использовать. Например, рассмотрим программу, в которой есть глобальная переменная

    Будет выведено
    foo: 100
    bar: 333
    Здесь глобальная переменная global видна всем функциям. Но аргумент функции затирает глобальную переменную, поэтому при передаче аргумента 333 выводится локальное значение 333.
    Вот другой пример

    Программа выведет 555. Также, как и в прошлом случае, локальная переменная "важнее". Переменная, объявленная в некоторой области видимости не видна вне её, например

    Этот пример не скомпилируется, потому что переменная y существует только внутри своего блока.
    Вот ещё пример, когда переменные, объявленные внутри блока перекрывают друг друга

    Программа выведет
    30
    20
    10
    Глобальных переменных необходимо избегать. Очень часто можно услышать такое. Давайте попытаемся разобраться, почему. В ваших простых проектах глобальные переменные выглядят вполне нормально. Но представьте, что у вас приложение, которое

    • 1) Разрабатывается несколькими людьми и состоит из сотен тысяч строк кода
    • 2) Работает в несколько потоков

    Во-первых, глобальная переменная, если она видна всем, может быть изменена любой частью программы. Вы изменили глобальную переменную, хотите её записать, а другая часть программы уже перезаписала в неё другое значение (на самом деле это целый класс проблем, которые возникают в многопоточной среде). Во-вторых, при больших размерах проекта не уследить, кто и когда насоздавал глобальных переменных. В приведённых выше примерах видно, как переменные могут перекрывать друг друга, то же произойдёт и в крупном проекте.

    Безусловно, есть ситуации, когда глобальные переменные упрощают программу, но такие ситуации случаются не часто и не в ваших домашних заданиях, так что НЕ СОЗДАВАЙТЕ ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ!
    Переменные могут быть не только целочисленными и с плавающей точкой. Существует множество других типов, которые мы будем изучать в дальнейшем.

    Оставьте ответ

    Ваш адрес email не будет опубликован. Обязательные поля помечены *