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

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

Базовые типы

В языке Си используются всего два базовых типа: целые и вещественные числа. Кроме того, имеется фиктивный тип void («пустота»), который применяется либо для функции, не возвращающей никакого значения, либо для описания указателя общего типа (когда неизвестна информация о типе объекта, на который ссылается указатель).

В C++ добавлен логический тип.

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

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

Язык Си для начинающих / #2 — Переменные и типы данных

Тип int

Самый естественный целочисленный тип — это тип int , от слова integer — целое число. Тип int всегда соответствует размеру машинного слова или адреса. Все действия с элементами типа int производятся максимально быстро. Всегда следует выбирать именно тип int , если использование других целочисленных типов не диктуется явно спецификой решаемой задачи. Параметры большинства стандартных функций, работающих с целыми числами или символами, имеют тип int . Целочисленные типы были подробно рассмотрены в «лекции 2» . Подчеркнем еще раз, что целочисленные переменные хранят на самом деле не целые числа, а элементы кольца вычетов по модулю m , где m — степень двойки.

В современных архитектурах элемент типа int занимает 4 байта, т.е. m = 2 32 . Элементы типа int трактуются в Си как числа со знаком. Минимальное отрицательное число равно -2 31 = -2147483648 , максимальное положительное равно 2 31 -1 = 2147483647 .

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

int x; int y, z, t;

При описании переменных можно присваивать им начальные значения:

int maxind = 1000; int a = 5, b = 7;

Кроме типа int , существуют еще три целочисленных типа: char , short и long .

Тип char

Тип char представляет целые числа в диапазоне от -128 до 127 . Элементы типа char занимают один байт памяти. Слово » char » является сокращением от character , что в переводе означает «символ». Действительно, традиционно символы представляются их целочисленными кодами, а код символа занимает один байт (см. лекцию 3). Тем не менее, подчеркнем, что элементы типа char — это именно целые числа, с ними можно выполнять все арифметические операции. С математической точки зрения, элементы типа char — это элементы кольца вычетов m = Z256 . Стандарт Си не устанавливает, трактуются ли элементы типа char как знаковые или беззнаковые числа, но большинство Си-компиляторов считают char знаковым типом. Примеры описаний переменных типа char :

char c; char eof = (-1); char letterA = ‘A’;

В последнем случае значение переменной » letterA » инициализируется кодом латинской буквы ‘A’ , т.е. целым числом 65 . В Си символьные константы записываются в одинарных апострофах и означают коды соответствующих символов в кодировке ASCII. Рассмотрим следующий пример:

char c = 0; char d = ‘0’;

Здесь переменная c инициализируется нулевым значением, а переменная d — значением 48 , поскольку символ ‘0’ имеет код 48 .

Типы short и long

Слова short и long означают в Си короткое и длинное целое число со знаком. Стандарт Си не устанавливает конкретных размеров для типов short и long . В самой распространенной в настоящее время 32-разрядной архитектуре переменная типа short занимает 2 байта (диапазон значений — от -32768 до 32767 ), а тип long совпадает с типом int , размер его равен четырем байтам. Примеры описаний:

short s = 30000; long x = 100000; int y = 100000;

В 32-разрядной архитектуре переменные x и y имеют один и тот же тип.

Модификатор unsigned

Типы int , short и long представляют целые числа со знаком. Для типа char стандарт Си не устанавливает явно наличие знака, однако большинство компиляторов трактуют элементы типа char как целые числа со знаком в диапазоне от -128 до 127 . Если необходимо трактовать целые числа как неотрицательные, или беззнаковые, следует добавить модификатор unsigned при описании переменных. Примеры:

unsigned char c = 255; unsigned short s = 65535; unsigned int i = 1000000000; unsigned j = 1;

При описании типа » unsigned int » слово » int » можно опускать, что и сделано в последнем примере.

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

Имеется также модификатор signed (знаковый). Его имеет смысл использовать на тех платформах, в которых тип char является беззнаковым. Пример описания:

