Light-electric.com

IT Журнал
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Программирование на си массивы

Одномерные массивы

Пожалуйста, приостановите работу AdBlock на этом сайте.

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

Рис.1 Переменные и массивы. Аналогия с коробками.

На картинке выше изображено три массива:

  • целочисленный массив из 8 элементов с именем arr_int
  • вещественный массив из 11 элементов с именем arr_float
  • символьный массив из 6 элементов с именем arr_char

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

Нумерация элементов массива начинается с нуля, а не с единицы.

Объявление и инициализация массива

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

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

Правило именования массивов

Имя массива – любая последовательность символов, цифр и знака нижнего подчеркивания «_», которая начинается с буквы. Регистр букв важен.

Вот ещё несколько примеров объявления массивов:

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

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

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

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

Давайте, например, выведем элементы массива из пяти элементов на экран.

Конечно, если массив будет очень большой, то выводить его поэлементно подобным образом то ещё удовольствие. Да и с маленькими массивами так никто не делает. Лучше и правильнее использовать циклы. Например:

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

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

Обратите внимание на приём, который используется в этой программе.
В нулевом элементе массива хранится количество выпадений числа 0 , в первом элементе – количество выпадений числа 1 , во втором элементе – числа 2 . То есть само сгенерированное число позволяет определить, к какому элементу массива необходимо добавить единичку. Поэтому необходимость в операторе выбора switch отпадает. Удобно, не так ли?

Практика

Решите предложенные задачи:

Для удобства работы сразу переходите в полноэкранный режим

Ruby on Rails c нуля!

Программирование на языке Си: Использование массивов данных в Си. Указатели.

октября 31, 2011 | Published in Си и C++ | 9 Comments

Объявление массива в Си
Массив (Array) относится к вторичным типам данных. Массив в Си представляет собой коллекция явно определенного размера элементов определенного типа. то есть в отличие от массивов в Ruby массивы в Си являются однотипными (хранят данные только одного типа) и имеют заранее определенную длину (размер).

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

В первом случае мы объявляем массив целых чисел (4 байта на число) размером в 100 элементов. Точнее мы резервируем память для хранения 100 элементов типа int.

Во втором случае мы определяем массив из 10 целочисленных элементов и сразу же присваиваем элементам массива значения.

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

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

Обращение к элементам массива в Си

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

Код printf(«%dn», a[1]); напечатает 2, а не 1 потому, что индексация массивов начинается с 0 и лишнее подтверждение тому строка printf(«%cn», ch[0]); , которая напечатает символ «R» — нулевой элемент массива ch.

В общем случае объявление массива имеет следующий синтаксис:

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

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

Указатели в Си
Типы данных необходимы для того, чтобы мочь выделить кусок памяти определенного размера для хранения данных и определения того, что это за данные ибо без явного определения непонятно является ли набор нулей и единиц числом, символом или чем-нибудь еще. В этом случае переменная является ссылкой на фрагмент памяти определенного размера и типа, например, int переменная ссылается на определенную область памяти объемом 4 байта, в которой хранится целое число, а char переменная ссылается на область памяти объемом 1 байт в которой хранится символ (код символа).

Чтобы получить адрес на который ссылается переменная мы используем специальный оператор & — оператор адреса (address operator), пример:

Строка printf(«%pn», &arr); напечатает 0xbfbbe068. 0xbfbbe068 — шестнадцатеричное представление адреса памяти где хранится число 100500.

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

$ ./program
A: 0xbfe32008
B: 0xbfe3200c

В примере выше мы присваиваем переменным a и b одинаковое значение — число 10, но переменные a и b ссылаются на две разные области памяти, то есть мы сохраняем в памяти число 10 два раза. Если мы изменим значение переменной b, то оно это не отразится на переменной a и наоборот. Это отличается от того, как мы работаем с переменными в Ruby, где переменные — это ссылки на объекты хранимые в памяти, и при присваивании в стиле a = b = 10 мы получаем один объект — число 10 и две ссылки на него.

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

