Сколько измерений будет у следующего массива
Массив (array) является объектом с элементами расположенными в соответствие с декартовой системой координат.
Количество измерений массива называется ранг (это терминология взята из APL). Ранг является неотрицательных целым. Также каждое измерение само по себе является неотрицательным целым. Общее количество элементов в массиве является произведением размеров всех измерений.
Реализация Common Lisp’а может налагать ограничение на ранг массива, но данное ограничение не может быть менее 7. Таким образом, любая Common Lisp программа может использовать массивы с семью и менее измерениями. (Программа может получить текущее ограничение для ранга для используемой системы с помощью константы array-rank-limit.)
Допускается существование нулевого ранга. В этом случае, массив не содержит элементов, и любой доступ к элементам является ошибкой. При этом другие свойства массива использоваться могут. Если ранг равен нулю, тогда массив не имеет измерений, и их произведение приравнивается к 1 (FIXME). Таким образом массив с нулевым рангом содержит один элемент.
Элемент массива задаётся последовательностью индексов. Длина данной последовательности должна равняется рангу массива. Каждый индекс должен быть неотрицательным целым строго меньшим размеру соответствующего измерения. Также индексация массива начинается с нуля, а не с единицы, как в по умолчанию Fortran’е.
В качестве примера, предположим, что переменная foo обозначает двумерный массив с размерами измерений 3 и 5. Первый индекс может быть 0, 1 или 2, и второй индекс может быть 0, 1, 2, 3 или 4. Обращение к элементам массива может быть осуществлено с помощью функции aref, например, (aref foo 2 1) ссылается на элемент массива (2, 1). Следует отметить, что aref принимает переменное число аргументов: массив, и столько индексов, сколько измерений у массива. Массив с нулевым рангом не имеет измерений, и в таком случае aref принимает только один параметр – массив, и не принимает индексы, и возвращает одиночный элемент массива.
В целом, массивы могут быть многомерными, могут иметь общее содержимое с другими массивами. и могут динамически менять свой размер после создания (и увеличивать, и уменьшать). Одномерный массив может также иметь указатель заполнения.
Многомерные массивы хранят элементы построчно. Это значит, что внутренне многомерный массив хранится как одномерный массив с порядком элементов, соответствующим лексикографическому порядку их индексов. Это важно в двух ситуациях: (1) когда массивы с разными измерениями имеют общее содержимое, и (2) когда осуществляется доступ к очень большому массиву в виртуальной памяти. (Первая ситуация касается семантики; вторая — эффективности)
Массив, что не указывает на другой массив, не имеет указателя заполнения и не имеет динамически расширяемого размера после создания называется простым массивом. Пользователи могут декларировать то, что конкретный массив будет простым. Некоторые реализации могут обрабатывать простые массивы более эффективным способом, например, простые массивы могут храниться более компактно, чем непростые.
Когда вызывается make-array, если один или более из :adjustable, :fill-pointer и :displaced-to аргументов равен истине, тогда является ли результат простым массивом не определено. Однако если все три аргумента равны лжи, тогда результат гарантированно будет простым массивом.
2.5.1 Векторы
В Common Lisp’е одномерные массивы называется векторами, и составляют тип vector (который в свою очередь является подтипом array). Вектора и списки вместе являются последовательностями. Они отличаются тем, что любой элемент одномерного массива может быть получен за константное время, тогда как среднее время доступа к компоненту для списка линейно зависит от длины списка, с другой стороны, добавление нового элемента в начала списка занимает константное время, тогда как эта же операция для массива занимает время линейно зависящее от длины массива.
Обычный вектор (одномерный массив, который может содержать любой тип объектов, но не имеющий дополнительных атрибутов) может быть записан с помощью перечисления элементов разделённых пробелом и окружённых #( и ). Например:
#(a b c) ;Вектор из трёх элементов
#() ;Пустой вектор
#(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47)
;Вектор содержит простые числа меньшие пятидесяти
Следует отметить, что когда функция read парсит данный синтаксис, она всегда создаёт простой массив. __________________________________________
Обоснование: Многие люди рекомендовали использовать квадратные скобки для задания векторов так: [a b c] вместо #(a b c). Данная запись короче, возможно более читаема, и безусловно совпадает с культурными традициями в других областях компьютерных наук и математики. Однако, для достижения предельной полезности от пользовательских макросимволов, что расширяют возможности функции read, необходимо было оставить некоторые строковые символы для этих пользовательских целей. Опыт использования MacLisp’а показывает, что пользователи, особенно разработчики языков для использования в исследованиях искусственного интеллекта, часто хотят определять специальные значения для квадратных скобок. Таким образом Common Lisp не использует квадратных и фигурных скобок в своём синтаксисе.
Реализации могут содержать специализированные представления массивов для достижения эффективности в случаях, когда все элементы принадлежат одному определённому типу (например, числовому). Все реализации содержат специальные массивы в случаях, когда все элементы являются строковыми символами (или специализированное подмножество строковых символов). Такие одномерные массивы называются строки. Все реализации также должны содержать специализированные битовые массивы, которые принадлежат типу (array bit). Такие одномерные массивы называются битовые векторы.
2.5.2 Строки
base-string ≡ (vector base-char)
simple-base-string ≡ (simple-array base-char (*))
Реализация может поддерживать другие типы строк. Все функции Common Lisp’а взаимодействуют со строками одинаково. Однако следует отметить, вставка extended character в base string является ошибкой.
Строковый (string) тип является подтипом векторного (vector) типа.
Строка может быть записана как последовательность символов, с предшествующим и последующим символом двойной кавычки «. Любой символ « или \ в данной последовательности должен иметь предшествующий символ \.
«Foo» ;Строка из трёх символов
«» ;Пустая строка
«\»APL\\360?\» he cried.» ;Строка из двенадцати символов
«|x| = |-x|» ;Строка из десяти символов
Необходимо отметить, что символ вертикальной черты | в строке не должен быть экранирован с помощью \. Также как и любая двойная кавычка в имени символа, записанного с использованием вертикальных черт, не нуждается в экранировании. Записи с помощью двойной кавычки и вертикальной черты похожи, но используются для разных целей: двойная кавычка указывает на строку, содержащую строковые символы, тогда как вертикальная черта указывает на символ, имя которого содержит последовательность строковых символов.
Строковые символы обрамленные двойными кавычками, считываются слева направо. Индекс символа больше индекса предыдущего символа на 1. Самый левый символ строки имеет индекс 0, следующий 1, следующий 2, и т.д.
Следует отметить, что функция prin1 будет выводить на печать в данном синтаксисе любой вектор строковых символов (не только простой), но функция read при разборе данного синтаксиса будет всегда создавать простую строку.
2.5.3 Битовые векторы
Битовый вектор может быть записан в виде последовательности битов заключённых в строку с предшествующей #*; любой разделитель, например, как пробел завершает синтаксис битового вектора. Например:
#*10110 ;Пятибитный битовый вектор; нулевой бит 1
#* ;Пустой битовый вектор
Биты записанные после #*, читаются слева направо. Индекс каждого бита больше индекса предыдущего бита на 1. Индекс самого левого бита 0, следующего 1 и т.д.
Функция prin1 выводит любой битовый вектор (не только простой) в этом синтаксисе, однако функция read при разборе этого синтаксиса будет всегда создавать простой битовый вектор.
Сколько измерений будет у следующего массива
Сколько элементов имеет следующий массив?
int[,,] numbers = new int[3, 2, 3];
Массив new int[3, 2, 3] имеет 18 элементов.
Сколько измерений (размерность) имеет следующий массив?
int[,] numbers = new int[3, 3];
Массив new int[3, 3] имеет 2 измерения, то есть это двухмерный массив.
Что будет выведено на консоль в результате выполнения следующего кода:
int[][] nums = new int[3][]; nums[0] = new int[2] < 1, 2 >; nums[1] = new int[3] < 3, 4, 5 >; nums[2] = new int[5] < 6, 7, 8, 9, 10 >; Console.WriteLine(nums[3][2]);
Консоль ничего не выведет, так как программа выбросит во время выполнения исключение System.IndexOutOfRangeException, поскольку массив имеет 3 подмассива, то, чтобы обратиться к самому последнему массиву, необходимо использовать индекс 2. А индекс 3 таким образом окажется вне границ массива.
Дан следующий массив
int[][] nums = new int[3][]; nums[0] = new int[2] < 1, 2 >; nums[1] = new int[3] < 3, 4, 5 >; nums[2] = new int[5] < 6, 7, 8, 9, 10 >;
Каким образом мы можем обратиться к числу 7 в этом массиве?
- nums[7]
- nums[2, 1]
- nums[2][1]
- nums[3]
- nums[3, 3]
- nums[3][3]
Правильный ответ nums[2][1] .
Двумерные массивы
Объявление int A[n] создает в памяти одномерный массив: набор пронумерованных элементов, идущих в памяти последовательно. К каждому элементу массива можно обратиться, указав один индекс — номер этого элемента. Но можно создать и двумерный массив следующим образом: int A[n][m] . Данное объявление создает массив из n объектов, каждый из которых в свою очередь является массивом типа int [m] . Тогда A[i] , где i принимает значения от 0 до n-1 будет в свою очередь одним из n созданных обычных массивов, и обратиться к элементу с номером j в этом массиве можно через A[i][j] .
Подобные объекты (массивы массивов) также называют двумерными массивами. Двумерные массивы можно представлять в виде квадратной таблицы, в которой первый индекс элемента означает номер строки, а второй индекс – номер столбца. Например, массив A[3][4] будет состоять из 12 элементов и его можно записать в виде
A[0][0] A[0][1] A[0][2] A[0][3] A[1][0] A[1][1] A[1][2] A[1][3] A[2][0] A[2][1] A[2][2] A[2][3]
Для считывания, вывода на экран и обработки двумерных массивов необходимо использовать вложенные циклы. Первый цикл – по первому индексу (то есть по всем строкам), второй цикл – по второму индексу, то есть по всем элементам в строках (столбцам). Например, вывести на экран двумерный массив в виде таблицы, разделяя элементы в строке одним пробелом можно следующим образом:
int A[n][m]; for (int i = 0; i < n; ++i) < // Выводим на экран строку i for (int j = 0; j < m; ++j) < cout cout
А считать двумерный массив с клавиатуры можно при помощи еще более простого алгоритма (массив вводится по строкам, то есть в порядке, соответствующему первому примеру):
for (i = 0; i < n; ++i) < for (j = 0; j < m; ++j) < cin >> A[i][j]; > >
Обработка двумерного массива
Обработка двумерных массивов производится аналогичным образом. Например, если мы хотим записать в массив таблицу умножения, то есть присвоить элементу A[i][j] значение i * j , это можно сделать следующим образом при помощи вложенных циклов:
for (i = 0; i < n; ++i) < for (j = 0; j < m; ++j) < A[i][j] = i * j; >>
Рассмотрим более сложную задачу и несколько способов ее решения. Пусть дан квадратный двумерный массив int A[n][n] . Необходимо элементам, находящимся на главной диагонали проходящей из левого верхнего угла в правый нижний (то есть тем элементам A[i][j] , для которых i == j ) присвоить значение 1 , элементам, находящимся выше главной диагонали – значение 0, элементам, нахощящимся ниже главной диагонали – значение 2. То есть получить такой массив (пример для n == 4 ):
1 0 0 0 2 1 0 0 2 2 1 0 2 2 2 1
Рассмотрим несколько способов решения этой задачи. Элементы, которые лежат выше главной диагонали – это элементы A[i][j] , для которых i < j , а для элементов ниже главной диагонали i >j . Таким образом, мы можем сравнивать значения i и j и по ним определять значение A[i][j] . Получаем следующий алгоритм:
for (i = 0; i < n; ++i) < for (j = 0; j < n; ++j) < if (i < j) < A[i][j] = 0; >else if (i > j) < A[i][j] = 2; >else < A[i][j] = 1; >> >
Данный алгоритм плох, поскольку выполняет одну или две инструкции if для обработки каждого элемента. Если мы усложним алгоритм, то мы сможем обойтись вообще без условных инструкций.
Сначала заполним главную диагональ, для чего нам понадобится один цикл:
for (i = 0; i
Затем заполним значением 0 все элементы выше главной диагонали, для чего нам понадобится в каждой из строк с номером i присвоить значение элементам A[i][j] для j = i+1 , . n-1 . Здесь нам понадобятся вложенные циклы:
for (i = 0; i < n; ++i) < for (j = i + 1; j < n; ++j) < A[i][j] = 0; >>
Аналогично присваиваем значение 2 элементам A[i][j] для j = 0 , . i-1 :
for (i = 0; i < n; ++i) < for (j = 0; j < i; ++j) < A[i][j] = 2; >>
Можно также внешние циклы объединить в один и получить еще одно, более компактное решение:
for (i = 0; i < n; ++i) < // Заполняем строку с номером i for (j = 0; j < i; ++j) < A[i][j] = 2; // Сначала пишем 2 ниже диагонали >A[i][j] = 1; // После завершения предыдущего цикла i==j, пишем 1 for (++j; j < n; ++j) // Цикл начинаем с увеличения j на 1 < A[i][j] = 0; // Записываем 0 выше диагонали >>
Многомерные массивы
Можно объявлять не только двумерные массивы, но и массивы с большим количеством измерений. Например, объявление int A[n][m][l] создает трехмерный массив из n*m*l элементов. Для обращения к каждому элементу такого массива необходимо указать три индекса: A[i][j][k] , при этом 0
Передача двумерных массивов в функцию
В функцию можно передавать двумерный массив в качестве параметра, если размер этого массива фиксирован и объявлен в описании функции. То есть если заранее известен размер массива, то можно определить функцию, получающую в качестве параметра двумерный массив такого размера:
void f (int A[10][10]) < . >int main()
Проблема заключается в том, что в этом случае нельзя использовать массивы произвольного размера.
Чтобы использовать массивы произвольного размера, нам на помощь прийдут указатели. Для начала разберемся, как представлять двумерный массив в виде указателей.
Одномерный массив int A[n] это почти то же самое, что указатель на переменную типа int : int * A .
Тогда двумерный массив - это массив, каждый из элементов которого является одномерным массивом, то есть указателем на какой-то адрес целого числа в памяти. То есть двумерный массив - это массив элементов типа int * или же это указатель на переменную типа int * , то есть это переменная типа int ** .
Итак, двойной указатель можно объявить так:
int ** A;
Теперь выделим память для массива A . Если мы хотим, чтобы в массиве A было n элементов, каждый из которых является указателем на тип int , то сделаем это при помощи операции new :
A = new int * [n];
Теперь A указывает на область памяти, содержащей n элементов, каждый из которых имеет тип int * и указывает на некоторую область памяти, пока еще не выделенную. Выделим эту память - сделаем все A[i] указателями на область памяти из m элементов типа int :
for (int i = 0; i
Функцию, получающую в качестве параметра двумерный массив, можно объявлять так:
void f (int ** A, int n, int m)
Как и в случае с одномерным массивом, передаваемым как указатель, нам нужно одновременно передавать размеры массива - количество строк n и количество столбцов m .
При таком способе объявления массива и выделения памяти можно сделать так, чтобы в разных строчках массива было различное число элементов.
Форматирование чисел при выводе
Допустим, мы заполним массив таблицей умножения: A[i][j]=i*j как в примере в начале раздела. Если мы теперь попробуем вывести этот массив на экран, разделяя элементы в строке одним пробелом, то из-за того, что числа имеют различную длину столбцы таблицы окажутся неровными:
0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 0 2 4 6 8 10 12 14 16 18 0 3 6 9 12 15 18 21 24 27
Для того, чтобы получить ровные столбцы необходимо, выводить числа так, чтобы одно выводимое число имело ширину, например, ровно в 3 символа, а “лишние” позиции были бы заполнены пробелами. Тогда получится следующая таблица:
0 0 0 0 0 0 0 0 0 0 0 1 2 3 4 5 6 7 8 9 0 2 4 6 8 10 12 14 16 18 0 3 6 9 12 15 18 21 24 27
Для того, чтобы выводимое число или строка имело ровно заданную ширину, необходимо перед выводом его на экран для потока cout вызвать метод width с параметром 3 . Данный метод устанавливает ширину поля для выводимого значения. Получим следующую программу для вывода:
for(int i = 0; i < n; ++i) < for(int j = 0; j < m; ++j) < cout.width(3); cout cout
Заметим, что мы теперь не выводим пробел после каждого числа, поскольку мы добавили этот пробел к ширине выводимого поля. Функция width действует однократно, только на следующее выводимый в поток значение, поэтому ее нужно вызывать перед каждым выводом числа на экран.
Внимание! Если выводимое число или строка имеет большую длину, чем это было установлено функцией width , то это число или строка будут выведены полностью, а не будет обрезано до указанного значения. То есть предпочтительней вывести результат некрасиво, нежели неверно.
Упражнения
Общие требования к оформлению программ.
Считывание данных осуществляется функцией void Read (int **& A, int & n, int & m) . Эта функция считывает размер массива в переменные n и m , передаваемые по ссылке, выделяет память под хранение массива.
Решение задачи осуществляется функцией, получающей в качестве параметра массив (типа int ** ), его размеры, дополнительные параметры при необходимости.
Вывод массива на экран осуществляется отдельной функцией Print , получающей в качестве параметров массив и его размеры.
Типичный вид программы на примере задачи A:
void Read (int **& A, int & n) < . >void Fill (int ** A, int n) < . >void Print (int ** A, int n) < . >int main()
A: Максимум
Найдите индексы первого вхождения максимального элемента. Выведите два числа: номер строки и номер столбца, в которых стоит наибольший элемент в двумерном массиве. Если таких элементов несколько, то выводится тот, у которого меньше номер строки, а если номера строк равны то тот, у которого меньше номер столбца.
3 4
0 3 2 4
2 3 5 5
5 1 2 3
1. Объявление массива
Здесь квадратные скобки являются элементом синтаксиса, а не признаком необязательности конструкции.
Объявление массива может иметь одну из двух синтаксических форм, указанных выше. Квадратные скобки, следующие за именем, – признак того, что переменная является массивом. Константное выражение, заключенное в квадратные скобки определяет число элементов в массиве. Индексация элементов массива в языке C++ начинается с нуля. Таким образом, последний элемент массива имеет индекс на единицу меньше, чем число элементов массива.
Во второй синтаксической форме константное выражение в квадратных скобках опущено. Эта форма может быть использована, если в объявлении массива присутствует инициализатор, либо массив объявляется как формальный параметр функции, либо данное объявление является ссылкой на объявление массива где-то в другом месте программы. Однако для многомерного массива может быть опущена только первая размерность.
Многомерный массив, или массив массивов, объявляется путем задания последовательности константных выражений в квадратных скобках, следующей за именем:
[ ][ ] . ;
Каждое константное выражение определяет количество элементов в данном измерении массива, поэтому объявление двумерного массива содержит два константных выражение, трехмерного – три и т.д.
Массив может состоять из элементов любого типа, кроме типа void и функций, т.е. элементы массива могут иметь базовый, перечислимый, структурный тип, быть объединением, указателем или массивом.
2. Инициализация массивов
Как и простые переменные, массивы могут быть инициализированы при объявлении. Инициализатор для объектов составных типов (каким является массив) состоит из списка инициализаторов, разделенных запятыми и заключенных в фигурные скобки. Каждый инициализатор в списке представляет собой либо константу соответствующего типа, либо, в свою очередь, список инициализаторов. Эта конструкция используется для инициализации многомерных массивов.
Наличие списка инициализаторов в объявлении массива позволяет не указывать число элементов по его первой размерности. В этом случае количество элементов в списке инициализаторов и определяет число элементов по первой размерности массива. Тем самым определяется размер памяти, необходимой для хранения массива. Число элементов по остальным размерностям массива, кроме первой, указывать обязательно.
Если в списке инициализаторов меньше элементов, чем в массиве, то оставшиеся элементы неявно инициализируются нулевыми значениями. Если же число инициализаторов больше, чем требуется, то выдается сообщение об ошибке.
3. Работа с массивами
3.1. Доступ к элементу массива
Для доступа к конкретному элементу массива используются так называемые индексные выражения:
[ ]
Здесь квадратные скобки являются требованием синтаксисам языка, а не признаком необязательности конструкции.
Индекс массива может быть не только константой, но и выражением, которое имеет целочисленный тип, например, a [ i + 1] (здесь a должно быть именем ранее объявленного массива, а i – переменной целого типа).
Объявление массива и индексное выражение, используемое для доступа к элементу массива, имеют схожий синтаксис. Различаются они по месту в программе. Это особенно важно, когда мы определяем индекс последнего элемента массива. Как было сказано ранее, индексы элементов массива в языке C начинаются с 0, и номер последнего элемента на 1 меньше количества элементов массива. Поэтому если Вы объявили массив x из 10 элементов, Вы не можете написать индексное выражение x [10], т.к. в этом случае Вы пытаетесь обратиться к элементу с индексом 10, которого нет в Вашем массиве. Компилятор не выдаст сообщения об ошибке, но результаты работы такой программы будут непредсказуемы.
Имя массива является адресом его начала! Оно имеет тип константный указатель на . Конструкция a [ i ] эквивалентна *( a + i ) (см. лекцию 5).
Для многомерного массива надо указать соответствующее количество индексов в квадратных скобках.
3.2. Обработка массивов
Для обработки многомерного массива используется соответствующее количество циклов.
Массивы не самодостаточны в том смысле, что не гарантируется хранение информации о количестве элементов вместе с самим массивом. В большинстве реализаций С++ отсутствует проверка диапазона индексов для массивов. Таков традиционный низкоуровневый подход к массивам. Более совершенное понятие массива можно реализовать при помощи классов.
В С++ массивы тесно связаны с указателями. Имя массива можно использовать в качестве указателя на его первый элемент. Гарантируется осмысленность значения указателя на элемент, следующий за последним элементом массива. Это важно для многих алгоритмов. Но ввиду того, что такой указатель на самом деле не указывает ни на какой элемент массива, его нельзя использовать ни для чтения, ни для записи. Результат получения адреса элемента массива, предшествующего первому, не определён, и такой операции следует избегать.
Неявное преобразование массива в указатель при вызове функции приводит к потере информации о размере массива. Вызываемая функция должна каким-либо образом определить этот размер, чтобы выполнять осмысленные действия.
Это ограничение при желании можно обойти. Правда, при этом возникают другие проблемы (см. пример 3 в конце лекции).
3.3. Ввод/вывод массивов
В результате на экране мы увидим примерно следующий текст: a[1] = 4 a[2] = 15 a[3] = -2 .
3.4. Пример 1. Обработка одномерного массива
Даны три массива разной размерности. Определить в каком массиве больше сумма элементов. #include #include const int nmax = 100; int ArrayInput( int *n, double x[], char *fname); // Функция ввода массива из файла double Sum( double x[], int n); // Функция поиска суммы элементов массива void main( int argc, char *argv[]) < double a[nmax], b[nmax], c[nmax]; double sa, sb, sc, max; int na, nb, nc; setlocale(LC_ALL, "rus"); // Меняем кодировку для консольного приложения if (argc < 4) < printf("Недостаточно параметров!\n"); return ; >if (!ArrayInput(&na, a, argv[1])) return ; if (!ArrayInput(&nb, b, argv[2])) return ; if (!ArrayInput(&nc, c, argv[3])) return ; sa = Sum(a, na); sb = Sum(b, nb); sc = Sum(c, nc); max = sa; if (sb > max) max = sb; if (sc > max) max = sc; if (sa == max) printf("Массив А имеет максимальную сумму элементов: %9.3lf\n", max); if (sb == max) printf("Массив B имеет максимальную сумму элементов: %9.3lf\n", max); if (sc == max) printf("Массив C имеет максимальную сумму элементов: %9.3lf\n", max); > double Sum( double x[], int n) < double s = 0; for ( int i = 0; i < n; i++) s += x[i]; return s; >int ArrayInput( int *n, double x[], char *fname) < FILE *file; if ((file = fopen(fname, "r")) == NULL) < printf("Невозможно открыть файл '%s'\n", fname); return 0; >if (fscanf(file, "%d", n) < 1) < printf ("Ошибка чтения из файла '%s'\n", fname); fclose(file); return 0; >if (*n < 0 || *n >nmax) < printf("Кол-во эл-тов массива должно быть от 1 до %d! (файл '%s')\n", nmax, fname); return 0; >for ( int i = 0; i < *n; i++) if (fscanf(file, "%lf", &x[i]) < 1) < printf ("Ошибка чтения из файла '%s'\n", fname); fclose(file); return 0; >fclose(file); return 1; >
3.5. Пример 2. Обработка двумерного массива
Для каждой строки матрицы проверить наличие нулевых элементов.
Первый способ
Второй способ
3.6. Пример 3. Суммирование элементов матрицы
Даны две матрицы разного размера. Функция Sum находит сумму элементов матрицы, не зависимо от того, что матрицы имеют разное количество столбцов. Обратите внимание, что функция будет выдавать корректный результат, только если используются все объявленные элементы матриц. #include #include double Sum( double *x, int m, int n); void main( int argc, char *argv[]) < const int na = 4, mb = 3, nb = 5; double a[na][na], b[mb][nb]; double sa, sb; FILE *file; setlocale(LC_ALL, "rus"); if (argc < 3) < printf("Недостаточно параметров!\n"); return ; >if ((file = fopen(argv[1], "r")) == NULL) < printf("Невозможно открыть файл '%s'\n", argv[1]); return ; >for ( int i = 0; i < na; i++) for ( int j = 0; j < na; j++) if (fscanf(file, "%lf", &a[i][j]) < 1) < printf ("Ошибка чтения из файла '%s'\n", argv[1]); fclose(file); return ; >fclose(file); if ((file = fopen(argv[2], "r")) == NULL) < printf("Невозможно открыть файл '%s'\n", argv[2]); return ; >for ( int i = 0; i < mb; i++) for ( int j = 0; j < nb; j++) if (fscanf(file, "%lf", &b[i][j]) < 1) < printf ("Ошибка чтения из файла '%s'\n", argv[2]); fclose(file); return ; >fclose(file); sa = Sum(a[0], na, na); // a[0] - указатель на первую строку матрицы // (и, соответственно, на начало всей матрицы). sb = Sum( reinterpret_cast < double *>(b), mb, nb); // Преобразование без проверки с помощью reinterpret_cast. // Просто b нельзя написать - это вызовет сообщение // о невозможности преобразовать матрицу в указатель. printf("SumA = %6.2lf\nSumB = %6.2lf\n", sa, sb); > double Sum( double *x, int m, int n) < double s = 0; for ( int i = 0; i < m; i++) for ( int j = 0; j < n; j++) s += x[i * n + j]; return s; > Содержание