signed char d = (-1);

Вещественные типы

Вещественных типов два: длинное вещественное число double (переводится как «двойная точность») и короткое вещественное число float (переводится как «плавающее»). Вещественные типы были подробно рассмотрены в разделе 1.4.2. Вещественное число типа double занимает 8 байтов, типа float — 4 байта.

Тип double является основным для компьютера. Тип float — это, скорее, атавизм, оставшийся от ранних версий языка Си. Компьютер умеет производить арифметические действия только с элементами типа double , элементы типа float приходится сначала преобразовывать к double . Точность, которую обеспечивает тип float , низка и не достаточна для большинства практических задач. Все стандартные функции математической библиотеки работают только с типом double . Рекомендуем вам никогда не использовать тип float !

Примеры описаний вещественных переменных:

double x, y, z; double a = 1.5, b = 1e+6, c = 1.5e-3;

В последних двух случаях использовалось задание вещественных констант в экспоненциальной форме (см. раздел 1.4.2).

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

В языке Си специального логического типа нет, вместо него используются переменные целого типа. Значению «истина» соответствует любое ненулевое целое число, значению «ложь» — ноль. Например, в Си допустим такой фрагмент программы:

int b; double s; . . . if (b)

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

Здесь целочисленная переменная b используется в качестве условного выражения в операторе if («если»). Если значение b отлично от нуля, то выполняется тело оператора if , т.е. переменной s присваивается значение 1.0 ; если значение b равно нулю, то тело оператора if не выполняется.

На самом деле, приведенный пример представляет собой дурной стиль программирования. Гораздо яснее выглядит следующий фрагмент, эквивалентный приведенному выше:

if (b != 0)

В более строгом языке Java второй фрагмент корректен, а первый нет.

Язык C++ вводит логический тип bool в явном виде (отметим, что этот тип появился в C++ далеко не сразу!). Переменные типа bool принимают два значения: false и true (ложь и истина). Слова false и true являются ключевыми словами языка C++.

Примеры описания логических переменных в C++:

bool a, b; bool c = false, d = true;

Оператор sizeof

Переменная одного и того же типа на разных платформах может занимать различное число байтов памяти. Язык Си предоставляет программисту возможность получить размер элемента данного типа или размер переменной в байтах, для этого служит оператор sizeof . Аргумент sizeof указывается в круглых скобках, он может быть типом или переменной. Рассмотрим несколько примеров. Пусть определены следующие переменные:

int i; char c; short s; long l; double d; float f; bool b;

Тогда приведенные ниже выражения в 32-разрядной архитектуре имеют следующие значения:

размер переменной размер типа значение
sizeof(i) sizeof(int) 4
sizeof(c) sizeof(char) 1
sizeof(s) sizeof(short) 2
sizeof(l) sizeof(long) 4
sizeof(d) sizeof(double) 8
sizeof(f) sizeof(float) 4
sizeof(b) sizeof(bool) 1
Тип void

Слово void означает «пустота». Тип void в Си обозначает отсутствие чего-либо там, где обычно предполагается описание типа. Например, функция, не возвращающая никакого значения, в Си описывается как возвращающая значение типа void :

void f(int x);

Другое применение ключевого слова void состоит в описании указателя общего типа, когда заранее не известен тип объекта, на который он будет ссылаться.

Источник: intuit.ru

Ruby on Rails c нуля!

gnu-c

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

Переменные

Переменные — это именованные, понятные человеку ссылки на данные. Переменные в языке Си являются статическим и строготипизированными. На практике это проявляется в следующем:

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

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

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

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

Типы данных Си

Знакомство с типами данных традиционно принято начинать с типа char. Не будем изменять традициям и начнем с char.

CHAR

char — это тип данных, которые требуют для хранения 1 байт памяти. Этого количества памяти хватает для хранения символа ASCII, или чисел от -128 до +127, или от 0 до +255. Тип char применяется для хранения ASCII последовательностей, но может интерпретироваться и как число.