$ ./program
A:
address: 0xbfed0fa8
value: 10
B:
address: 0xbfed0fa8
value: 10

Указатели и массивы

На самом деле в Си нет массивов в привычном для многих людей понимании. Любой массив в Си — это просто ссылка на нулевой элемент массива. Пример:

$ ./program
a-Address:0xbfc029b4
a[0]-Address:0xbfc029b4
a[0]-Value:10
a-Size:12

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

Читать еще:  Что такое параллельное программирование

Когда мы запускаем программу, то операционная система предоставляет программе два особых объема памяти — стек (stack) и кучу (heap). В нашей программе используется только стек. Стек хранит значения упорядочено. Когда мы создаем массив, мы на самом деле создаем указатель ну нулевой элемент коллекции элементов и резервируем память для N-количества элементов. В примере выше мы создали коллекцию из 3 элементов типа int, т.е. каждый элемент занимает 4 байта памяти. Когда мы воспользовались функцией sizeof(), которая возвращает размер в байтах переданного ей аргумента, то получили значение 12 т.е. массив занимает 12 байт памяти: 3элемента * 4 байта. Поскольку для хранения элементов коллекции используется стек — элементы сохраняются по порядку, то есть занимают соседние области стека, а это означает, что мы можем перемещаться по коллекции зная позицию элемента и размер коллекции. Пример:

$ ./program
a[0] has 10 in 0xbfbeda88
a[1] has 20 in 0xbfbeda8c
a[2] has 30 in 0xbfbeda90
a[3] has 40 in 0xbfbeda94
a[4] has 10 in 0xbfbeda98
a[5] has 5 in 0xbfbeda9c

Программа напечатала нам информацию о массиве из 5 элементов: номер элемента, значение и адрес в памяти. Обратите внимание на адреса элементов — это то, о чем я вам говорил. Адреса идут подряд и каждый следующий больше предыдущего на 4. В 5 элементе коллекции, которого мы на самом деле не объявляли хранится общее количество элементов коллекции. Самое интересное — это то, что мы можем аналогичным образом использовать и указатели для прохода по массиву. Пример:

Примечания

1. Обратите внимание на то, что указателю b мы присваиваем не адрес массива a, а само значение переменной a, ведь a это, по сути и есть указатель.

2. Использование квадратных скобой с указанием индексов элементов массива — это такой синтаксический сахар в Си для более удобного и понятного обращения к элементам коллекции.

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

4. Адрес 1 элемента массива больше адреса 0 элемента массива на объем памяти выделяемой под хранение элемента данного типа. Мы работаем с элементами типа int, для хранения каждого из которых используется 4 байта. Адрес элемента массива в памяти и вообще любых данных — это адрес первого байта выделяемой под его хранение памяти.

5. Для упрощения понимания представьте, что память компьютера — это огромный кинотеатр, где места пронумерованы от 0 до, скачем 1_073_741_824. У данных типа char задница нормального размера и они помещаются в одном кресле (занимают один байт), а у толстых посетителей типа long double задницы огромные и каждый из них вмещается только на 10 сидениях. Когда у толстых посетителей кинотеатра спрашивают номер их места, они говорят только номер первого кресла, а количество и номера всех остальных кресел можно легко вычислить исходя из комплекции посетителя (типа данных). Массивы можно представить в виде групп однотипных посетителей кинотеатра, например группа худеньких балерин типа char из 10 человек займет 10 мест потому, что char вмещается в одном кресле, а группа любителей пива состоящая из 5 человек типа long int займет 40 байт.

6. У операторов & и * имеется несколько популярных названий, но вы можете называть их хоть Васей и Петей. Главное, что стоит запомнить — это:

& — показывает номер первого занятого посетителем кинотеатра сидения. То есть адрес первого занимаемого байта.

* — позволяет обратиться к посетителю сищящему на определенном месте. То есть позволяет получить значение, что хранится по определенному адресу в памяти.

