Что такое размерность массива

Дадим формальное определение:

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

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

· Как описать массивв программе?

· Как инициализировать массив, то есть как задать начальные значения его элементов?

· Как организовать доступк элементам массива?

· Как организовать массивыс размерностью более одной?

· Как организовать выполнениетиповых операций с массивами?

Описание и инициализация массива в программе

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

1. Перечислением элементов массива в поле операндов одной из директив описания данных. При перечислении элементы разделяются запятыми. К примеру:

;массив из 5 элементов.Размер каждого элемента 4 байта:

2. Используя оператор повторения dup. К примеру:

;массив из 5 нулевых элементов.

;Размер каждого элемента 2 байта:

Такой способ определения используется для резервирования памяти с целью размещения и инициализации элементов массива.

3. Используя директивы labelиrept. Пара этих директив может облегчить описание больших массивов в памяти и повысить наглядность такого описания. Директиваreptотносится к макросредствам языка ассемблера и вызывает повторение указанное число раз строк, заключенных между директивой и строкой endm. К примеру, определим массив байт в области памяти, обозначенной идентификаторомmas_b. В данном случае директиваlabelопределяет символическое имяmas_b, аналогично тому, как это делают директивы резервирования и инициализации памяти. Достоинство директивыlabelв том, что она не резервирует память, а лишь определяет характеристики объекта. В данном случае объект — это ячейка памяти. Используя несколько директивlabel, записанных одна за другой, можно присвоить одной и той же области памяти разные имена и разный тип, что и сделано в следующем фрагменте:

В результате в памяти будет создана последовательность из четырех слов f1f0. Эту последовательность можно трактовать как массив байт или слов в зависимости от того, какое имя области мы будем использовать в программе —mas_bилиmas_w.

4. Использование цикла для инициализации значениями области памяти, которую можно будет впоследствии трактовать как массив.

5. Посмотрим на примере листинга 2, каким образом это делается.

Листинг 2 Инициализация массива в цикле

mes db 0ah,0dh,’Массив- ‘,’$’

mas db 10 dup (?) ;исходный массив

xor ax,ax ;обнуление ax

mov cx,10 ;значение счетчика цикла в cx

mov si,0 ;индекс начального элемента в cx

go: ;цикл инициализации

mov mas[si],bh ;запись в массив i

inc si ;продвижение к следующему элементу массива

loop go ;повторить цикл

;вывод на экран получившегося массива

mov ah,02h ;функция вывода значения из al на экран

add dl,30h ;преобразование числа в символ

mov ax,4c00h ;стандартный выход

end main ;конец программы

Доступ к элементам массива

При работе с массивами необходимо четко представлять себе, что все элементы массива располагаются в памяти компьютера последовательно.

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

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

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

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

Пусть эта последовательность чисел трактуется как одномерный массив. Размерность каждого элемента определяется директивой dw, то есть она равна2байта. Чтобы получить доступ к третьему элементу, нужно к адресу массива прибавить6. Нумерация элементов массива в ассемблере начинается с нуля.

То есть в нашем случае речь, фактически, идет о 4-м элементе массива — 3, но об этом знает только программист; микропроцессору в данном случае все равно — ему нужен только адрес.

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

база + (индекс*размер элемента)

Архитектура микропроцессора предоставляет достаточно удобные программно-аппаратные средства для работы с массивами. К ним относятся базовые и индексные регистры, позволяющие реализовать несколько режимов адресации данных. Используя данные режимы адресации, можно организовать эффективную работу с массивами в памяти. Вспомним эти режимы:

· индексная адресация со смещением — режим адресации, при котором эффективный адрес формируется из двух компонентов:

o постоянного (базового)— указанием прямого адреса массива в виде имени идентификатора, обозначающего начало массива;

o переменного (индексного)— указанием имени индексного регистра.

;поместить 3-й элемент массива mas в регистр ax:

· базовая индексная адресация со смещением — режим адресации, при котором эффективный адрес формируется максимум из трех компонентов:

