Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
PYaVU_otvyty.docx
Скачиваний:
2
Добавлен:
04.08.2019
Размер:
100.42 Кб
Скачать

Билет 34. Массивы. Определение и инициализация двумерных массивов

!!!Теория по массивам представлена в предыдущем вопросе(34). При ответе использовать её!

Двумерный массив - это одномерный массив, элементами которого являются одномерные массивы. Наглядно двумерный массив удобно представлять в виде таблицы, в которой n строк и m столбцов, а под ячейкой таблицы, стоящей в i-й строке и j-м столбце понимают некоторый элемент массива a[i][j].

Определение двумерного массива аналогично одномерному, отличия: 1 – две пары индексных скобок вместо одной: int mt1[MAXROW] [MAXCOL] (где MAXROW и MAXCOL определены до этой записи);, 2 – в первых скобках обязательно должно стоять число (это связано с тем, что С необходимо знать, сколько строк выделять в памяти, см. определение двумерного массива); чтобы не ставить этот размер, в С99 их заменяют на звездочку перед именем, т.е.: double *ars[];

Инициализация аналогична одномерным массивам, отличия в записи:

int mt1[2] [3]={{1,3,5},{2,4,6}};

mt2[r][c]=c;

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

Билет 35. Связь указателей и массивов

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

Элемент массива a[i] есть элемент массива, на который указывает значение a+i, т.е. *(a+i), где значение а является адресом первого элемента массива а, а именно a[0]. Выражение a+i является примером арифметических действий с указателями - целое значение i складывается со значением указателя, адресом первого элемента массива а. Значение этого выражения есть а плюс объем памяти, занимаемый i элементами массива a. Предположим, что x - двумерный массив. Тогда ссылка на подмассив x[i] является ссылкой на i-ю строку массива x. x[i] дает адрес первого элемента этой строки, т.е. *(x+i). Элементы каждой строки занимают непрерывную область памяти, так как массивы хранятся записанными по строкам, т.е. при записи элементов массива в память быстрее всех изменяется последний индекс.

Аналогично, ссылка на y[i], где y - n-мерный (n>1) массив, является ссылкой на (n-1)-мерный подмассив с элементами y[i, j2,j3,_jn], где значения jk соответствуют определению массива y. y[i] дает адрес первого элемента этого подмассива, т.е. *(y+i). Все элементы этого (n-1)-мерного подмассива занимают непрерывную область памяти.

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

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

Билет 36. Использование указателей в качестве итераторов. Идиома *р++

Итератор – это объект, выполняющий роль «бегунка», средство доступа и обхода контейнеров.

Контейнер – объект, предназначенный для хранения других объектов.

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

Рассмотрим такую задачу: допустим, у нас есть структура, в которой есть массив чисел. В массив, начиная с пятого элемента и во все нечетные, необходимо записать число 5. Данную задачу проще и быстрее решить с помощью итератора. Просто создаем указатель it на пятый элемент массива, а затем в цикле производим операцию: *it=5; it+=2;

Идиома –устоявшееся выражение, которое приобрело особый смысл.

Теперь по поводу идиомы *р++ (это выражение изначально говорит, что р является итератором). Унарные операции * и ++ имеют один и тот же приоритет, но выполняются слева направо (т.е. сначала указатель будет разыменован, а потом прибавление единички). Чтобы понять, к чему относится оператор, необходимо посмотреть в обратном направлении, справа налево (т.е. +1 идет к адресу, а не к содержанию ячейки памяти). Данная идиома используется в массивах, где надо обработать текущий элемент и перейти к следующему (напоминаю, что операция р++ эквивалентна р=р+1).

Билет 37. Обработка одномерных массивов (ввод\вывод и т.п.)

Массивы в С, как одномерные, так и двумерные, обрабатываются поэлементно и только поэлементно (исключение составляют строки, которые в данном билете не рассматриваются). В принципе, вот и весь ответ на данный вопрос. Чтобы сказать что-то более-менее объемное, надо написать Козину пример обработки, функцию ввода одномерного массива с клавиатуры, к примеру. Также желательно показать работу этой функции на модели одномерного массива:

Ar 0 1 2 … n

Т.е по шагам, как изменяется массив.

В принципе, все.

Билет 38. Обработка двумерных массивов (ввод\вывод и т.п.)

См. билет № 38. Отличия двумерного массива: при обработке используются вложенные циклы, обрабатывать можно по столбцам или построчно (если по столбцам, то во внешнем цикле стоит счетчик по столбцам, а во внутреннем – по строкам, если построчно, то наоборот).

Модель двумерного массива – таблица, притом имя массива является указателем на нулевой элемент нулевой строки. В памяти массив располагается в непрерывном блоке памяти (т.е. все его строки собраны в одном месте).

Билет 39. Массивы с переменными размерами в стандарте С99

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

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

int game(int r, int c)

{

int pole[r][c];

/* game */

return winner;

}

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]