Сложные типы данных в си

Базовые типы

Для указания простых типов указываются спецификаторы int, char, float или double. К переменным могут подставляться модификаторы unsigned (беззнаковый), signed (знаковый), short, long, long long.


По умолчанию все числа являются знаковыми, соответственно, могут находиться в диапазоне только положительных чисел. Чтобы определить переменную типа char как знаковую, пишется signed char. Long, long long и short указывают, как много места в памяти отводится для хранения. Наибольшее — long long, наименьшее — short.

Char — самый маленький тип данных в Си. Для хранения значений выделяется всего 1 байт памяти. Переменной типа character обычно присваиваются символы, реже — цифры. Символьные значения берутся в кавычки.

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

Явное преобразование беззнаковой переменной задается так:

Неявное выглядит так:

Float и double определяют числа с точкой. Числа float представляются в виде -2.3 или 3.34. Double используется для большей точности — после разделителя целой и дробной части указывается больше цифр. Этот тип занимает больше места в памяти, чем float.

Void имеет пустое значение. Он определяет функции, которые ничего не возвращают. С помощью этого спецификатора указывается пустое значение в аргументах методов. Указатели, которые могут принимать любой тип данных, также определяются как void.

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

Целочисленные типы данных отлично подходят для работы с целыми числами, но есть ведь ещё и дробные числа. И тут нам на помощь приходит тип данных с плавающей точкой (или «тип данных с плавающей запятой», от англ. «floating point»). Переменная такого типа может хранить любые действительные дробные значения, например: 4320.0, -3.33 или 0.01226. Почему точка «плавающая»? Дело в том, точка/запятая перемещается («плавает») между цифрами, разделяя целую и дробную части значения.

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

Категория Тип Минимальный размер Типичный размер
Тип данных с плавающей точкой float 4 байта 4 байта
double 8 байт 8 байт
long double 8 байт 8, 12 или 16 байт

Объявление переменных разных типов данных с плавающей точкой:

float fValue; double dValue; long double dValue2;

1 2 3

floatfValue;

doubledValue;

longdoubledValue2;

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

int n(5); // 5 — это целочисленный тип double d(5.0); // 5.0 — это тип данных с плавающей точкой (по умолчанию double) float f(5.0f); // 5.0 — это тип данных с плавающей точкой, «f» от «float»

1 2 3

intn(5);// 5 — это целочисленный тип

doubled(5.0);// 5.0 — это тип данных с плавающей точкой (по умолчанию double)

floatf(5.0f);// 5.0 — это тип данных с плавающей точкой, «f» от «float»

Обратите внимание, литералы типа с плавающей точкой по умолчанию относятся к типу double. в конце числа означает тип float

Инициализация полей структуры

Инициализация полей структуры может осуществляться двумя способами:

  • присвоение значений элементам структуры в процессе объявления переменной, относящейся к типу структуры;
  • присвоение начальных значений элементам структуры с использованием функций ввода-вывода (например, printf() и scanf()).

В первом способе инициализация осуществляется по следующей форме:

struct ИмяСтруктуры ИмяПеременной={ЗначениеЭлемента1, ЗначениеЭлемента_2, . . . , ЗначениеЭлементаn};

Пример

struct date bd={8,»июня», 1978};

  ИмяПеременной.ИмяЭлементаСтруктуры

  printf(«%d %s %d»,bd.day, bd.month, bd.year);

Пример

1234567891011121314151617181920212223242526272829303132

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <stdlib.h>struct date {  int day;  char month;  int year;};struct persone {  char firstname;  char lastname;  struct date bd;};int main() {  system(«chcp 1251»);  system(«cls»);  struct persone p;  printf(«Введите имя : «);  scanf(«%s», p.firstname);  printf(«Введите фамилию : «);  scanf(«%s», p.lastname);  printf(«Введите дату рождения\nЧисло: «);  scanf(«%d», &p.bd.day);  printf(«Месяц: «);  scanf(«%s», p.bd.month);  printf(«Год: «);  scanf(«%d», &p.bd.year);  printf(«\nВы ввели : %s %s, дата рождения %d %s %d года»,    p.firstname, p.lastname, p.bd.day, p.bd.month, p.bd.year);  getchar(); getchar();  return 0;}

Имя структурной переменной может быть указано при объявлении структуры. В этом случае оно размещается после закрывающей фигурной скобки }. Область видимости такой структурной переменной будет определяться местом описания структуры.

struct complex_type  // имя структуры{  double real;  double imag;} number;    // имя структурной переменной

Поля приведенной структурной переменной: number.real, number.imag . 

Манипуляторы потока

Функцию — манипулятор потока можно включать в операции помещения в поток и извлечения из потока (<<, >>). В С++ имеется ряд манипуляторов. Рассмотрим основные:

