Двумерные массивы в c. Массив указателей
тип имя[размер №1][размер №2];
Размеры двумерного массива в СИ указываются в отдельных парных квадратных скобках после имени и могут быть любыми положительными целочисленными значениями. На практике принято значение первой размерности называть строками, а второй – столбцами. Как и в случае одномерного массива, в стандарте С89 регламентируется, что размеры двумерного массива должны быть целочисленными константами.
Стандарт С99 допускает объявление динамических двумерных массивов путём использования выражений при указании размеров матрицы, если в это выражение входят значения определенных ранее переменных (выражение должно иметь положительный целочисленный результат). Например:
int n,m;
printf("Введите размеры матрицы: ”);
scanf("%d %d”,&n,&m);
double a[n][m]; При объявлении двумерного массива в СИ допускается производить инициализацию значений элементов матрицы:
тип имя[размер №1][размер №2] = {
{значение № 11, ... значение № 1N},
...
{значение № M1, ... значение № MN}
}; Примеры объявлений с инициализацией:
int a = { //Объявлен двумерный массив
{1,2,3,4}, // 1 2 3 4
{5,6}}; // 5 6 0 0
Double b = { //Объявлен двумерный массив
{1.0, 2.0, 3.0, 4.0, 5.0}, // 1 2 3 4 5
{6.0, 7.0} // 6 7 0 0 0
}; // 0 0 0 0 0
int a = {{1,2,3,4,5},{6,7,8,9,0}}; Допускается не указывать количество строк в двумерном массиве (указываются пустые квадратные скобки). В таком случае размер массива будет определен по числу инициализирующих значений строк. Количество столбцов матрицы всегда необходимо указывать. Например:
double b = {{1,2,3,4},{5,6,7,8}}; Объявление константных матриц (значения их элементов изменить нельзя) начинается с ключевого слова const, за которым следует объявление матрицы с инициализацией. Пример:
const int matrix = {
{1,2,3,4,5},
{6,7,8,9}
}; Обращение к элементу матрицы осуществляется путем указания имени матрицы, а после имени в отдельных парных квадратных скобках индексы элемента (строка и столбец):
имя[строка][столбец] Индексация в языке СИ начинается с нуля, поэтому для матрицы размером, например, пять строк и десять столбцов правильными будут индексы строк от нуля до четырех, а столбцов – от нуля до девяти включительно.
Каждый отдельный элемент матрицы может рассматриваться как простая переменная и, соответственно, выступать в выражениях в качестве RValue или LValue значений.
Ввод и вывод матриц в языке СИ осуществляется поэлементно. Так как матрица имеет двойную размерность, то ввод и вывод осуществляется во вложенных циклах. Например:
double a;
for(int i=0;i<5;i++)
for(int j=0;j<10;j++)
scanf("%lf”,&a[i][j]);
...
for(int i=0;i<5;i++){
for(int j=0;j<10;j++)
printf("%8.2lf\t”,a[i][j]);
printf("\n”);
} Присвоение матрицы матрице также осуществляется поэлементно. Например, необходимо присвоить целочисленную матрицу x целочисленной матрице y. Фрагмент программы:
int x, y;
...
for(int i=0;i<5;i++)
for(int j=0;j<10;j++)
y[i][j] = x[i][j];
... В языке СИ допускается создание массивов размерностью три и более(т.е трехмерных, четырехмерных и т.д.). Например, объявление трёхмерного целочисленного массива с инициализацией будет иметь вид:
int a={ //это трехмерный массив
{{1,2},{3,4}},
{{5,6},{7,8}}
}; Ввод, вывод и прочая обработка такого массива осуществляется аналогично обработке двумерного массива, только уже в трех вложенных
Вообще-то программировать расчёт определителей не нужно. Их умеет считать, скажем, встроенная функция МОПРЕД из Excel:
- набираем элементы матрицы в смежных ячейках, например, матрица размерностью 4*4 показана на картинке;
- в нужной ячейке вводим формулу (в нашем случае =МОПРЕД(A1:D4) и нажимаем Enter:)
Не труднее вычислить и в MathCAD - просто нажать кнопку на панели матриц...
Но иногда нужен алгоритм, а не ответ... вот немного кода на консольном C++, на совершенство он не претендует, но нули в матрице или "не тот" порядок элементов смущать функцию determinant не должны. Пример из main - 1001-й на работу с динамической матрицей средствами C++ :) Остальное закомментировано в исходнике.
#define bool int
#define true 1
#define false 0
int search (double **a, int m, int n, double what,
bool match, unsigned int &uI, unsigned int &uJ, unsigned int starti, unsigned int startj) {
// Поиск в матрице a[m][n] элемента с указанным значением what
// Возвращаеются его номер строки и столбца uI, uJ, если элемент найден.
// match - искать равный элемент или отличный от указанного.
// Вернёт 0 - не найдено, не 0 - найдено
if ((!m) || (!n)) return 0;
if ((starti >= n) || (startj >= m)) return 0;
for (unsigned int i = starti; i < n; i++)
for (unsigned int j = startj; j < m; j++) {
if (match == true) {
if (a[i][i] == what) {
uI = i; uJ = j; return 1;
}
}
else if (a[i][j] != what) {
uI = i; uJ = j; return 1;
}
}
return 0;
}
void swaprows (double **a, int n, int m, unsigned int x1, unsigned int x2) {
//Меняет в матрице a[n][m] строки с номерами x1 и x2 местами
if ((!n) || (!m)) return;
if ((x1 >= n) || (x2 >= n) || (x1 == x2)) return;
double tmp;
for (unsigned int x = 0; x < m; x++) {
tmp = a[x];
a[x] = a[x];
a[x] = tmp;
}
return;
};
void swapcolumns (double **a, int n, int m, unsigned int x1, unsigned int x2) {
//Меняет в матрице a[n][m] столбцы с номерами x1 и x2 местами
if ((!n) || (!m)) return;
if ((x1 >= m) || (x2 >= m) || (x1 == x2)) return;
double tmp;
for (unsigned int x = 0; x < n; x++) {
tmp = a[x];
a[x] = a[x];
a[x] = tmp;
}
return;
};
double determinant (double **a, unsigned int n) {
//Вычисление определителя квадратной матрицы a[n][n]
unsigned int m = n;
if (m == 0) return 0;
if (m == 1) return a;
if (m == 2) return (a * a - a * a);
bool sign = false; // смена знака определителя. по умолчанию - нет
double det = 1; // определитель
double tmp;
unsigned int x, y;
for (unsigned int i = 0; i < n; i++) { // цикл по всей главной диагонали
if (a[i][i] == 0) { // если элемент на диагонали равен 0, то ищем ненулевой элемент в матрице
if (!search(a,m,n,0, false, y, x, i, i)) return 0; // если все элементы нулевые, то опр. = 0
if (i != y) { // меняем i-ую строку с y-ой
swaprows(a,m,n,i, y);
sign = !sign;
}
if (i != x) { // меняем i-ый столбец с x-ым
swapcolumns(a,m,n,i, x);
sign = !sign;
}
// таким образом, в a[i][i], теперь ненулевой элемент.
}
// выносим элемент a[i][i] за определитель
det *= a[i][i];
tmp = a[i][i];
for (x = i; x < m; x++) {
a[i][x] = a[i][x] / tmp;
}
// таким образом a[i][i] теперь равен 1
// зануляем все элементы стоящие под (i, i)-ым,
// при помощи вычитания с опр. коеффициентом
for (y = i + 1; y < n; y++) {
tmp = a[y][i];
for (x = i; x < m; x++)
a[y][x] -= (a[i][x]*tmp);
}
}
if (sign) return det*(-1);
return det;
};
#include
Внимание! Об
обновлениях смотри внизу этой страницы. Последнее обновление – от 18.04.2018.
Введение
Класс
DMatrix разработан на языке C++ (в среде Borl
a
nd
Builder
6) и предназначен для
встраивания в исходный код с целью упрощения программирования операций с
матрицами.
Класс
позволяет использовать при программировании переопределенные операции:
присвоение, сложение матриц, умножение матриц, умножение матрицы на число (справа).
Например, код C++, использующий объекты данного класса, может выглядеть так:
A = B;
A = B + C;
A = B * C;
A = B * c;
где
A
,
B
и
C
– объекты класса, с
– переменная
типа float
,
double
или
long
double
.
Кроме
того, класс содержит функции обращения матрицы, вычисления определителя и
транспонирования:
A = B.
Inverse
();
-обращение матрицы
B
;
d
=
B
.
det
(
);
-вычисление определителя матрицы
B
;
A = B.
T
(
);
-транспонирование матрицы
B
.
Значения
ячеек матрицы имеют тип long
double
, что позволяет производить операции с
большой точностью. В некоторых достаточно сложных прикладных задачах,
построенных на итеративных алгоритмах, увеличение точности вычислений приводит
к ускорению сходимости алгоритма, то есть даже ускоряет работу программы.
Важное
преимущество нашего класса заключается в реализации подхода «динамическая
матрица».
В
прикладных задачах, связанных с обработкой потоков информации, встает задача
оперативного формирования матриц на основе данных (сигналов), поступающих по
нескольким каналам. При этом, во-первых, данные не должны пропадать из-за
нехватки времени, они должны без временных задержек наполнять матрицы, позволяя
математическому алгоритму быстро приступать к их обработке. Во-вторых, память
компьютера должна использоваться рационально, чтобы избежать переполнения
памяти при больших потоках информации.
Объект
класса DMatrix можно изобразить в виде стакана:
Матрица,
хранящаяся в данном объекте, имеет размерность m*n
. Как правило, в случае работы с потоком данных число n
– это количество переменных,
содержащихся в потоке, и/или каких-то рассчитанных величин, например, производных
по времени от переменных потока.
Рациональное
использование памяти при работе с динамической матрицей подразумевает
динамическое выделение памяти для строк матрицы (низ стакана) и динамическое
освобождение памяти от использованных строк (верх стакана).
При
операциях с матрицами, таких, как сложение, умножение, вычисление определителя
и др., обработке подвергаются только актуальные данные, для указания на которые
служит переменная k.
При
обработке сигналов от устройств часто возникают задача формирования и решения в
реальном времени систем уравнений. Для этой цели сделаны классы LSM и
PROJECTION, работающие с нашими динамическими матрицами. В них реализованы
алгоритмы решения систем линейных алгебраических уравнений с гибкой системой
настройки параметров. Алгоритмы базируются на методе наименьших квадратов с
«коэффициентом экспоненциального забывания» и проекционном решающем алгоритме.
Настройки этих алгоритмов позволяют адаптировать их как для чистки входящих
сигналов, так и для быстрого реагирования решения на скачки сигналов на входе.
Таким образом, программист (или эксплуатант), подбирая эти настройки, должен
найти оптимальный баланс между точностью решения и быстротой реагирования.
Переменные и функции класса
DMatrix
Класс
содержит переменные:
int
m
;
- количество строк матрицы
int
n
;
- количество столбцов матрицы
int k;
-
указатель на последнюю строку матрицы. При операциях в качестве актуальных
строк матрицы используются строки массива с индексами(k-m), … , (k
-1).
int M;
- количество указателей на строки матрицы
long double **data;
- указатель на двумерный массив значений
ячеек матрицы
booloblom;
- признак аварийного
результата выполнения операции
Класс
содержит функции:
long
double
__
fastcall
det
(
void
);
- расчет определителя
матрицы
DMatrix
__
fastcall
T
(
void
);
-
транспонирование матрицы
DMatrix
__
fastcall
Inverse
(
void
);
- расчет обратной матрицы
void
__
fastcall
Ini
(
m
0,
n
0,
M
0,
k
0);
- инициализация переменных объекта-матрицы и выделение памяти
void
__
fastcall
de
_
allocate
(
void
);
- чистка памяти: удаление
m
строк
матрицы из диапазона (k-m), … , (k
-1) и
указателей наэти строки
void
__
fastcall
Allocate
(
int
k
0);
- выделение памяти для
указанной строки
void
__
fastcall
Delete
(
int
k
0);
- чистка памяти:
удаление указанной строки
Работа с матрицами
Пример
1.
Рассмотрим
простейший пример – сложение двух матриц:
Сначала
нужно добавить в проект наш класс. Если используется среда Borland
Builder
, то необходимо добавить в проект файл
dmatrix
.
cpp
и подключить его в
unit
’е, в котором мы будем работать с
матрицами; для этого напишем в
header
-файле
директиву#include
"
d
matrix.h
"
.
Добавим
на форму кнопку
Button
1 и
надпись Label1. В функцию Button1Click поместим следующий код.
Объявим
3 матрицы:
DMatrixA, B, C;
(слагаемые и результат,
C
=
A
+
B
),
опишем
свойства этих матриц и выделим память для строк и столбцов матриц:
A.m = 2;
A.n = 2;
A.k = 2;
A.M = 2;
A.oblom = false;
A.data = new long double*;
for (inti = 0; i < A.k;
i++)A.data[i] = new long double;
То же
самое можно написать более компактным образом, с помощью функции Ini:
A
.
Ini
(2, 2, 2, 2);
В
результате выполнения функции
Ini
(m
0,
n
0,
M
0,
k
0) задаются значения переменных A.m, A.n,
A.M, A.k, выделяется память для A.M указателей на строки и выделяется память
для A.k строк.
Примечание
по работе Ini
:
Иногда
нет смысла сразу выделять память под строки. В этом случае можно написать:A.Ini(2, 2, 2).После выполнения функции Ini с тремя аргументами
будет присвоено A.k = 0, о чем не стоит забывать, т.к. A.k = 0 указывает на
матрицу из 0 строк; если мы хотим указать на матрицу из A.m строк, то A.k
должен быть не меньше
A
.
m
.
Можно
также сделать двухместный вызов этой функции:A.Ini(2, 2), в этом случае не будет выделена память для указателей на
строки и будет присвоено A.
M
= 0.
Так же
поступим с матрицами
B
и
C
:
B
.
Ini
(2, 2, 2, 2);
C
.
Ini
(2, 2, 2, 2);
Зададим
значения ячеек матриц
A
и B:
A.data = 1;
A.data = 2;
A.data = 3;
A.data = 4;
B.data = 5;
B.data = 6;
B
.
data
= 7;
B
.
data
= 8;
и,
наконец, сложим матрицы:
C
=
A
+
B
;
В
результате сложения в массиве C.data появится требуемый результат, который
можно вывести на экран. Например:
Label
1->
Caption
=
FloatToStr
(
C
.
data
);
- на форме отобразится значение ячейки
(1-я строка, 1-й столбец), равное 6.
После
получения результата и его выгрузки освободим память:
if(A.data)A.de_allocate();
if(B.data)B.de_allocate();
if(C.data)C.de_allocate();
Важное
замечание по поводу работы функции de_allocate():эта функция удаляет только строки в диапазоне
(k-m), … , (k
-1)(имеются в виду индексы массива data в C++
коде, то есть нумерация идет с 0). То есть «рабочую» часть нашего стакана.Перед запуском de_allocate() надо быть
уверенным, что все прочие строки, лежащие вне данного диапазона, были удалены
ранее. В нашем примере k = m, поэтому функцию выполнять можно; вопрос
постепенного удаления «отслуживших» строк рассмотрим в следующем примере.
Исходный
код рассмотренного примера – .
Пример
2.
Предположим,
что требуется оценивать некоторую характеристику потока измерений, поступающих
в компьютер с внешних устройств. Например, это данные с
N
датчиков.
В каждый
момент времени имеем
N
значений, из которых можно составить строку матрицы, то есть можно сказать, что
на вход приходят строки. Пусть характеристика, которую надо вычислять –
детерминант. Для того, чтобы его вычислить, нам нужно иметь
N
строк, т.к. матрица должна быть
квадратной.
Опишем
матрицу и выделим память (только для указателей на строки):
X
.
Ini
(
N
,
N
, 10000);// Не указали
значение
k
- не выделилось место под строки
X
.
k
= 1;
while
(
X
.
k
<=
X
.
M
)
{
X
.
Allocate
(
X
.
k
- 1);// Выделяем память для строки
if
(
X
.
k
>
X
.
m
)
X
.
Delete
(
X
.
k
-
X
.
m
- 1);// Удаляем
последнюю использованную, но пока не удаленную строку
// Заполняем новую строку (симуляция
сигналов)
for(i = 0; i < N; i++)
X.data[i] = (((rand() %
RAND_MAX)+1.0)/RAND_MAX);//
Равномерно распределенная на случайная величина
if
(
X
.
k
>=
X
.
m
)
det
=
X
.
det
();// Появилось
m
строк - можно считать определитель
X
.
k
++;
}
Полный
текст пр
ограммы - . В
исходном коде добавлено умножение матрицы на себя, дискриминант берется от
матрицы-произведения. Отображение результатов на форме сделано с помощью
таймера.
Исходя
из значения X.M можно оценить, сколько раз в секунду Ваш компьютер находит
значение определителя матрицы размера
N
*
N
(всего определитель вычисляется (X.M-
N
+1) раз). Увеличивая размер матрицы, можно
получить представление о возможностях алгоритма.
Важное
замечание: в этом примере мы освобождали и выделяли память для строк на каждом
шаге. Для повышения быстродействия иногда имеет смысл перераспределять память с
интервалом в несколько шагов, большими кусками. То есть через несколько шагов
добавлять / удалять сразу по несколько строк матрицы.
Так как
функция de_allocate() освобождает память от строк с индексами из диапазона(k-m),
… , (k
-1),
важно перед запуском функции указать правильное значение k. Для этого в
исходном коде после главного цикла указано:X.k--;
, чтобы сбросить последнее увеличение X.k на единицу.
Динамическая идентификация состояния системы
Для
демонстрации возможностей работы с классом предлагается пример (с исходниками) .
При
запуске программы (matrix.exe) открывается форма, на которой можно задавать
матрицы и производить простейшие операции с ними. В исходном тексте можно
увидеть, каким образом используется наш класс при программировании на C++.
При
нажатии на кнопку «Динамические операции» открывается форма для решения
следующей задачи.
Пусть у
нас есть 4 сигнала, поступающих на вход:X 1 , X 2 , X 3
и Y
. Мы предполагаем, что эти 4
переменные связаны между собой линейным уравнением:
C
1
* X 1 +
C
2
* X 2 +
C
3
* X 3 = Y
В качестве
одного или нескольких входных параметров может использоваться как физический
сигнал, так и расчетные величины, например, производные или отфильтрованные
данные.
Требуется
оценить в каждый момент времени коэффициенты состояния системы
C
1
,
C
2
,
C
3
, то
есть решить уравнение относительно C i
.
В
идеальных условиях, при отсутствии шума и при постоянных X 1 , X 2 , X 3
и Y
в каждый момент времени мы получаем одно и то же уравнение,
имеющее бесконечное множество решений. На практике мы имеем шум и изменяющиеся значения
сигналов, в результате чего получается система из большого количества
несовместных уравнений.
Для
приближенного решения несовместной системы существует несколько вычислительных
подходов; в нашей программе реализована комбинация 2-х методов:МНК (Метод наименьших квадратов) с
«коэффициентом экспоненциального забывания» и обобщенный проекционный алгоритм.
Использование
подхода МНК обусловлено необходимостью получения на каждом шаге невырожденной
матрицы для последующего решения системы уравнений проекционным алгоритмом. Для
увеличения гибкости настройки вводится коэффициент экспоненциального забывания
W
2
, смысл
которого состоит в усреднении вновь полученной методом МНК системы с
аналогичной системой, полученной на предыдущем шаге. Чем больше значение
W
2
, тем
больший вес имеют предыдущие значения. Коэффициент принадлежит интервалу ;
Если процесс – единственный,
этого делать не надо, по умолчанию
Thr
= 0.
То же касается и инициализации
объектов
LSM
и
PROJECTION. В этих классах в функциях инициализации добавлена еще одна
переменная (по умолчанию также равная 0):
LSMLsm;
Lsm
.Ini
(…,
…, [
номер
процесса
]);
PROJECTIONProjection
;
Projection
.
Ini
0(…, [номер процесса]);
Все исходники,
доступные к скачиванию с данной страницы, обновлены с учетом этих изменений.
При решении задач с большим количеством данных одинакового типа использование переменных с различными именами, не упорядоченных по адресам памяти, затрудняет программирование. В подобных случаях в языке Си используют объекты, называемые массивами. — это непрерывный участок памяти, содержащий последовательность объектов одинакового типа, обозначаемый одним именем. Массив характеризуется следующими основными понятиями: Элемент массива (значение элемента массива)
– значение, хранящееся в определенной ячейке памяти, расположенной в пределах массива, а также адрес этой ячейки памяти. Адрес массива
– адрес начального элемента массива. Имя массива
– идентификатор, используемый для обращения к элементам массива. Размер массива
– количество элементов массива Размер элемента
– количество байт, занимаемых одним элементом массива. Графически расположение массива в памяти компьютера можно представить в виде непрерывной ленты адресов. Представленный на рисунке массив содержит q
элементов с индексами от 0
до q-1
. Каждый элемент занимает в памяти компьютера k
байт, причем расположение элементов в памяти последовательное. Адреса i
-го элемента массива имеет значение Адрес массива представляет собой адрес начального (нулевого) элемента массива. Для обращения к элементам массива используется порядковый номер (индекс) элемента, начальное значение которого равно 0
. Так, если массив содержит q
элементов, то индексы элементов массива меняются в пределах от 0
до q-1
. Длина массива
– количество байт, отводимое в памяти для хранения всех элементов массива. ДлинаМассива = РазмерЭлемента * КоличествоЭлементов
Для определения размера элемента массива может использоваться функция int
sizeof
(тип); Например, sizeof
(char
) = 1; Для объявления массива в языке Си используется следующий синтаксис: тип имя[размерность]={инициализация};
Инициализация
представляет собой набор начальных значений элементов массива, указанных в фигурных скобках, и разделенных запятыми. int
a = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // массив a из 10 целых чисел
Если количество инициализирующих значений, указанных в фигурных скобках, меньше, чем количество элементов массива, указанное в квадратных скобках, то все оставшиеся элементы в массиве (для которых не хватило инициализирующих значений) будут равны нулю. Это свойство удобно использовать для задания нулевых значений всем элементам массива. int
b = {0}; // массив b из 10 элементов, инициализированных 0
Если массив проинициализирован при объявлении, то константные начальные значения его элементов указываются через запятую в фигурных скобках. В этом случае количество элементов в квадратных скобках может быть опущено. int
a = {1, 2, 3, 4, 5, 6, 7, 8, 9}; При обращении к элементам массива индекс требуемого элемента указывается в квадратных скобках . Пример на Си
1 #include
Результат выполнения программы: Однако часто требуется задавать значения элементов массива в процессе выполнения программы. При этом используется объявление массива без инициализации. В таком случае указание количества элементов в квадратных скобках обязательно. int
a; Для задания начальных значений элементов массива очень часто используется параметрический цикл: 1 Результат выполнения программы В языке Си могут быть также объявлены многомерные массивы. Отличие многомерного массива от одномерного состоит в том, что в одномерном массиве положение элемента определяется одним индексом, а в многомерном - несколькими. Примером многомерного массива является матрица. Общая форма объявления многомерного массива тип имя[размерность1][размерность2]...[размерностьm]; Элементы многомерного массива располагаются в последовательных ячейках оперативной памяти по возрастанию адресов. В памяти компьютера элементы многомерного массива располагаются подряд, например массив, имеющий 2 строки и 3 столбца, int
a; Общее количество элементов в приведенном двумерном массиве определится как КоличествоСтрок * КоличествоСтолбцов = 2 * 3 = 6.
Количество байт памяти, требуемых для размещения массива, определится как КоличествоЭлементов * РазмерЭлемента = 6 * 4 = 24 байта.
Значения элементов многомерного массива, как и в одномерном случае, могут быть заданы константными значениями при объявлении, заключенными в фигурные скобки {}
. Однако в этом случае указание количества элементов в строках и столбцах должно быть обязательно указано в квадратных скобках . Пример на Си
1 #include
Однако чаще требуется вводить значения элементов многомерного массива в процессе выполнения программы. С этой целью удобно использовать вложенный параметрический цикл . Пример на Си
1 #define
_CRT_SECURE_NO_WARNINGS
Обработку массивов удобно организовывать с помощью специальных функций. Для обработки массива в качестве аргументов функции необходимо передать Исключение составляют функции обработки строк, в которые достаточно передать только адрес. При передаче переменные в качестве аргументов функции данные передаются как копии. Это означает, что если внутри функции произойдет изменение значения параметра, то это никак не повлияет на его значение внутри вызывающей функции. Если в функцию передается адрес переменной (или адрес массива), то все операции, выполняемые в функции с данными, находящимися в пределах видимости указанного адреса, производятся над оригиналом данных, поэтому исходный массив (или значение переменной) может быть изменено вызываемой функцией. Пример на Си
Дан массив из 10 элементов. Поменять местами наибольший и начальный элементы массива. Для операций поиска максимального элемента и обмена использовать функцию. 1 #define
_CRT_SECURE_NO_WARNINGS
Каждый элемент массива характеризуется тремя величинами:
sizeof
(int
) = 4;
sizeof
(float
) = 4;
sizeof
(double
) = 8;Объявление и инициализация массивов
2
3
4
5
6
7
8
int
main()
{
int
a = { 5, 4, 3, 2, 1 }; // массив a содержит 5 элементов
printf("%d %d %d %d %d\n"
, a, a, a, a, a);
getchar();
return
0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include
int
main()
{
int
a;
int
i;
// Ввод элементов массива
for
(i = 0; i<5; i++)
{
printf("a[%d] = "
, i);
scanf("%d"
, &a[i]);
}
// Вывод элементов массива
for
(i = 0; i<5; i++)
printf("%d "
, a[i]); // пробел в формате печати обязателен
getchar(); getchar();
return
0;
}Многомерные массивы
будет расположен в памяти следующим образом
Инициализация многомерных массивов
2
3
4
5
6
7
8
9
int
main()
{
int
a = { 1, 2, 3, 4, 5, 6 };
printf("%d %d %d\n"
, a, a, a);
getchar();
return
0;
}
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
#include
int
main()
{
int
a; // массив из 2 строк и 3 столбцов
int
i, j;
// Ввод элементов массива
for
(i = 0; i<2; i++) // цикл по строкам
{
for
(j = 0; j<3; j++) // цикл по столбцам
{
printf("a[%d][%d] = "
, i, j);
scanf("%d"
, &a[i][j]);
}
}
// Вывод элементов массива
for
(i = 0; i<2; i++) // цикл по строкам
{
for
(j = 0; j<3; j++) // цикл по столбцам
{
printf("%d "
, a[i][j]);
}
printf("\n"
); // перевод на новую строку
}
getchar(); getchar();
return
0;
}Передача массива в функцию
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
35
36
37
38
39
40
41
42
#include
// Функция обмена
void
change(int
*x, int
n)
{
// x - указатель на массив (адрес массива)
// n - размер массива
int
i;
int
max, index;
max = x;
index = 0;
// Поиск максимального элемента
for
(i = 1; i
if
(x[i]>max)
{
max = x[i];
index = i;
}
}
// Обмен
x = x;
x = max;
}
// Главная функция
int
main()
{
int
a;
int
i;
for
(i = 0; i<10; i++)
{
printf("a[%d] = "
, i);
scanf("%d"
, &a[i]);
}
change(a, 10); // вызов функции обмена
// Вывод элементов массива
for
(i = 0; i<10; i++)
printf("%d "
, a[i]);
getchar();
getchar();
return
p = p * x[i];
}
return
p;
}
// Главная функция
int
main()
{
int
a; // объявлен массив a из 5 элементов
int
i;
int
pr;
// Ввод элементов массива
for
(i = 0; i<5; i++)
{
printf("a[%d] = "
, i);
scanf("%d"
, &a[i]); // &a[i] - адрес i-го элемента массива
}
pr = func(a, 5); // вычисление произведения
printf("\n pr = %d"
, pr); // вывод произведения четных элементов
getchar(); getchar();
return
0;
}