На этом статья окончена, но не окончена тема массивов и указателей, а тем более изучения всего языка Си.

Лучшая благодарность автору — ваши комментарии!

Массивы в C++ — урок 5

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

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

Пример инициализации массива

Описание синтаксиса

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

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

Попробуем вывести наш массив на экран с помощью оператора cout .

Скомпилируйте этот код и посмотрите, на результат работы программы. Готово? А теперь запустите программу еще раз и сравните с предыдущим результатом. В моей операционной системе вывод был следующим:

  • Первый вывод: 0x7ffff8b85820
  • Второй вывод: 0x7fff7a335f90
  • Третий вывод: 0x7ffff847eb40

Мы видим, что выводится адрес этого массива в оперативной памяти, а никакие не «Иванов» и «Петров».

Дело в том, что при создании переменной, ей выделяется определенное место в памяти. Если мы объявляем переменную типа int , то на машинном уровне она описывается двумя параметрами — ее адресом и размером хранимых данных.

Массивы в памяти хранятся таким же образом. Массив типа int из 10 элементов описывается с помощью адреса его первого элемента и количества байт, которое может вместить этот массив. Если для хранения одного целого числа выделяется 4 байта, то для массива из десяти целых чисел будет выделено 40 байт.

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

Попробуем вывести первый элемент массива — фамилию студента Иванова.

Смотрим, компилируем, запускаем. Убедились, что вывелся именно «Иванов». Заметьте, что нумерация элементов массива в C++ начинается с нуля. Следовательно, фамилия первого студента находится в students[0] , а фамилия последнего — в students[9] .

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

Попробуем вывести список всех студентов. Но сначала подумаем, а что если бы вместо группы из десяти студентов, была бы кафедра их ста, факультет из тысячи, или даже весь университет? Ну не будем же мы писать десятки тысяч строк с cout ?

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

Вывод элементов массива через цикл