Манипулятор Описание
endl Помещение в выходной поток символа конца строки ‘\n’
dec Установка основания 10-ой системы счисления
oct Установка основания 8-ой системы счисления
hex Установка основания 16-ой системы счисления
setbase Вывод базовой системы счисления
width(ширина) Устанавливает ширину поля вывода
fill(‘символ’) Заполняет пустые знакоместа значением символа
precision(точность) Устанавливает количество значащих цифр в числе (или после запятой) в зависимости от использования fixed
fixed Показывает, что установленная точность относится к количеству знаков после запятой
showpos Показывает знак + для положительных чисел
scientific Выводит число в экспоненциальной форме
get() Ожидает ввода символа
getline(указатель, количество) Ожидает ввода строки символов. Максимальное количество символов ограничено полем количество

Пример Программа ввода-вывода значения переменной в C++

1234567891011

#include <iostream>using namespace std;int main(){  int n;  cout << «Введите n:»;  cin >> n;  cout << «Значение n равно: » << n << endl;  cin.get(); cin.get();  return 0;}

12345678910

#include <stdio.h>int main(){  int n;  printf(«Введите n:»);  scanf(«%d», &n);  printf(«Значение n равно: %d\n», n);  getchar(); getchar();  return 0;}

Пример

1234567891011121314151617181920212223242526

#include <iostream>using namespace std;int main(){  double a = -112.234;  double b = 4.3981;  int c = 18;  cout << endl << «double number:» << endl;  cout << «width(10)» << endl;  cout.width(10);  cout << a << endl << b << endl;  cout << «fill(‘0’)» << endl;  cout.fill(‘0’);  cout.width(10);  cout << a << endl << b << endl;  cout.precision(5);  cout << «precision(5)» << endl << a << endl << b << endl;  cout << «fixed» << endl << fixed << a << endl << b << endl;  cout << «showpos» << endl << showpos << a << endl << b << endl;  cout << «scientific» << endl << scientific << a << endl << b << endl;  cout << endl << «int number:» << endl;  cout << showbase << hex << c << » » << showbase << oct << c << » «;  cout << showbase << dec << c << endl;  cin.get();  return 0;}

12345678910111213141516

#include <iostream>using namespace std;int main(){  cout << fixed;  for (double t = 0; t <= 3; t += 0.5) {    cout.width(3);    cout.precision(1);    cout << t;    cout.width(8);    cout.precision(3);    cout << cos(t) << endl;  }  system(«pause»);  return 0;}

Символы

Под символьный тип данных отводится 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, однако ее значение было задано через символ, а не число.

Динамическое выделение памяти для структур

Динамически выделять память под массив структур необходимо в том случае, если заранее неизвестен размер массива. Для определения размера структуры в байтах используется операция sizeof(ИмяСтруктуры).Пример Библиотека из 3 книг

12345678910111213141516171819202122232425262728293031323334

#include <stdio.h>#include <stdlib.h>#include <malloc.h>struct book{  char title;  char author;  int value;};int main(){  struct book *lib;  int i;  system(«chcp 1251»);  system(«cls»);  lib = (struct book*)malloc(3 * sizeof(struct book));  for (i = 0; i<3; i++)  {    printf(«Введите название %d книги : «, i + 1);    gets_s((lib + i)->title);    printf(«Введите автора %d книги : «, i + 1);    gets_s((lib + i)->author);    printf(«Введите цену %d книги : «, i + 1);    scanf_s(«%d», &(lib + i)->value);    getchar();  }  for (i = 0; i<3; i++)  {    printf(«\n %d. %s «, i + 1, (lib + i)->author);    printf(«%s %d», (lib + i)->title, (lib + i)->value);  }  getchar();  return 0;}

Язык Си

Float ranges and precision

In order to find the value ranges of the floating-point number in your platform, you can use the header file. This header file defines macros such as  and that store the float value ranges and precision of the  type.

You can also find the corresponding macros for and with the prefixes  and

The following program illustrates the storage size and precision of floating-point numbers in your system.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

/* * File   : main.c * Author : zentut.com * Purpose: C float demo */   #include <stdio.h> #include <float.h>  

intmain()

{

printf(«Storage size: %d bytes\n»

«Minimum float value: %E\n»

«Maximum float value: %E\n»

«Precision: %d decimal digits\n»,

sizeof(float),

FLT_MIN,

FLT_MAX,

FLT_DIG);

puts(«\nExample of float precision:\n»);

doubled=12345.6;

floatf=(float)d;

printf(«The floating-point number d  «

«%18.10f\n»,d);

printf(«Stored in a variable f\n»

«of type float as the value   «

«%18.10f\n»,f);


return;

}

The output of the program in our system is as follows:

1 2 3 4 5 6 7 8 9 10

Storage size4bytes

Minimum floatvalue1.175494E-038

Maximum floatvalue3.402823E+038

Precision6decimal digits

Example of floatprecision

The floating-point numberd12345.6000000000

Stored inavariablef

of type floatasthe value12345.5996093750

In this tutorial, we have introduced you various C float types and explained what precision means to each type of float in C.

  • Was this tutorial helpful ?

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

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

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

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

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

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

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

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

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

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