#include int main(void) < char a = ‘a’; printf(«%c ->%dn», a, a); printf(«%d — 5 = %dn», a, a — 5); return 0; >

В результате выполнения программы будет напечатано следующее:

a -> 97
97 — 5 = 92

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

Тип int используется для хранения целых чисел и занимает не менее 4 байтов памяти. Тип int является, так сказать, семейством типов. int типов существует несколько: short int, long int и long long int (C99). Признаться честно, все типы являются платформа-зависимыми, то есть, говоря, что int занимает 4 байта, а не подразумеваю, что 4 байта и только так.

На некоторых платформах int может занимать, например 8 байт памяти, а на других 2. Насколько мне известно, стандарт Си все же регламентирует минимальное значение основных типов и потому, наверное, можно быть уверенным в том, что int зарезервирует минимум 4 байта. Лично на моей машине int вмещает число 2147483647, long int занимает столько же места, как и int. Тип short int занимает минимум 2 байта.

Помимо int существуют short int и long int. Первый занимает минимум 1 байт, а второй обязан быть не менее int, но чаще всего занимает 4 байта.

#include int main(void)

Программа напечатает следующую строку:

2147483647, 32767, 2147483647

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

Для хранения чисел с плавающей точкой, используются специальные типы данных: float, double и long double. Каждый из них занимает 4, 8 и 12 байт соответственно.

Чтобы узнать достоверно, какой размер памяти занимает каждый тип необходимо воспользоваться функцией sizeof():

#include int main(void)

Эта программа напечатает следующий результат:

—— Integer numbers —— type | size char | 1 short int | 2 int | 4 long int | 4 long long int | 8 —— Floating point numbers —— float | 4 double | 8 long double | 12

Signed и Unsigned типы

Численные типы данных могут быть signed и unsigned. Signed типы означают, что переменная такого типа может хранить число со знаком, а unsigned, наоборот, что переменная хранит число без знака. Когда я писал выше, что char может хранить числа в диапазоне от -128 до +127, или от 0 до +255, то в первом случае подразумевался тип signed char, а во втором unsigned.

Читайте также:
Программа для эвм как объект интеллектуальной собственности

Если переменная не должна хранить отрицательное число, то ей необходимо прописать unsigned-тип, так вы более явно укажете, что число может быть только положительным и увеличите диапазон положительных значений в 2 раза (с 127 до 255, например). Вам не обязательно писать signed, если переменная может иметь в качестве значения отрицательное число. Если signed или unsigned не указаны, то переменная по умолчанию объявляется с signed типом.

Строки и массивы

Хочу вас обрадовать. В Си нет строк. Нет строк таких как в Ruby, JavaScript или даже богомерзком PHP. Строки в Си представляют собой массив символов. Единственное чем строки отличаются от массива — это возможность использовать более краткий и лаконичный синтаксис их объявления, а еще строка должна завершаться символом окончания строки — « «. Ниже приведен пример специфичного для строк синтаксиса их объявления, а еще «классический» синтаксис создания массива.

#include int main(void) < char a[] = «string»; char b[] = < ‘s’, ‘t’, ‘r’, ‘i’, ‘n’, ‘g’, ‘’>; printf(«%s == %sn», a, b); return 0; >

Данная программа напечатает следующее: string == string

Как видите, чтобы объявить массив необходимо также указывать тип его элементов и ставить [] после имени переменной. Да, да, массивы в Си могут хранить коллекцию элементов только одного типа. Ниже приведены некоторые примеры массивов.

int a[100] — массив целых чисел (тип int), размер которого — 100 элементов.
char b[5] — массив символов (или целых чисел, тип char), размер которого — 5 элементов.
float c[] = < 4.5, 6.7, 12.345 >— массив чисел с плавающей точкой (тип float) состоящий из 3 элементов.

