Типы данных и их вывод в языке программирования C

В этом уроке мы познакомимся с особенностями функции printf() и типами данных: целыми и вещественными числами, символами, массивами и строками. Это далеко не все допустимые в C типы. Есть еще указатели, структуры, объединения, перечисления, также имеется возможность определять собственные типы данных.

Функция printf() и форматированный вывод

Вывод символов на экран, а точнее в стандартный поток вывода, осуществляется в языке C помощью функции printf(). Эта функция выводит на экран строку, переданную первым аргументом, предварительно заменив в ней специальные комбинации символов преобразованными в символы данными, переданными последующими аргументами. Сами данные могут быть строками, символами, целыми или вещественными числами, а также указателями. У каждого типа данных имеется свое обозначение ‒ своя спецификация формата.

На прошлом уроке мы выводили строку "Hello World" вот так:

printf("Hello World\n");

Однако то же самое можно сделать так:

printf("%s\n", "Hello World");

Здесь %s — это спецификация строкового формата, т. е. вместо %s будет подставлен следующий аргумент, данные которого должны быть строкой.

Пример вывода целого числа:

printf("%d\n", 5);

Вместо числа 5 может стоять переменная целочисленного типа.

Функция printf() может принимать произвольное число аргументов:

printf("%d %s, %d %s.\n", 3, "dogs", 2, "cats");

При выводе данные подставляются по очередности следования: 3 на место первой спецификации, "dogs" на место второй и т.д. То есть следует строго соблюдать соответствие форматов и последующих данных.

Под выводимые данные можно выделять больше знакомест, чем необходимо. Для этого между знаком % и буквой формата прописывается целое число, обозначающие ширину поля, например так: %10d. По умолчанию выравнивание происходит по правому краю. Для выравнивания по левому краю перед числом ставится знак минус.

Напишите программу, которая выводила бы на экране данные примерно так, как на картинке. При этом используйте возможность задать ширину поля, а также выравнивание по левому и правому краям.

Целочисленные типы

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

Так, если под переменную какого-либо целочисленного типа выделяется 2 байта, что составляет 16 бит, и ей можно присваивать только положительные числа и ноль, то эти числа будут в диапазоне от 0 до 65535, т. к. 216 = 65536, но одна вариация забирается на нуль. Если же тип допускает отрицательные числа, то диапазон допустимых значений уже будет лежать в пределах от -32768 до +32767.

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

#include <stdio.h>
 
int main() {
 
    int lines, i;
    int count = 0;
 
    lines = 100;
    i = -1;
 
    printf("%5d %5d %5d\n", i, count + 10, lines);
}

Обратите внимание, что в Си присваивать значение можно при объявлении переменных.

Обычно под переменную типа int, которая может принимать как положительные так и отрицательные значения, отводится 4 байта, что равно 32-м битам. Отсюда допустимый диапазон значений будет лежать в пределах от -2 147 483 648 до 2 147 483 647. Однако если переменной присвоить максимально допустимое для ее типа значение, а потом увеличивать его, то сообщений об ошибке не будет ни на этапе компиляции, ни на этапе выполнения.

#include <stdio.h>
 
int main() {
    int max = 2147483647;
 
    printf("%d\n", max);
 
    max = max + 1;
    printf("%d\n", max);
 
    max = max + 9;
    printf("%d\n", max);
}

Результат будет таким:

2147483647
-2147483648
-2147483639

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

То же самое с минимумом int. Если мы начнем из него вычитать, т. е. двигаться против часовой стрелки, то перескочим максимальную границу и будем идти в направлении уменьшения уже от нее:

#include <stdio.h>

int main() {
    int min = -2147483648;

    printf("%d\n", min-1);
    printf("%d\n", min-2);
    printf("%d\n", min-10);
}

Результат:

2147483647
2147483646
2147483638

Помимо типа int в языке программирования C существуют другие (модифицированные) целочисленные типы:

При выводе длинных чисел следует дополнять спецификацию формата буквой 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 <stdio.h>
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);
}

выдает такой результат:

? == 63
r == 114
b, c

Число 63 по таблице символов ASCII соответствует знаку '?'. Сначала мы выводим значение переменной ch в формате символа, затем – числа. Тоже самое с переменной uch, однако ее значение было задано через символ, а не число.

Вещественные типы данных

В языке C существует три типа чисел с плавающей точкой: float и double (двойной точности) и long double. Также существует три формата вывода вещественных чисел, причем они не связаны с типами, а связаны с удобством представления числа. Вещественные числа могут иметь высокую точность, очень маленькое или очень большое значение. Если выполнить функции printf() с такими параметрами:

double a = 0.0005;
printf("%f\n", a);
printf("%g\n", 0.0005);
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 * 103, что равно 4325. Если с такой формой представления чисел вы сталкиваетесь первый раз, то почитайте дополнительные источники, например, статью в Википедии "Экспоненциальная запись".

Формат %e выведет число исключительно в нормализованном виде, каким бы это вещественное число ни было.

Если при выводе требуется округлить число до определенной точности, то перед буквой-форматом ставят точку и число-указатель точности. Например, printf("%.2f", 0.23) выведет на экран 0.23, а не 0.230000. Когда требуется указать еще и поле, то его ширину прописывают перед точкой, например, %10.3f.

Массивы

Чтобы в языке 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];

f_arr[0] = 25.3;
f_arr[4] = 34.2;
printf("%c, %.2f\n", vowels[4], f_arr[0]);

Когда переменная-массив объявляется и сразу определяется (как в случае vowels), то размер массива можно не указывать, т. к. он вычисляется по количеству элементов, переданных в фигурных скобках.

Строки

В языке программирования С нет отдельного строкового типа данных, хотя формат вывода строки есть (%s). Строки в Си – это массивы символов, последний элемент которых является первым (с номером 0) символом в таблице ASCII. В этом месте таблицы стоит "ничто", которое обозначается в исходном коде как символ '\0'.

Однако строки ‒ это не обычные массивы. В том смысле, что работа с ними несколько отличается от работы с другими типами массивов. В этом мы убедимся позже.

Выше мы объявили и определили массив 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));

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

Пример выполнения программы в Ubuntu

Курс с решением задач:
pdf-версия


Основы языка C. Курс




Все разделы сайта