Pascal: занятие № 10. двумерный массив в pascal
Содержание:
Указатели
- Указатели в Паскале необходимы при работе с динамической памятью.
- Переменная типа «указатель» в качестве своего значения содержит адрес участка динамической памяти, с которой связан этот указатель.
Объявление
- Типизированные указатели:

Универсальные нетипизированные указатели могут хранить адрес переменной любого типа:

Присваивание значений

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

1 2 3 4 5 6 7 8 9 10 |
var n, k integer;
pI ^integer;
begin
n = 4;
pI = @n;
writeln('Адрес n =' , pI);
writeln('n = ', pI^);
k = 4*(7 - pI^); // k = 4*(7 - 4) = 12
pI^ = 4*(k - n); // n = 4*(12 – 4) = 32
end.
|
Другой вариант присваивания значений — использование служебного слова NEW:
1 2 3 4 5 6 7 |
var pI ^integer;
begin
new(pI);
pI^ = 4;
writeln('Адрес =' , pI);
writeln('Значение = ', pI^);
end.
|
Пример работы с записями
1 2 3 4 5 6 7 8 9 10 11 |
Type rec = Record
Name string30;
Surname string30;
end;
var
P ^rec;
begin
new(P);
P^.Name='Иван';
write(P^.Name); // Иван
end.
|
Задание 1: Описать целочисленную переменную i. Описать указатель на целочисленную переменную i_ptr. Инициализировать i значением 2. Присвоить i_ptr значение i. Вывести значение, находящееся по адресу i_ptr.
Как создать двумерный динамический массив в C++
Для создания двумерного динамического массива мы будем использовать похожую конструкцию (как и в одномерном динамическом массиве):
<тип данных> **<имя массива> = new <тип данных массива>* ;
| 1 | <типданных>**<имямассива>=new<типданныхмассива>*<количествоячеек>; |
Вам нужно обратить внимание на:
Дополнительный оператор * перед и после .
Дальше для каждой ячейки мы должны создать одномерный массив. Чтобы это сделать, нам понадобится цикл for и конструктор .
for (int i = 0; i < n; i++) {
<имя массива> = new <тип ячеек> ;
}
|
1 |
for(inti=;i<n;i++){ <имямассива>i=new<типячеек> <количествоячеек>; |
В можно задавать разные значения. Поэтому сначала для первого массива можно задать длину 1 (), потом для второго — длину 2 (), как в примере ниже.
Внизу находится пример двумерного динамического массива:
#include <iostream>
using namespace std;
int main() {
setlocale(0, «»);
int **dinamic_array2 = new int* ; // создаем
for (int i = 0; i < 5; i++) { // двумерный
dinamic_array2 = new int ; // массив
} // !
for (int i = 0; i < 5; i++) {
cout << «Введите числа» << «(» << i + 1 << «)» << «:»;
for (int j = 0; j < i + 1; j++) {
cin >> dinamic_array2;
}
}
for (int i = 0; i < 5; i++) {
int sum = 0;
for (int j = 0; j < i + 1; j++) {
sum += dinamic_array2;
}
cout << «Сумма » << i + 1 << » массива равна » << sum << endl;
}
for (int i = 0; i < 5; i++) {
delete [] dinamic_array2; // удаляем массив
}
system(«pause»);
return 0;
}
|
1 |
#include <iostream> usingnamespacestd; intmain(){ setlocale(,»»); int**dinamic_array2=newint*5;// создаем for(inti=;i<5;i++){// двумерный dinamic_array2i=newinti+1;// массив }// ! for(inti=;i<5;i++){ cout<<«Введите числа»<<«(«<<i+1<<«)»<<«:»; for(intj=;j<i+1;j++){ cin>>dinamic_array2ij; } } for(inti=;i<5;i++){ intsum=; for(intj=;j<i+1;j++){ sum+=dinamic_array2ij; } cout<<«Сумма «<<i+1<<» массива равна «<<sum<<endl; } for(inti=;i<5;i++){ deletedinamic_array2i;// удаляем массив } system(«pause»); return; } |
- В строках 8 — 11: создали двумерный динамический массив.
- В строках 13 — 18: заполнили массив.
- В строках 20 — 26: подсчитали и вывели по отдельности на экран сумму всех массивов.
- В строках 28 — 30: происходит удаление массива (об этом ниже).
Задача
На каждом удаве из стаи написано его имя. Имя удава написано маленькими латинскими буквами от головы к хвосту. Все удавы из стаи ползут друг за другом, ведь так легче ползти. Иногда вожак даёт команду «Реверс». В этом случае каждый удав стаи разворачивается, и стая начинает ползти в противоположном направлении. Название стаи можно прочитать, если читать от головы удава, ползущего первым, к хвосту последнего. При этом название может измениться после команды «Реверс». Имена же удавов не меняются.
Входные данные
Первая строка содержит одно число $N (1 ≤ N ≤ 100000)$ – количество удавов. В следующих $N$ строках написаны имена удавов в том порядке, в котором они ползут. Имя удава – строчка, содержащая не более $10$ маленьких латинских букв.
6.2. Управление жизненным циклом динамического массива
Стандартный интеллектуальный указатель можно использовать для управления жизненным циклом динамического массива (см. ). Он имеет частичную специализацию для массивов, которая перегружает оператор вместо оператора и использует оператор в качестве удалителя по умолчанию. Вот пример:
Эта поддержка не является полноценной: не хранится информация о размере массива, соответственно, не поддерживается интерфейс стандартных контейнеров и диапазонный . Такое использование не рекомендуется, вместо этого лучше использовать . Интеллектуальный указатель не имеет даже такой поддержки массивов и совсем не рекомендуется для работы с динамическими массивами.
Классика жанра
Если мы откроем классический труд «Язык программирования C» Брайана Кернигана и Денниса Ритчи, то прочитаем, что «В языке C есть возможность работать с многомерными прямоугольными массивами, хотя на практике они используются гораздо реже, чем массивы указателей». C++ практически полностью унаследовал работу с многомерными массивами своего предтечи.
Определение автоматических многомерных массивов
В этом разделе я буду иногда употреблять термин «матрица» как синоним термина «двумерный массив». В C/C++ прямоугольный двумерный массив чисел действительно реализует математическое понятие «матрица». Однако, в общем случае, двумерный массив — понятие гораздо более широкое, чем матрица, поскольку он может быть и не прямоугольным, и не числовым.
Определение автоматических многомерных массивов почти полностью совпадает с определением одномерных массивов (о чём было рассказано в первой статье), за исключением того, что вместо одного размера может быть указано несколько:
В этом примере определяется двумерный массив из 3 строк по 5 значений типа в каждой строке. Итого 15 значений типа .
Во втором примере определяется трёхмерный массив, содержащий 3 матрицы, каждая из которых состоит из 5 строк по 2 значения типа в каждой строке.
Понятно, что тип данных, содержащихся в многомерном массиве, может быть любым.
При дальнейшем изложении для таких многомерных массивов будет употребляться термин «C-массив», что бы отличать их от массивов других видов.
Инициализация
При статической (определяемой на этапе компиляции) инициализации значения C-массива перечисляются в порядке указания размеров (индексов) в определении массива. Каждый уровень (индекс), кроме самого младшего, многомерного массива заключается в свою пару фигурных скобок. Значения самого младшего индекса указываются через запятую:
В примере показана статическая инициализация прямоугольного массива. Весь список инициализирующих значений заключён в фигурные скобки. Значения для каждой из 3 строк заключены в свою пару из фигурных скобок, значения для каждого из 5 столбцов для каждой строки перечислены через запятую.
При наличии инициализатора, самый левый размер массива может быть опущен. В этом случае компилятор сам определит этот размер, исходя из списка инициализации.
Заполнение массива значениями
Многомерный массив заполняется значениями с помощью вложенных циклов. Причём, как правило, количество циклов совпадает с размерностью массива:
В этом примере каждому элементу массива присваивается значение, первая цифра которого указывает номер строки, а вторая цифра — номер столбца для этого значения (нумерация с 1).
Вывод значений массива на консоль
В продолжение предыдущего примера можно написать:
В результате получим следующий вывод на консоль:
Для трёхмерного массива можно написать код, использующий те же приёмы:
Здесь присваивание значения элементу массива и вывод на консоль происходят в одной группе циклов.
Расположение в памяти
Для многомерного C-массива выделяется единый блок памяти необходимого размера: .
Значения располагаются последовательно. Самый левый индекс изменяется медленнее всего. Т.е. для трёхмерного массива сначала располагаются значения для первой (индекс 0) матрицы, затем для второй и т.д. Значения для матриц располагаются построчно (ср. со статической инициализацией массива выше).
Имя (идентификатор) многомерного C-массива является указателем на первый элемент массива (так же как и для одномерных массивов)
Если код из последнего примера немного изменить:
поставить точку останова на и посмотреть под отладчиком память, отведённую под переменную , то будет видно, что значения, расположенные в памяти, последовательно возрастают:
№1
Поскольку все значения многомерного C-массива располагаются последовательно, то, пользуясь адресной арифметикой, можно сделать следующий хак:
Или даже так:
В последнем фрагменте осуществляется доступ к значениям двумерного массива как к одномерному массиву. Цивилизованное решение реализуется через .
№2
Из двух примеров, приведённых выше, следует, что работу с двумерным или многомерным массивом (в понимании на более высоком уровне абстракции) технически можно организовать посредством одномерного массива соответствующего размера:
Этот приём достаточно распространён. Его выгода в том, что массив не обязательно должен быть выделен автоматически. Его можно выделять и динамически. Но при этом логически рассматривать как C-массив.
Вышеприведённый код написан в духе чистого C. В C++ обычно такие вещи прячут в класс, оставляя снаружи лаконичный интерфейс без всяких следов адресной арифметики.
Код программы (c-string)
e-olymp 3912 C++ solution
C++
#include <iostream>
#include <cstring>
using namespace std;
#define boa_name_size 11
int main()
{
int N;
cin >> N;
char **flock = new char *; // Создаем массив в N строк
for (int i = 0; i <= N; i++)
flock = new char; // Под каждую строку выделяем массив в boa_name_size символов
for (int i = 0; i <= N; i++)
cin.getline(flock, boa_name_size);
for (int i = N; i > 0; i—)
cout << flock;
return 0;
}
|
1 |
#include <iostream> usingnamespacestd; intmain() { intN; cin>>N; char**flock=newchar*N;// Создаем массив в N строк for(inti=;i<=N;i++) flocki=newcharboa_name_size;// Под каждую строку выделяем массив в boa_name_size символов for(inti=;i<=N;i++) cin.getline(flocki,boa_name_size); for(inti=N;i>;i—) cout<<flocki; return; } |
Очереди
Очередь — динамическая структура данных, у которой в каждый момент времени доступны только два элемента: первый и последний. Добавление элементов возможно только с одного конца (конца очереди), а удаление элементов – только с другого конца (начала очереди).
Существует сокращение для очереди: FIFO = First In – First Out, с английского — «Кто первым вошел, тот первым вышел».
Для очереди доступны следующие операции:
- добавить элемент в конец очереди (PushTail);
- удалить элемент с начала очереди (Pop).
Работа с очередью обычным массивом:
Это достаточно простой способ, который подразумевает два неблагоприятных момента: заблаговременное выделение массива, сдвиг элементов при удалении из очереди.
Работа с очередью с помощью кольцевого массива:

Если в очереди 1 элемент:
Если очередь пуста:
Если очередь заполнена:
Определение размера массива (при пустой и заполненной очереди):
Очередь в Паскале (использование кольцевого массива)
Создание структуры:
type Queue = record
data array1..MAXSIZE of integer;
head, tail integer;
end;
|
Как добавить в очередь:
procedure PushTail( var Q Queue; x integer);
begin
if Q.head = (Q.tail+1) mod MAXSIZE + 1
then Exit; { очередь уже полна }
Q.tail = Q.tail mod MAXSIZE + 1;
Q.dataQ.tail = x;
end;
|
Как выбрать из очереди:
function Pop ( var S Queue ) integer;
begin
if Q.head = Q.tail mod MAXSIZE + 1 then begin
Result = MaxInt;
Exit;
end;
Result = Q.dataQ.head;
Q.head = Q.head mod MAXSIZE + 1;
end;
|
Создание очереди посредством списка
Объявление узла:

1 2 3 4 5 6 7 8 |
type PNode = ^Node;
Node = record
data integer;
next PNode;
end;
type Queue = record
head, tail PNode;
end;
|
Добавляем новый элемент:
1 2 3 4 5 6 7 8 9 10 11 |
procedure PushTail( var Q Queue; x integer );
var NewNode PNode;
begin
New(NewNode);
NewNode^.data = x;
NewNode^.next = nil;
if Q.tail <> nil then
Q.tail^.next = NewNode;
Q.tail = NewNode;
if Q.head = nil then Q.head = Q.tail;
end;
|
Выбираем элемент из списка:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function Pop ( var S Queue ) integer;
var top PNode;
begin
if Q.head = nil then begin
Result = MaxInt;
Exit;
end;
top = Q.head;
Result = top^.data;
Q.head = top^.next;
if Q.head = nil then Q.tail = nil;
Dispose(top);
end;
|
Деки
Дек — англ. double ended queue, т.е. очередь с двумя концами – это динамическая структура данных, добавлять и удалять элементы в которой можно с обоих концов.
Задание: В файле записан список чисел. Необходимо переписать его в другой файл в обратном порядке.
Примеры работы с динамическими массивами
Пример: поиск элемента в массиве (выдавать индекс искомого)
Выполнение:
Выполним сначала БЕЗ использования :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function IndexOf(aarray of integer;xinteger)integer;
begin
result=-1;
for var i= to High(a) do
if ai=x then
begin
result=i;
break
end
end;
begin
var a=Arr(1,2,3,4,5);
print(IndexOf(a,5))
end.
|
А теперь, выполним с использованием :
1 2 3 4 5 6 7 8 |
function IndexOf<T>(aarray of T;xT)integer; begin ... end; begin var a=Arr(1,2,3,4,5); print(IndexOf(a,5)) end. |
При вызове обобщенной функции компиляция будет в два этапа:
- Автовыведение типа Т, сравнение с реальными цифрами, и т.к. числа целые, то Т определится как integer.
- Берется тело функции и заменяется Т на integer (инстанцирование функции с конкретным типом)
Очистка динамического массива
Если в программе случайно создается повторно один и тот же массив:
var a array of integer; a=new integer4; ... a=new integer5; |

В результате возникают так называемые участки «утекшей» памяти (неиспользуемой).
Постепенно произойдет переполнение памяти. В платформе .net используется автоматический сборщик мусора.
Но можно очистить память и принудительно:
a=nil; |
В процессе очистки выполнение программы и всех процессов приостанавливается. По этой причине сборщик мусора в системах реального времени не используется.
- Цикл for
for var i= to High(a) do print(ai);; |
Цикл foreach
foreach var x in a do
print(x);
|
Что такое динамические массивы
Мы уже знакомы с миром массивов в C++. Мы не раз создавали их на определенное количество ячеек и при этом использовали статическое создание массивов.
int array;
| 1 | intarray100; |
Но еще ни разу не затрагивали их использование с указателями!
Мы создавали массивы на сто тысяч элементов, а то и больше. И не один раз бывало, что большое количество ячеек оставались неиспользованными. Это является неправильным применением оперативной памяти в ПК.
Чтобы мы бесполезно не использовали оперативную память в компьютере, нам понадобится оперировать с указателями в свете массивов.
Нам нужно вспомнить, что для создания статического массива количество ячеек нужно задавать числовой константой (а не переменной). Это очень неприятно, потому что в программе мы не знаем, сколько нам может понадобится ячеек.
Например, пользователь захотел вписать 1000 чисел в массив, а мы из-за незнания этого факта сделали массив всего лишь на 500 ячеек.
Динамический массив — это массив, у которого количество ячеек можно задавать и переменной, и числовой константой. Это большой плюс перед использованием статического массива.
Как работают динамические массивы
Для работы динамических массивов нам понадобится при инициализации указатель (всего лишь при инициализации!) и уже знакомый конструктор .
Быстрое выделение памяти под многомерные массивы
Рассмотрим выделение памяти под двумерный массив. Типичная реализация, которая используется везде в этом курсе выглядит примерно так
const int M = 100;
const int N = 200;
int **a = NULL;
int i, j;
//Создаём массив указателей
a = (int**) malloc(M * sizeof(int*));
//Каждому элементу из массива указателей присваиваем
//адрес выделенного массива памяти
for (i = 0; i < M; i++) {
a = (int*) malloc(N * sizeof(int));
}
//Важные действия
//Удаление: сначала удаляем все массивы
for (i = 0; i < M; i++) {
free(a);
}
//Потом удаляем массив указателей
free(a);
В этом примере сначала выделяется память под массив указателей, потом M раз выделяется память под массивы. Во время удаления массива сначала M раз удаляются массивы, а потом удаляется массив указателей. Операции malloc и free затратные. Кроме того, выделение маленьких кусков памяти приводит к фрагментации памяти, так что последующее выделение памяти становится ещё медленнее.
Розовым обозначен массив указателей
Массив — это непрерывная последовательность байт. Массив не хранит своего размера. Указатель на массив хранит всего лишь адрес начала массива. Поэтому можно существенно ускорить выделение и освобождение памяти под массив. Выделяем сначала память под массив указателей, а затем первому элементу выделяем память под все массивы одновременно. Таким образом, первый элемент будет хранить адрес начала этого массива. С его помощью «делим» массив, раздавая его оставшимся указателям.
const int M = 100;
const int N = 200;
int **a = NULL;
int i;
a = (int**) malloc(M * sizeof(int*));
a = (int*) malloc(M * N * sizeof(int));
for (i = 1; i < M; i++) {
a = a + i * N;
}
//Важные действия
free(a);
free(a);
Теперь нам необходимо всего две операции выделения памяти и две операции для освобождения.
Розовым обозначен массив указателей
У этого подхода есть и ещё одно важное преимущество. Массив a по структуре становится похож на одномерный, так что его можно передавать как одномерный, например, для сортировки
Элементы расположены в нём по рядам, как в двумерном статическом массиве, поэтому без проблем можно его привести к типу указателя на массивы.
Можно пойти ещё дальше и заменить всё одним вызовом malloc: упаковать друг за другом сначала массив указателей, а потом массив массивов.
const int M = 100;
const int N = 200;
int **a = NULL;
int i, j;
a = (int**) malloc(M * sizeof(int*) + N * M * sizeof(int));
a = (int*)(a + M);
for (i = 1; i < M; i++) {
a = a + i * N;
}
//Важные действия
free(a);
Здесь всего одна операция выделения и одна освобождения.
Розовым обозначен массив указателей
Для массивов более высокой размерности выделение памяти остаётся очень похожим.
Скорость выполнения соотносится для данных способов выделения памяти как 404:13:12 для массива размером 100 x 200 типа int.
Последние два способа выделения памяти, дабы не смущать неокрепшие умы, почти не используются в курсе, но на практике динамически
выделять память под многомерные массивы лучше именно таким образом.
Рассмотрим выделение памяти под трёхмерный массив. Трёхмерный массив — массив указателей на указатели, которые ссылаются
на массивы указателей, которые ссылаются на массивы объектов заданного типа. Выделение памяти под трёхмерный массив размером
M*N*K, соответственно, потребует M + M*N операций выделения памяти и столько же для освобождения.
Серым обозначен массив указателей на указатели, розовым массив указателей
Первым делом объявим переменные
const int M = 10; const int N = 10; const int K = 10; int*** a = NULL; int* data; int** ptrs; int i, j, k;
Здесь a — наш будущий трёхмерный массив, data — вспомогательная переменная, которая хранит
адрес, по которому начинаются непосредственно данные (белым цветом на рисунке). ptrs — вспомогательная
переменная, которая хранит адрес, по которому начинаются массивы указателей (розовый на рисунке).
Для начала выделим память под массив
a = (int***) malloc(M * sizeof(int**) + M*N * sizeof(int*) + M*N*K * sizeof(int));
Затем инициализируем вспомогательные переменные
ptrs = (int**) (a + M); data = (int*) (a + M + M*N);
Затем надо инициализировать массив указателей на указатели
for (i = 0; i < M; i++) {
a = ptrs + i*N;
...
}
Но также нужно инициализировать каждый из массивов указателей
for (i = 0; i < M; i++) {
a = ptrs + i*N;
for (j = 0; j < N; j++) {
a = data + j * N*K;
}
}
Теперь наш массив принимает вид:
Серым обозначен массив указателей на указатели, розовым массив указателей
Закрепим
const int M = 10;
const int N = 10;
const int K = 10;
int*** a = NULL;
int* data;
int** ptrs;
int i, j, k, q;
a = (int***) malloc(M * sizeof(int**) +
M*N * sizeof(int*) +
M*N*K * sizeof(int));
ptrs = (int**) (a + M);
data = (int*) (a + M + M*N);
q = 0;
for (i = 0; i < M; i++) {
a = ptrs + i*N;
for (j = 0; j < N; j++) {
a = data + (q++) * N*K;
}
}
Q&A
Всё ещё не понятно? – пиши вопросы на ящик
Примеры
Паскаль
Динамические массивы поддерживаются Delphi, FreePascal, но не Turbo Pascal.
var byteArray Array of Byte; // Одномерный массив multiArray Array of Array of string; // Многомерный массив ... begin ... // Установить размер одномерного массива в n элементов SetLength (byteArray, n); // Доступ к динамическому массиву аналогичен доступу к обычному. // Индексация всегда начинается с нуля, индексы - всегда целые. byteArray := 10; // Изменить размер до m элементов. SetLength(byteArray, m); ... // Установить размер двумерного массива в X*Y элементов SetLength(multiArray, X, Y); multiArray7,35 := 'ru.wikipedia.org'; ... end.
Си
В самом языке Си нет динамических массивов, но функции стандартной библиотеки , и позволяют реализовать массив переменного размера:
int *mas = (int*)malloc(sizeof(int) * n); // Создание массива из n элементов типа int ... mas = (int*)realloc(mas, sizeof(int) * m); // Изменение размера массива с n на m с сохранением содержимого ... free(mas); // Освобождение памяти после использования массива
Неудобство данного подхода состоит в необходимости вычислять размеры выделяемой памяти, применять явное преобразование типа и тщательно отслеживать время жизни массива (как и всегда при работе с динамически выделенной памятью в Си).
Многомерный динамический массив может быть создан как массив указателей на массивы:
int **A = (int **)malloc(N*sizeof(int *));
for(int i = ; i < N; i++) {
Ai = (int *)malloc(M*sizeof(int));
}
Однако рост размерности существенно усложняет процедуры создания массива и освобождения памяти по завершении его использования. Ещё более усложняется задача изменения размера массива по одной или нескольким координатам.
Некоторые компиляторы Си предоставляют нестандартную библиотечную функцию , несколько упрощающую работу с динамическими массивами. Эта функция выделяет память не в куче, как , а на стеке, и эта память автоматически освобождается при достижении оператора . То есть при выделении памяти динамического массива этой функцией его не нужно удалять вручную, но такой массив невозможно вернуть из функции в точку вызова.
Начиная с версии стандарта C99 в язык введены массивы переменной длины. В обычном синтаксисе описания массива Си на месте размера массива может указываться не только константа, но и переменная целого типа:
void func(int arraySize) {
int masarraySize]; // Описание массива переменной длины
for (int i = ; i < arraySize; ++i) {
masi = anotherFunc(i); // Обращение к элементам массива
}
...
}
Массив переменной длины может получить любой необходимый размер в момент создания. Память под него выделяется на стеке. Массив переменной длины существует до выхода из области видимости, в которой он был объявлен, после чего его память автоматически освобождается. Как и в предыдущем случае, массив переменной длины невозможно вернуть из функции в точку вызова.
С++
В C++ поддерживаются функции работы с памятью из стандартной библиотеки Си, но их использование не рекомендуется. Массив переменной длины здесь также можно выделить с помощью стандартных команд работы с динамической памятью и :
// Создание массива длиной n int *mas = new intn]; ... // Освобождение памяти массива delete []mas;
Как и в случае с Си, здесь требуется отслеживать время жизни массива, чтобы избежать утечки памяти или, наоборот, преждевременного освобождения памяти. Аналога здесь нет, так что изменить размер массива можно только вручную, выделив новую память нужного размера и перенеся в неё данные.
Библиотечным решением является шаблонный класс :
std::vector<int> mas; // Создать пустой вектор mas.reserve(100); // Выделить вектору память под 100 элементов (размер останется нулевым) mas.resize(50); // Задать размер вектора в 50 элементов masi = i; // Обращение к элементу по индексу mas.push_back(100); // Добавить элемент x = mas.back; // Обращение к последнему элементу mas.pop_back(); // Удалить последний элемент std::cout << mas.size() << " " << mas.capacity() << "\n"; // Вывести ёмкость и размер mas.shrink_to_fit(); // Уменьшить ёмкость до размера
имеет множество методов и переопределённых операторов, часть из которых показана выше на примере. Они позволяют обращаться по индексу, изменять в любую сторону размер массива, использовать его как стек. Управляемым является не только актуальный размер, но и ёмкость вектора, что позволяет оптимизировать процесс выделения памяти. Стандарт C++ требует от реализации обязательного выполнения условий:
- все элементы вектора должны храниться подряд в порядке увеличения индекса в целостном блоке оперативной памяти;
- должно быть гарантировано константное время доступа к элементу вектора.
Вывод информации
Функция 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;}
Результат работы программы
Тот же самый код может быть представлен с использованием одного вызова printf:
123456789
#include <stdio.h>int main(){ int a = 5; float x = 2.78; printf(«a=%d\nx=%f\n», a, x); getchar(); return 0;}
Описание, ввод и вывод элементов двумерного массива
Варианты описания двумерного массива
- Описание массива в разделе переменных:
const N = 3;
M = 4;
var A array1..N,1..M of integer;
|
Описание массива через раздел type:
const M=10; N=5; type matrix=array 1..M, 1..N of integer; var A matrix; |
Ввод двумерного массива m x n с клавиатуры:

