Урок 1. Типы данных и их вывод

Особенности языка С. Учебное пособие

Эта тема не так проста как кажется. Точнее она проста, но достаточно объемна по количеству информации. Лучше в ней разобраться до конца и запомнить некоторые вещи наизусть.

На этом уроке мы познакомимся с особенностями функции printf() и типами данных: целыми и вещественными числами, символами, массивами и строками. Это далеко не все допустимые в C типы. Есть еще указатели, структуры, объединения, перечисления, также в 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. По умолчанию выравнивание происходит по правому краю. Для выравнивания по левому краю перед числом ставится знак минус.

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



Целые числа

В языке C существует несколько типов целых чисел. Они различаются между собой объемом памяти, отводимым под переменную, а также возможностью присваивания положительных и отрицательных чисел. От объема памяти, т.е. от количества выделяемых байтов под переменную, зависит, каким может быть максимально возможное число, записанное в данную переменную. Так, если под переменную выделяется 2 байта и ей можно присваивать только положительные числа, то эти числа будут в диапазоне от 0 до 65535. (Если вы не знаете, почему это так, то спросите.)

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

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

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

Задание
Обычно под переменную типа int отводится 4 байта. Определите (узнайте, вспомните) максимально и минимально возможные значения для переменных такого типа. Объявите в программе переменную max типа int и присвойте ей значение на единицу больше максимально допустимого. Запрограммируйте вывод значения переменной на экран. Скомпилируйте программу и запустите. Чему равна переменная? Почему?

Что будет, если переменной присвоить значение на единицу меньше минимально допустимого ее типом?

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

  • short — отводится меньше байтов, чем на int;
  • long — отводится больше байтов, чем на int (не всегда, зависит от системы);
  • unsigned — столько же байт как у int, но без отрицательных чисел; в результате чего знаковый разряд освобождается, и количество положительных значений увеличивается;
  • unsigned short;
  • 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 <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);
}

Вещественные числа

В языке 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.

Задание
Напишите программу, в которой должны быть две переменные любых вещественных типов. Одной переменной присвойте достаточно маленькое, а другой — большое значение. Выведите на экран значения этих переменных с использованием различных форматов. При использовании форматов %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];
 
  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));

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

Если у вас на компьютере есть вторая операционная система, то скомпилируйте программу и там; сравните полученные результаты. Вот что получилось у меня в результате компиляции с помощью GCC в Xubuntu и Fedora:

Результат выполнения программы на C в Ubuntu и Fedora

В некоторых местах допущена

В некоторых местах допущена ошибка: "shot" вместо "short". А в остальном хочу поблагодарить за такой хороший курс.

Примеры местами не

Примеры местами не компилируются в ТС3.0, но объяснения понятны.
СПАСИБО!