Если бы нам пришлось выводить массив из нескольких тысяч фамилий, то мы бы просто увеличили конечное значение счетчика цикла — строку for (. ; i заменили на for (. ; i .

Заметьте что счетчик нашего цикла начинается с нуля, а заканчивается девяткой. Если вместо оператора строгого неравенства — i использовать оператор «меньше, либо равно» — i , то на последней итерации программа обратится к несуществующему элементу массива — students[10] . Это может привести к ошибкам сегментации и аварийному завершению программы. Будьте внимательны — подобные ошибки бывает сложно отловить.

Массив, как и любую переменную можно не заполнять значениями при объявлении.

Объявление массива без инициализации

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

Читать еще:  Билд это в программировании

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

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

Заполним с клавиатуры пустой массив из 10 элементов.

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

Скомпилируем эту программу и проверим ее работу.

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

Массивы — очень важная вещь в программировании. Автор советует вам хорошо попрактиковаться в работе с ними.

C Урок 9. Массивы. Часть 2

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

А теперь давайте познакомимся с таким понятием, как многомерный массив.

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

Двумерный массив — это массив из нескольких одномерных массивов.

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

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

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

Так и у наших многомерных массивов существует несколько измерений, это своего рода матрицы.

Вот так вот выглядит объявление целочисленного двумерного массива

int a[ 4 ][ 3 ];

Мы объявили массив из 4 строк и 3 столбцов.

По сути мы получили 4 массива по 3 элемента.

Двумерный массив мы можем представить как матрицу из нескольких строк и нескольких столбцов

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

a[ 0 ][ 0 ] = 15 ; a[ 0 ][ 1 ] = 24 ; a[ 0 ][ 2 ] = -55 ;

a[ 1 ][ 0 ] = 33 ; a[ 1 ][ 1 ] = -4 ; a[ 1 ][ 2 ] = -5 ;

a[ 2 ][ 0 ] = 45 ; a[ 2 ][ 1 ] = -31 ; a[ 2 ][ 2 ] = 5 ;

a[ 3 ][ 0 ] = 81 ; a[ 3 ][ 1 ] = 46 ; a[ 3 ][ 2 ] = 0 ;

Получится вот так

На этапе объявления массива мы можем произвести инициализацию вот таким образом

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

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

Здесь даже лучше виден смысл многомерного массива, здесь очевидно, что это массив, состоящий из четырёх трёхэлементных массивов.

Давайте поиграем с такими массивами в нашем коде, с массивами из нескольких строк разберёмся несколько позднее.

Перейдём в main() и в самом начале тела данной функции добавим ещё одну переменную

unsigned char i, j;

Закомментируем предыдущий код и добавим вот такой, в котором мы объявим массив размерностью 4 на 3, затем проинициализируем его элементы и выведем их на экран в виде матрицы

Закомментируем наши счётчики, они нам больше пока не понадобятся

// unsigned char i, j;

Затем добавим следующий код

В данном коде мы объявили двумерный массив размерностью 3 на 30, состоящий из 3 символьных массивов по 30 элементов. Затем мы воспользовались функцией копирования строк strcpy, которая в копирует сроку, оканчивающуюся нулём, указатель на которую находится во втором параметре в определённое место памяти, на которое указывает первый параметр.

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

Соберём наш код и посмотрим, что у нас получилось

Все наши строки благополучно отобразились в консоли.

Теперь попробуем инициализацию наших строк на этапе объявления массива

Мы объявили массив размером 3 на 32, так будет удобнее для просмотра памяти.

Если мы посмотрим работу нашего кода, то мы получим тот же результат.

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

gdb myprog09

Далее, попав в отладчик установим точку останова на функцию main

Установим дизассемблирование в формат Intel

Запустим программу на выполнение, программа остановится на входе в main

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

Мы видим здесь дамп байтов по 8 байтов в каждой строке и видим, что наши строки расположились по адресам 0x404020, 0x404040 и 0x404060. То есть мы заняли блок памяти размером в 96 байт под наши три небольших строки. Это, конечно, очень расточительно, если мы не планируем писать в наши элементы массивов впоследствии в коде более длинные строки. Давайте теперь шагнём по программе с помощью вот такой вот простенькой команды

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

Перейдём ещё раз в окно дизассемблирования с помощью команды disas и посмотрим вот на этот код

Для тех, кто не знает, или не совсем хорошо знает ассемблер (вообще-то переходить к высокоуровневым языкам типа C нужно уже зная ассемблер), я постараюсь вкратце по-простому объяснить, что здесь происходит. Копируем мы участок памяти при помощи команды movs с префиксом rep, который заставляет повторять процесс копирования столько раз, сколько мы задали, занеся определённое число в регистр ecx. При каждом повторении копирования значение в этом регистре будет убавляться на 1, то есть декрементироваться. А в регистре у нас находится число 0x18. «А у нас ведь больше байтов!», — скажет кто-то. А дело в том, что нас ведь стоит DWORD PTR, которое говорит о том, что мы оперируем 4-байтными величинами, поэтому получится 0x18x4 = 0x60, что и составляет в десятичном выражении 96. Копирование происходит из участка памяти, адрес которого находится в регистре esi, то есть это и есть наш 0x404020, в участок памяти, на который показывает регистр edi, а это esp + 0x10. esp — это регистр, в котором находится адрес стека.

Посмотрим этот адрес, заодно посмотрим содержание всех регистров

Поэтому строки наши должны будут скопироваться в участок памяти по адресу 0x61feb0+0x10=0x61fec0.

Вот давайте их там и поищем

Там они и находятся.

Таким образом, мы видим, что мы уже заняли память вдвое больше.

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

Теперь выйдем из отладки

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

Читать еще:  Что такое метод в программировании

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

mas_b label byte

mas_w label word

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

Ссылка на основную публикацию
ВсеИнструменты
Adblock
detector
×
×