o постоянного(необязательный компонент), в качестве которой может выступать прямой адрес массива в виде имени идентификатора, обозначающего начало массива, или непосредственное значение;

o переменного (базового)— указанием имени базового регистра;

o переменного (индексного)— указанием имени индексного регистра.

Этот вид адресации удобно использовать при обработке двухмерных массивов. Пример использования этой адресации мы рассмотрим далее при изучении особенностей работы с двухмерными массивами.

Напомним, что в качестве базового регистра может использоваться любой из восьми регистров общего назначения. В качестве индексного регистра также можно использовать любой регистр общего назначения, за исключением esp/sp.

Микропроцессор позволяет масштабировать индекс. Это означает, что если указать после имени индексного регистра знак умножения “*” с последующей цифрой 2, 4 или 8, то содержимое индексного регистра будет умножаться на 2, 4 или 8, то есть масштабироваться.

Применение масштабирования облегчает работу с массивами, которые имеют размер элементов, равный 2, 4 или 8 байт, так как микропроцессор сам производит коррекцию индекса для получения адреса очередного элемента массива. Нам нужно лишь загрузить в индексный регистр значение требуемого индекса (считая от 0). Кстати сказать, возможность масштабирования появилась в микропроцессорах Intel, начиная с модели i486. По этой причине в рассматриваемом здесь примере программы стоит директива .486. Ее назначение, как и ранее использовавшейся директивы.386, в том, чтобы указать ассемблеру при формировании машинных команд на необходимость учета и использования дополнительных возможностей системы команд новых моделей микропроцессоров.

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

Листинг 3. Просмотр массива слов с использованием

.data ;начало сегмента данных

mes1 db ‘не равен 0!$’,0ah,0dh

mes2 db ‘равен 0!$’,0ah,0dh

mas dw 2,7,0,0,1,9,3,6,0,8 ;исходный массив

.486 ;это обязательно

mov ds,ax ;связка ds с сегментом данных

xor ax,ax ;обнуление ax

mov cx,10 ;значение счетчика цикла в cx

mov esi,0 ;индекс в esi

mov dx,mas[esi*2] ;первый элемент массива в dx

cmp dx,0 ;сравнение dx c 0

je equal ;переход, если равно

not_equal: ;не равно

mov ah,09h ;вывод сообщения на экран

mov ah,02h ;вывод номера элемента массива на экран

inc esi ;на следующий элемент

dec cx ;условие для выхода из цикла

jcxz exit ;cx=0? Если да — на выход

jmp compare ;нет — повторить цикл

mov ah,09h ;вывод сообщения mes3 на экран

mov ah,09h ;вывод сообщения mes2 на экран

inc esi ;на следующий элемент

dec cx ;все элементы обработаны?

mov ax,4c00h ;стандартный выход

end main ;конец программы

Еще несколько слов о соглашениях:

· Если для описания адреса используется только один регистр, то речь идет о базовой адресациии этот регистр рассматривается какбазовый:

;переслать байт из области данных, адрес

которой находится в регистре ebx:

· Если для задания адреса в команде используется прямая адресация(в виде идентификатора) в сочетании с одним регистром, то речь идет обиндексной адресации. Регистр считаетсяиндексным, и поэтому можно использовать масштабирование для получения адреса нужного элемента массива:

;сложить содержимое eax с двойным словом в памяти

;по адресу mas + (ebx)*4

· Если для описания адреса используются два регистра, то речь идет о базово-индексной адресации. Левый регистр рассматривается как базовый, а правый — как индексный. В общем случае это не принципиально, но если мы используем масштабирование с одним из регистров, то он всегда являетсяиндексным. Но лучше придерживаться определенных соглашений.

· Помните, что применение регистров ebp/bpиesp/spпо умолчанию подразумевает, что сегментная составляющая адреса находится в регистреss.

Заметим, что базово-индексную адресацию не возбраняется сочетать с прямой адресацией или указанием непосредственного значения. Адрес тогда будет формироваться как сумма всех компонентов.