for i=1 to N do
for j=1 to M do begin
write('A=');
read ( Ai,j );
end;
|
Заполнение случайными числами:

«Красивый» вывод элементов двумерного массива m x n:
Следующий фрагмент программы выводит на экран значения элементов массива по строкам:
1 2 3 4 5 |
for i=1 to N do begin
for j=1 to M do
write ( Ai,j5 );
writeln;
end;
|
Рассмотрим следующую задачу: Получены значения температуры воздуха за 4 дня с трех метеостанций, расположенных в разных регионах страны:
| Номер станции | 1-й день | 2-й день | 3-й день | 4-й день |
|---|---|---|---|---|
| 1 | -8 | -14 | -19 | -18 |
| 2 | 25 | 28 | 26 | 20 |
| 3 | 11 | 18 | 20 | 25 |
Т.е. запись показаний в двумерном массиве выглядела бы так:
| t:=-8; | t:=-14; | t:=-19; | t:=-18; |
| t:=25; | t:=28; | t:=26; | t:=20; |
| t:=11; | t:=18; | t:=20; | t:=25; |
Объявление двумерного массива:
var t array 1..3, 1..4 of integer; |
Задание array 1: Необходимо:
- Распечатать температуру на 2-й метеостанции за 4-й день и на 3-й метеостанции за 1-й день.
- Распечатать показания термометров всех метеостанций за 2-й день.
- Определить среднюю температуру на 3-й метеостанции.
- Распечатать, в какие дни и на каких метеостанциях температура была в диапазоне 24-26 градусов тепла.
Дополните код:
Показать решение:
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 |
var t array 1..3, 1..4 of integer;
s,i,jinteger;
begin
t1,1=-8; t1,2=-14; t1,3=-19; t1,4=-18;
t2,1=25; t2,2=28; t2,3=26; t2,4=20;
t3,1=11; t3,2=18; t3,3=20; t3,4=25;
{1. Распечатать показания термометров на 2-й метеостанции за 4-й день и на 3-й метеостанции за 1-й день}
writeln('1-е задание: ',t2,4 , ' и ',t...,...);
{2. Показания термометров всех метеостанций за 2-й день}
for i=1 to ... do
writeln ('2-е задание: ',t...,...);
{3. Определим среднее значение температуры на 3-й метеостанции:}
i=3;
s=;
for j=1 to 4 do
s=...; {сумматор}
writeln('3-е задание: ', s4);
{распечатаем всю таблицу}
for i=1 to 3 do
for j=1 to 4 do
writeln(ti,j);
{4. Распечатаем станции и дни с температурой 24-26 гр}
writeln('4-е задание: ');
for i=1 to 3 do
for ... ... do
if (...) and (...) then
writeln('станция ', i, ' день ', j)
end.
|
Самостоятельно подумайте, как находится сумма элементов массива pascal.
Задание array 2. Найти элементов массива (прямоугольной таблицы) размером
Задание array 3. Найти массива размером
Задание array 4.
Найти всех элементов массива (переменная ) 5 x 4, а также сумму элементов, составляющих столбцы таблицы (двумерного массива). Для хранения сумм столбцов чисел использовать одномерный массив (). Дополните код.
Показать решение:
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 33 34 |
const m = 5;
n = 4;
var
a array1..m,1..n of byte;
s array1..n of byte;
i,j, sum byte;
begin
randomize;
for i = 1 to m do begin
for j = 1 to n do begin
... {инициализация элементов массива случайными числами}
... {вывод элементов массива}
end;
writeln
end;
writeln ('------------'); {для оформления}
{обнуление значений массива суммы s[]:}
...
{поиск сумм элементов по столбцам:}
for i = 1 to n do begin
for j = 1 to m do begin
si=...;
end;
write(...) ;
end;
{поиск общей суммы:}
sum=;
...
{вычисление суммы элементов массива значений сумм по столбцам:}
for ...
...
write (' | sum = ', sum);
readln
end.
|
Задание array 4_1.
Найти сумму элементов двумерного массива по строкам:
2 8 1 9 : sum = 20 3 1 7 2 : sum = 13 4 5 6 2 : sum = 17