Двумерные массивы в 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 int main () { const int n=4; int data = { 5,4,3,2, 11,-1,2,7, 0,1,0,4, -13,79,1,2 }; int i,j,k=0; double **a = new double * [n]; for (i=0; i

Внимание! Об обновлениях смотри внизу этой страницы. Последнее обновление – от 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;
sizeof (int ) = 4;
sizeof (float ) = 4;
sizeof (double ) = 8;

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

Для объявления массива в языке Си используется следующий синтаксис:

тип имя[размерность]={инициализация};

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

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
2
3
4
5
6
7
8

#include
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;
}

Результат выполнения программы:

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

int a;

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

1
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;
}

Результат выполнения программы

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

В языке Си могут быть также объявлены многомерные массивы. Отличие многомерного массива от одномерного состоит в том, что в одномерном массиве положение элемента определяется одним индексом, а в многомерном - несколькими. Примером многомерного массива является матрица.

Общая форма объявления многомерного массива

тип имя[размерность1][размерность2]...[размерностьm];

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

int a;


будет расположен в памяти следующим образом

Общее количество элементов в приведенном двумерном массиве определится как

КоличествоСтрок * КоличествоСтолбцов = 2 * 3 = 6.

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

КоличествоЭлементов * РазмерЭлемента = 6 * 4 = 24 байта.

Инициализация многомерных массивов

Значения элементов многомерного массива, как и в одномерном случае, могут быть заданы константными значениями при объявлении, заключенными в фигурные скобки {} . Однако в этом случае указание количества элементов в строках и столбцах должно быть обязательно указано в квадратных скобках .

Пример на Си

1
2
3
4
5
6
7
8
9

#include
int main()
{
int a = { 1, 2, 3, 4, 5, 6 };
printf("%d %d %d\n" , a, a, a);
getchar();
return 0;
}



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

Пример на Си

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

#define _CRT_SECURE_NO_WARNINGS
#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;
}



Передача массива в функцию

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

  • адрес массива,
  • размер массива.

Исключение составляют функции обработки строк, в которые достаточно передать только адрес.

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

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

Пример на Си Дан массив из 10 элементов. Поменять местами наибольший и начальный элементы массива. Для операций поиска максимального элемента и обмена использовать функцию.

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
35
36
37
38
39
40
41
42

#define _CRT_SECURE_NO_WARNINGS
#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;
}