;адрес операнда равен [mas+(ebx)+(ecx)*2]

;адрес операнда равен [(ebx)+8+(ecx)*4]

Но имейте в виду, что масштабирование эффективно лишь тогда, когда размерность элементов массива равна 2, 4 или 8 байт. Если же размерность элементов другая, то организовывать обращение к элементам массива нужно обычным способом, как описано ранее.

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

Листинг 4. Обработка массива элементов с нечетной длиной

MODEL small ;модель памяти

STACK 256 ;размер стека

.data ;начало сегмента данных

N=5 ;количество элементов массива

mas db 5 dup (3 dup (0))

main: ;точка входа в программу

xor ax,ax ;обнуление ax

mov dl,mas[si] ;первый байт поля в dl

inc dl ;увеличение dl на 1 (по условию)

mov mas[si],dl ;заслать обратно в массив

add si,3 ;сдвиг на следующий элемент массива

Источник

Массивы

Многие сегодня хотят стать программистами. Хотят. Но ничего не делают для этого. Не делают даже простых вещей. Не хотят даже прочитать книжку из 10 страниц. В итоге так и остаются никем. Потому что мечты не сбываются никогда. Сбываются только планы… Подробнее.

Элементы массива в памяти компьютера расположены друг за другом. Получить доступ к отдельному элементу массива можно по индексу этого элемента.

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

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

Синтаксис массива в Паскале:

var ИмяМассива : array[0..15] of ТипДанных;

var M1 : array[0..15] of byte;

Работать с отдельным элементом массива можно так:

var m : byte;
M1[0] := 100;
m := M1[0];

Здесь мы сначала в первый элемент массива записываем значение 100, а потом в переменную m записываем значение первого элемента массива. Догадайтесь, какое значение будет в переменной m после этого))).

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

for i := 0 to 15 do M1[i] := i;
for i := 0 to 15 do Write(M1[i], ‘ ‘);

Надеюсь, не надо объяснять, что делает этот код. А теперь представьте, сколько бы строк кода вам пришлось написать, если бы то же самое вы делали с помощью обычных переменных.

Двухмерный массив объявляется так:

M2 : array[1..4, 1..2] of byte;

Это будет матрица (или таблица) 4х2. То есть такой массив имеет некоторое количество строк (в нашем примере 4) и некоторое количество столбцов (в нашем примере 2). Того же результата можно достичь, если объявить массив массивов:

M2e : array[1..4] of array[1..2] of byte;

Строка 1, Столбец 1Строка 1, Столбец 2
Строка 2, Столбец 1Строка 2, Столбец 2
Строка 3, Столбец 1Строка 3, Столбец 2
Строка 4, Столбец 1Строка 4, Столбец 2

Если вы попробуете использовать, например, М2[1, 3], то компилятор выдаст предупреждение, так как столбца 3 в нашем массиве не существует. Однако будьте осторожны! В некоторых средствах разработки программа при этом будет создана (зависит от настроек среды)! И вы можете получить ошибку, которую в последствии будет трудно обнаружить.

А теперь пример использования нашего двухмерного массива:

Надеюсь, с этим кодом вы разобрались. Или хотя бы запустили его и посмотрели, что он делает. А он выводит двухмерный массив на экран. Но вывод выполняется в одну строку. И это не очень удобно для двухмерного массива. Ведь обычно в таких массивах представлены матрицы (таблицы). То есть удобнее воспринимать информацию, если она будет выводиться в виде таблицы. В нашем случае хотелось бы получить 4 строки и 2 столбца.

Попробуйте решить эту задачу самостоятельно. А если у вас не получится, то вот один из вариантов решения:

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

Изучите внимательно этот пример и найдите все участки кода, где используется константа k. Дальше, надеюсь, вы разберётесь с этим кодом самостоятельно.

Ну и напоследок добавлю, что для определения индексов массива можно использовать уже известные нам по первым урокам стандартные функции Low и High. Например, так:

WriteLn(‘Индекс первого элемента М1 : ‘, Low(M1));
WriteLn(‘Индекс последнего элемента М1 : ‘, High(M1));

Статья получилась больше, чем я ожидал. Но надеюсь, у вас хватило терпения дочитать её до конца.

Источник

Массивы в Visual Basic

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

Используя массив, можно ссылаться на эти связанные значения по одному и тому же имени и использовать число, которое называется индексом или подиндексом для обозначения отдельного элемента в зависимости от его позиции в массиве. Индексы в диапазоне от 0 до 1 меньше, чем общее число элементов в массиве. при использовании синтаксиса Visual Basic для определения размера массива указывается его самый высокий индекс, а не общее число элементов в массиве. Можно работать с массивом как с единицей, а возможность итерации элементов освобождает вас от необходимости знать, сколько элементов оно содержит во время разработки.

Несколько простых примеров перед подробным описанием:

Элементы массива в простом массиве

Давайте создадим массив с именем students для хранения числа учащихся в каждом классе в школе. Индексы элементов находятся в диапазоне от 0 до 6. Использование этого массива проще, чем объявление семи переменных.

На следующем рисунке показан students массив. Для каждого элемента массива:

индекс элемента представляет школьный класс (индекс 0 представляет детский сад);

значение, содержащееся в элементе, представляет число учеников в этом классе.

Что такое размерность массива. Смотреть фото Что такое размерность массива. Смотреть картинку Что такое размерность массива. Картинка про Что такое размерность массива. Фото Что такое размерность массива

в следующем примере содержится код Visual Basic, который создает и использует массив:

В этом примере выполняется три вещи:

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

Создание массива

Размер массива можно определить несколькими способами.

Размер можно указать при объявлении массива:

Можно использовать предложение, New чтобы указать размер массива при его создании:

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

Дополнительные сведения см. в описании оператора ReDim.

Сохранение значений в массиве

В следующем примере показаны некоторые инструкции, которые хранят и извлекают значения в массивах.

Заполнение массива литералами массива

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

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

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

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

Дополнительные примеры можно найти в статье How to: Initialize an Array Variable in Visual Basic (Практическое руководство. Инициализация переменной массива в Visual Basic).

Проход по массиву

При итерации по массиву вы обращаетесь к каждому элементу в массиве от самого низкого индекса к верхнему или от самого низкого. Как правило, используйте для. Next или For Each. Оператор Next для итерации элементов массива. Если вы не знакомы с верхними границами массива, можно вызвать Array.GetUpperBound метод, чтобы получить наибольшее значение индекса. Хотя наименьшее значение индекса почти всегда равно 0, можно вызвать Array.GetLowerBound метод, чтобы получить наименьшее значение индекса.

В следующем примере выполняется итерация по одномерным массиву с помощью For. Next инструкции.

В следующем примере выполняется перебор многомерного массива с помощью For. Next инструкции. Метод GetUpperBound имеет параметр, который определяет измерение. GetUpperBound(0) Возвращает самый верхний индекс первого измерения и GetUpperBound(1) возвращает наибольший индекс второго измерения.

В следующем примере используется объект For Each. Оператор Nextдля итерации одномерного массива и двумерного массива.

Размер массива