Доступ к элементам массива очень прост и должно быть вы не раз сталкивались с подобным синтаксисом:

#include int main(void) < float c[] = < 4.5, 6.7, 12.345 >; printf(«%fn», c[0]); printf(«%fn», c[1]); printf(«%fn», c[2]); return 0; >

4.500000
6.700000
12.345000

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

Эта арифметика заключается например в том, что 1 + 1 = 4, именно на 4 байта должен переместиться указатель, чтобы получить доступ к следующему элементу типа float. Если быть совсем точным, то перемещается не указатель (есть такой элемент языка Си), а сама программа, которая хочет получить доступ к данным. Указатель остается на месте, а вот программа отсчитывает от него 4 байта (точнее столько, сколько резервирует для себе определенный тип данных) или 1 элемент того же типа. Подробнее об указателях мы поговорим в отдельной главе ибо это достаточно важная, большая и сложная тема.

Несмотря на всю аскетичность Си, массивы в Си могут быть многоуровневыми. Ниже приведен пример создания такого массива:

#include int main(void) < int a[3][3] = < < 1, 2, 3 >, < 4, 5, 6 >, >; printf(«%dn», a[0][0]); printf(«%dn», a[0][1]); printf(«%dn», a[1][0]); printf(«%dn», a[2][0]); return 0; >

Данная программа напечатает следующий текст:

В программировании на Си, а особенно в работе с массивами имеется один неприятный момент — вы можете легко залезть не туда, куда хотели. Например вы можете повредить данные другого запущенного приложения. Сделать это достаточно просто:

#include int main(void) < int a[] = < 1, 2, 3, 4 >; float c[] = < 4.5, 6.7, 12.345 >; printf(«%fn», c[0]); printf(«%fn», c[1]); printf(«%fn», c[2]); printf(«%dn», a[5]); return 0; >

4.500000
6.700000
12.345000
1087792742

Откуда у a взялся 6й элемент? Разумеется его нет и быть не может. Поскольку данные типа int занимают ячейку в 4 байта, то программа просто отсчитала 5 ячеек по 4 байта и выбрала шестую ячейку размером 4 байта. Разумеется, никакой 6й ячейки в действительно нет, а полученное число 1087792742 может быть просто мусором или данным из какой-нибудь другой программы.

Обычно операционная система беспокоится о том, чтобы каждой программе был выделен какой-то объем памяти и чтобы другая программа не могла получить к нему доступа. Если другая программа пытается получить доступ к чужим данным, то возникает ошибка Segmentation fault и программа завершает свою работу.

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

Свойства переменных

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

Область видимости переменной может быть следующей: блок кода (и вложенные в него блоки кода), функция, файл и программа в целом.

Пример переменной с глобальной областью видимости (по всему файлу):

#include void print_file_var(void); char file_var[] = «file scope»; int main(void) < printf(«%sn», file_var); print_file_var(); return 0; >void print_file_var()

Данная программа напечатает:

file scope
file scope

Пример переменной с областью видимости — функцией:

#include void print_function_var(void); int main(void) < char function_var[] = «function scope»; printf(«%sn», function_var); print_function_var(); return 0; >void print_function_var()

При компиляции программы возникает ошибка:

$ cc program.c
program.c: In function ‘print_function_var’:
program.c:14:20: error: ‘function_var’ undeclared (first use in this function)
program.c:14:20: note: each undeclared identifier is reported only once for each function it appears in

Она возникает потому, что переменной function_var не видно внутри функции print_var() . Внутри main() переменная function_var видима и может успешно использоваться.

Пример переменной с областью видимости — блоком кода:

#include int main(void) < char function_var[] = «function scope»; < char function_var[] = «block variable»; printf(«%sn», function_var); >printf(«%sn», function_var); return 0; >

Данная программа напечатает:

block variable
function scope

Спецификаторы времени хранения