-2147483648
-2147483647
-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 существуют другие (модифицированные) целочисленные типы:

  • short — отводится меньше байтов, чем на int;

  • long — отводится больше байтов, чем на int (не всегда, зависит от системы);

  • unsigned — столько же байт как у int, но без отрицательных чисел; в результате чего знаковый разряд освобождается, и количество положительных значений увеличивается;

  • unsigned short;

  • unsigned long.

При выводе длинных чисел следует дополнять спецификацию формата буквой l перед буквой формата. Например:

printf("%ld\n",i);
printf("%15ld\n",i);

Строковые константы

Строковая константа — это последовательность символов, заключенная в кавычки, например:

«Это строковая константа»

Кавычки не входят в строку, а лишь ограничивают её. Технически строковая константа представляет собой массив символов, и по этому признаку может быть отнесена к разряду сложных объектов языка Си. В конце каждой строковой константы компилятор помещает ‘\0’ (нуль-символ), чтобы программе было возможно определить конец строки. Такое представление означает, что размер строковой константы не ограничен каким-либо пределом, но для определения длины строковой константы её нужно полностью просмотреть. Поскольку строковая константа состоит из символов, то она имеет тип char. Количество ячеек памяти, необходимое для хранения строковой константы на 1 больше количества символов в ней (1 байт используется для хранения нуль-символа). Символьная константа ‘x’ и строка из одного символа «x» — не одно и то же. Символьная константа — это символ, используемый для числового представления буквы x, а строковая константа «x» содержит символ ‘x’ и нуль-символ ‘\0’ и занимает в памяти 2 байта. Если в программе строковые константы записаны одна за другой через разделители, то при выполнении программы они будут размещаться в последовательных ячейках памяти. 

setprecision() to Specify Decimal Points

We can specify the number of decimal points to print in by using the function.

This function is defined in the header file, which stands for input/output manipulation.

Example 2: Using setprecision() For Floating-Point Numbers

Output

Double Type Number  = 3.912348239293
Float Type Number      = 3.912348270416

As we can see from the example above, we have specified the precision up to 13 digits.

The floating-point value we have assigned to our variables also consists of 13 digits.

However, since has a precision of up to only 7 digits, it shows garbage values after its precision is exceeded.

Our variable shows the correct number because it has a precision of 15 digits, while the number itself consists of 13 digits.

As an alternative, we can specify different precisions for different variables while printing them.

Example 3: Different Precisions For Different Variables

Output

Double Type Number = 3.9123482393
Float Type Number    = 3.912348

From the program above, we can see that we have set two different precision values for and .

In both cases, the precision is smaller than the actual digits of the number. So the last digit is rounded off and the rest is truncated.

Note: If we specify the precision greater than the precision of the data type itself (7 for and 15 for ), then the compiler will give us garbage values after the precision limit has been exceeded, as can be seen with the output in example 2.

Функция sizeof()

Функция sizeof() языка C принимает в качестве аргумента константу, тип данных или переменную и возвращает количество байт, которые отведено под этот объект в памяти.

При выводе на экран значения, возвращаемого sizeof() используется формат %lu (длинное целое без знака). Примеры:

int a = 10;
 
int b100;
 
printf("Integer: %lu \n", sizeof(a));
 
printf("Float: %lu \n", sizeof(float));
 
printf("Array of 100 integers: %lu \n", sizeof(b));

Задание

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

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

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

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

  printf(«СтрокаФорматов», объект1, объект2, …, объектn);

СтрокаФорматов

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

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

  • ‘\n’ — перевод строки;
  • ‘\t’ — горизонтальная табуляция;
  • ‘\v’ — вертикальная табуляция;
  • ‘\b’ — возврат на символ;
  • ‘\r’ — возврат на начало строки;
  • ‘\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 — строковый формат.

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

12345678910

#include <stdio.h>int main(){  int a = 5;  float x = 2.78;  printf(«a=%d\n», a);  printf(«x=%f\n», x);  getchar();  return 0;}

123456789

#include <stdio.h>int main(){  int a = 5;  float x = 2.78;  printf(«a=%d\nx=%f\n», a, x);  getchar();  return 0;}

Функция 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. По умолчанию выравнивание происходит по правому краю. Для выравнивания по левому краю перед числом ставится знак минус.

Задание

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

Вывод типов

В си++ 2011 служебное слово auto используется для автоматического определения типа переменных. Часто тип переменной может быть определён, исходя из правой части инициализации. В том случае, когда компилятор может однозначно определить тип, его можно задавать с помощью служебного слова auto:

auto x = 3;
//эквивалентно int x = 3;
auto point = new Point;
//эквивалентно Point *point = new Point

Кроме этого, есть возможность задавать тип переменной по уже имеющемуся типу, с помощью служебного слова decltype

int intX = 42;
decltype(intX) intY = 33;
//эквивалентно int intY = 33;
auto pt1 = new Point;
decltype(pt1) p2 = new Point{2, 6};
//эквивалентно
//Point *pt1 = new Point;
//Point *pt2 = new Point{2, 6}

С этим читают