Размер массива является произведением длин всех его измерений. Он представляет собой общее число элементов, в данный момент содержащихся в массиве. Например, в следующем примере объявляется двухмерный массив с четырьмя элементами в каждом измерении. Как видно из выходных данных в примере, размер массива равен 16 (или (3 + 1) * (3 + 1).

Размер массива можно определить с помощью свойства Array.Length. Длину каждого измерения многомерного массива можно узнать с помощью Array.GetLength метода.

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

Тип массива

Каждый массив имеет тип данных, который отличается от типа данных его элементов. Не существует единого типа данных, подходящего для всех массивов. Вместо этого тип данных массива определяется числом измерений ( рангом) массива и типом данных его элементов. Две переменные массива имеют один и тот же тип данных, только если они имеют одинаковый ранг и их элементы имеют один и тот же тип данных. Длины измерений массива не влияют на тип данных массива.

Выяснить тип данных массива или его элементов можно несколькими способами.

Массивы как возвращаемые значения и параметры

Массивы массивов

Иногда структура данных в приложении является двухмерной, но не прямоугольной. Например, массив можно использовать для хранения данных о высокой температуре каждого дня месяца. Первое измерение массива представляет месяц, но второе измерение представляет количество дней, а число дней в месяце является неравномерным. Немассивный массив, который также называется массивом массивов, предназначен для таких сценариев. Немассивный массив — это массив, элементы которого также являются массивами. Массив массивов и каждый элемент в нем могут иметь одно или несколько измерений.

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

В предыдущем примере значения массива массивов назначаются для элемента в отдельности с помощью For. Next цикла. Можно также присваивать значения элементам массива массивов с помощью вложенных литералов массива. Однако попытка использовать вложенные литералы массива (например, Dim valuesjagged = <<1, 2>, <2, 3, 4>> ) приводит к возникновению ошибки компилятора BC30568. Чтобы исправить ошибку, заключите внутренние литералы массива в круглые скобки. Круглые скобки принудительно оценивают выражение литерала массива, а результирующие значения используются с литералом внешнего массива, как показано в следующем примере.

Массивы нулевой длины

Visual Basic отличает неинициализированный массив (массив, значение которого равно Nothing ) и массив нулевой длины или пустой массив (массив без элементов). Неинициализированный массив — это тот, который не был измерен или имел присвоенные ему значения. Вот несколько примеров.

Массив нулевой длины объявляется с измерением-1. Вот несколько примеров.

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

Вы хотите, чтобы ваш код был простым, не требуя проверки в Nothing качестве специального случая.

Код взаимодействует с интерфейсом API, который требует передачи массива нулевой длины в одну или несколько процедур или возвращает массив нулевой длины из одной или нескольких процедур.

Разделение массива

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

В этом разделе не рассматривается разделение одной строки на массив строк, основанный на каком-либо разделителе. Сведения о разбиении строки см. в описании String.Split метода.

Ниже приведены наиболее распространенные критерии разделения массива.

Количество элементов в массиве. Например, может потребоваться разделить массив больше, чем заданное число элементов, на несколько приблизительно равных частей. Для этой цели можно использовать значение, возвращаемое Array.Length Array.GetLength методом или.

Значение элемента, которое служит разделителем, указывающим место разделения массива. Можно выполнить поиск определенного значения, вызвав Array.FindIndex Array.FindLastIndex методы и.

После определения индекса или индексов, на которых массив должен быть разделен, можно создать отдельные массивы, вызвав Array.Copy метод.

В следующем примере массив разбивается на два массива приблизительно равного размера. (Если общее число элементов массива нечетное, первый массив содержит еще один элемент, чем второй.)

В следующем примере массив строк разбивается на два массива на основе наличия элемента, значение которого равно «zzz», которое служит разделителем массива. Новые массивы не включают элемент, содержащий разделитель.

Соединение массивов

Можно также объединить несколько массивов в один массив большего размера. Для этого также используется Array.Copy метод.

В этом разделе не обсуждается объединение массива строк в одну строку. Сведения о присоединении массива строк см. в описании String.Join метода.

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

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

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

Коллекции в качестве альтернативы массивам

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

при использовании ReDim для переизмерения массива Visual Basic создает новый массив и освобождает предыдущий. Это занимает время выполнения. Таким образом, если количество элементов, с которыми вы работаете, часто меняются, или вы не можете предсказать максимальное количество элементов, вы обычно получаете лучшую производительность, используя коллекцию.

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

Если коллекция содержит элементы только одного типа данных, можно использовать один из классов в пространстве имен System.Collections.Generic. Универсальная коллекция обеспечивает строгую типизацию, так что в нее нельзя добавить другие типы данных.

Более подробную информацию о коллекциях см. в статье Коллекции.

Источник

Добавить комментарий

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