Спецификаторы времени хранения еще называют спецификаторами типа. Таких спецификаторов всего четыре: static, register, extern и auto.

Читайте также:
Программа проверяет является ли введенное с клавиатуры число целым числом

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

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

register пытается поместить переменную в регистр, доступ к которому значительно быстрее, чем к оперативной памяти. В силу того, что регистр располагает малым объемом памяти, спецификатор register не гарантирует того, что переменная будет помещена в регистр. В регистр следует помещать только такие данные, доступ к которым происходит многократно. Поскольку переменная со спецификатором register ссылается не на оперативную память, но на регист CPU, то получить адрес переменной нельзя, а значит нельзя и создать соответствующий указатель.

extern позволяет «наследовать» переменную, то есть сделать ее во истину глобальной. Вам достаточно объявить глобальную (видимую в одном файле) переменную в одном файле исходников вашей программы, а в другом вам достаточно написать:

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

Ниже приведен пример использования спецификаторов времени хранения:

/* auto, register, static, extend */ /* programm.c */ #include char var[] = «ololo» int main(void) < auto char function_var[] = «function scope»; register int some_var = 100500; for (int i = 1; i return 0; > /* programm_1.c */ #include int main(void)

Данная программа напечатает следующее:

Благодаря тому, что переменная counter сохраняет свое значение между вызовами блока кода в цикле for.

Модификаторы класса хранилища

Модификаторы класса хранилища еще называют квалификаторами типа. Таких модификаторов существует целых два: const и volatile.

Модификатор const позволяет объявить переменную, значение которой нельзя изменить. Пример:

#include int main(void)

При попытке скомпилировать получаем ошибку:

$ cc program.c -std=c99
program.c: In function ‘main’:
program.c:5:5: error: assignment of read-only location ‘function_var[3]’

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

На этом мы заканчиваем наше знакомство с типами данных и переменных!

Источник: rubydev.ru

#2 — Переменные и типы данных в Си

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

Видеоурок

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

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

В ходе программы мы можем записывать новые значения в переменную, но тип данных должен оставаться неизменным:

float some_value = 2.95; some_value = 6.9; // Записали новое значение
Рассмотрим все типы данных для создания переменных.

Целые числа

  • short — предназначен для хранения целых чисел. Диапазон чисел от -32 768 до 32 767;
  • unsigned short — предназначен для хранения целых положительных чисел. Диапазон чисел от 0 до 65 535;
  • int — предназначен для хранения целых чисел. Диапазон чисел от -2 147 483 648 до 2 147 483 647;
  • unsigned int — предназначен для хранения целых положительных чисел. Диапазон чисел от 0 до 4 294 967 295;
  • long — предназначен для хранения целых чисел. Диапазон чисел от –9 223 372 036 854 775 808 до 9 223 372 036 854 775 807;
  • unsigned long — предназначен для хранения целых положительных чисел. Диапазон чисел от 0 до 18 446 744 073 709 551 615.

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

Числа с точкой

  • float — для создания чисел с плавающей точкой. Диапазон чисел от от -3.4*10 38 до 3.4*10 38 ;
  • double — для создания чисел с плавающей точкой. Диапазон чисел от от ±4.9*10 -324 до ±1.8*10 308 .

Прочие типы данных

  • bool — логический тип данных. Предназначен для записи истинного (true) или ложного (false) значения;
  • char — тип данных для работы с символами. Позволяет поместить в одинарных кавычках какой-либо символ.

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

int a = 0; // Добавление значения сразу float c; // Создание переменной без значения short b, y = 342; // Создание нескольких переменных
Для вызова переменной вы можете обратиться к ней по имени.

Получение данных

Для получения данных от пользователя необходимо воспользоваться функцией scanf() :
scanf(«%d»,

Таким образом введенные пользователем данные будут помещены в переменную с названием «some_value».
Весь код будет доступен после подписки на проект!

Задание к уроку

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

Большое задание по курсу

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

Источник: itproger.com

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru