Как передать матрицу в функцию c
Перейти к содержимому

Как передать матрицу в функцию c

  • автор:

Как передать матрицу в функцию c

Регистрация: 05.02.2022

Сообщений: 1

Как корректно передать матрицу в функцию через указатель?

Здравствуйте. Мне нужно написать программу на языке си, которая получает с клавиатуры от пользователя двумерный массив. Пользователь задаёт размеры и заполняет элементы. Затем некая функция производит с ним какие-то действия и результат выводится на экран. При этом всём требуются отдельные функции для ввода, вычисления и вывода. Программа работает в консоли. Ввод и вывод, если больше не писать функций, произвести получается, но после появляется ошибка ./bus error, обращение к несуществующей памяти, как я понимаю. Пытаюсь сделать функцию с циклом по подобию вывода, она делает чёрти что. Мне кажется, я путаюсь в указателях. Вот мой код:

 #include #include void input(int ***matrix, int *n, int *m); void output(int ***matrix, int n, int m); void main() < int **matrix, **result; int n, m; input(&matrix, &n, &m); output(&matrix, n, m); >void input(int ***matrix, int *n, int *m) < int i, j; scanf("%d", n); scanf("%d", n); *matrix = (int**)malloc((*n)*sizeof(int*)); for (i = 0; i < *m; i++) matrix[i] = (int**)malloc((*m) * sizeof(int)); for ( i = 0; i < *n; ++i ) for ( j = 0; j < *m; ++j ) scanf("%d", &matrix[ i ][ j ]); >void output(int ***matrix, int n, int m) < int i, j; for (i = 0; i < n; i++) < for (j = 0; j < m; j++) printf("%d ", matrix[i][j]); printf("\n"); >>

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

Как передать матрицу в функцию c

Скачай курс
в приложении

Перейти в приложение
Открыть мобильную версию сайта

© 2013 — 2024. Stepik

Наши условия использования и конфиденциальности

Get it on Google Play

Public user contributions licensed under cc-wiki license with attribution required

Как передать матрицу в функцию c

БлогNot. C++: как передать в функцию статическую и динамическую матрицу одним и тем же ко.

C++: как передать в функцию статическую и динамическую матрицу одним и тем же кодом?

Возможно, мы могли бы сделать такое в «чистом» C (из-за иного кастинга типов), но не в C++. Функция в наших примерах пусть занимается просто выводом матрицы в консоль.

Вариант 1 — применяем указатели вида тип **матрица . Удобно для динамических матриц, но не для статических.

Обратите внимание на закомментированную строчку

print_matrix(n,m, (double **)&a[0][0]);

в листинге. Явное приведение типа вида (double **)&a[0][0] откомпилируется, но создаст ошибку времени исполнения.

#include #include #include using namespace std; void print_matrix(int n, int m, double** a) < cout.precision(3); cout cout > int main() < const int n = 3, m = 3; //Создаём и выводим статическую матрицу функцией print_matrix double a[n][m] = < , , >; //print_matrix(n,m, (double **)&a[0][0]); //откомпилируется, но даст неопределённое поведение в C++! double** a_ptr = new double* [n]; for (int i = 0; i < n; i++) a_ptr[i] = &a[i][0]; print_matrix(n, m, a_ptr); //а вот так - пожалуйста //Создаём и выводим динамическую матрицу функцией print_matrix double** b = new double *[n]; if (!b) exit(1); for (int i = 0; i < n; i++) < b[i] = new double[m]; if (!b[i]) exit(1); for (int j = 0; j < m; j++) b[i][j] = i + j; >print_matrix(n, m, b); cin.get(); return 0; >

Вариант 2. Использовать шаблоны, если ваши массивы — статические, и вы хотите одним кодом печатать матрицы разных размерностей.

Но в этом случае так просто не напечатать динамическую матрицу.

#include #include #include using namespace std; template //применяем шаблон void print_matrix(double(&a)[n][m]) < cout.precision(3); cout cout > int main() < const int n = 3, m = 3; double a[n][m] = < , , >; print_matrix(a); //Выводим статическую матрицу 3 x 3 double c[2][2] = < , >; print_matrix(c); //И матрицу 2 x 2 тем же кодом cin.get(); return 0; >

Попытаться «помучить» так динамическую матрицу можно, но работать это не будет.

Например, добавим перед cin.get(); такой код:

double** b = new double* [n]; if (!b) exit(1); for (int i = 0; i < n; i++) < b[i] = new double[m]; if (!b[i]) exit(1); for (int j = 0; j < m; j++) b[i][j] = i + j; >double *b_ptr[n]; for (int i = 0; i < n; i++) b_ptr[i] = &b[i][0]; print_matrix ((double(&)[n][m])b_ptr); //Также откомпилируется, но работать правильно не будет

Можно передать в функцию и

reinterpret_cast (b_ptr[0][0])

- тоже не поможет 🙂

Дело в том, что типизированность C++ никто не отменял и массив указателей - не то же самое, что массив массивов.

double m[3][4] < , , >;

компилятор, фактически, создаёт массив массивов. Да, в памяти это будет

double _m[] = ;

но, благодаря типизированности языка, компилятор запоминает, что тип m - это double[3][4] . В частности, фиксируются размеры 3 и 4 .

Когда Вы пишете m[i][j] , компилятор заменяет это на _m[i * 4 + j] ( 4 берётся из второй размерности в double[3][4] ). Например, m[1][2] == 1 и _m[1 * 4 + 2] == _m[6] == 1 .

Двойной указатель ** - это другой тип, который не несёт информации о размерностях. Чтобы рассматривать double **a как матрицу a[3][4] , a[0] , a[1] и a[2] нужно сделать указателями на double (то есть, они будут иметь тип double * ), указывающими на первый элемент соответствующей строки.

Вы можете добиться этого, например, с помощью кода

double* rows[] = < &m[0][0], &m[1][0], &m[2][0] >; double** a = &rows[0];

Простое приведение типа не создаст этих указателей.

Ну и "безразмерного" типа [][] тоже не существует, хотя можно фиксировать вторую размерность и создать указатель на будущие строки матрицы одинакового размера:

double* e[n]; for (int i = 0; i < n; i++) e[i] = &a[i][0]; print_matrix(n, m, e); //печатаем матрицу a for (int i = 0; i < n; i++) e[i] = &b[i][0]; print_matrix(n, m, e); //а теперь матрицу b

(добавить в вариант 1 кода перед cin.get() ).

Вариант 3. Оптимальное, на мой взгляд, решение - эмулируем матрицу через одномерный массив.

#include #include #include using namespace std; void print_matrix (size_t n, size_t m, double *a) < cout.precision(3); cout cout > int main() < const int n = 3, m = 3; double a[n * m] = < 1,2,3, 4,5,6, 7,8,9 >; print_matrix(n,m,&a[0]); //печать статической матрицы 3 x 3 double c[2 * 2] = < 1,2, 3,4 >; print_matrix(2,2,c); //печать статической матрицы 2 x 2 double * b = new double [n * m]; if (!b) exit(1); for (int i = 0; i < n; i++) < for (int j = 0; j < m; j++) b[i * m + j] = i + j; >print_matrix (n, m, b); //печать динамической матрицы 3 x 3 double d[4] = < 1,2,3,4 >; print_matrix(4, 1, d); //напечатает "вектор-столбец" print_matrix(1, 4, d); //напечатает "вектор-строку" cin.get(); return 0; >

Теперь функция работает одинаково для статики и динамики плюс может работать и с "просто одномерными" массивами, такими как d .

Если не хочется каждый раз вычислять a[i * m + j] вместо a[i] [j], можно обернуть код в класс и переопределить в этом классе оператор [][].

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

#include #include #include using namespace std; template void print_matrix(size_t n, size_t m, T* a) < cout.precision(3); cout cout > int main() < const int n = 3, m = 3; double a[n * m] = < 1.5,2,3, 4,5,6, 7,8,9 >; print_matrix(n, m, &a[0]); //печать вещественной матрицы 3 x 3 int c[2 * 2] = < 1,2, 3,4 >; print_matrix(2, 2, c); //печать целочисленной матрицы 2 x 2 unsigned char* b = new unsigned char[n * m]; if (!b) exit(1); for (int i = 0; i < n; i++) < for (int j = 0; j < m; j++) b[i * m + j] = 'A' + i + j; >print_matrix(n, m, b); //печать динамической матрицы char 3 x 3 cin.get(); return 0; >

Все коды из заметки проверялись в консолях актуальных сборок Visual Studio 2019 и QT 5.X.

26.03.2021, 13:04 [3503 просмотра]

14 Лекция. Передача двумерного массива в качестве параметра функции (продолжение). Двумерные массивы в куче (обобщение).

Передача двумерного массива в качестве параметра функции (продолжение).

В предыдущих примерах основной недостаток - наличие глобальных переменных.

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

Если убрать количество строк n_g компиляция программы пройдет успешно.

Пример: Передача двумерного массива в качестве параметра функции (в двух файлах).

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#include #include #include "sum_array.h" int main ()  static int n=2, m=3; int sum_a; int array[n_g][m_g] = 1,4,5,3>,4,5,6,7>>; sum_a = sum_array(array,n,m); sum_a = sum_array(array,n_g,m_g); srand((unsigned)time(NULL)); for (int i=0; in; i++)  for (int j=0; jm; j++)  array[i][j]=1+rand()%8; > > sum_a = sum_array(array,n,m); sum_a = sum_array(array,n_g,m_g); > 

Пример: Файл (sum_array.h) с функцией "sum_array".

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
const int n_g =3; const int m_g =4; int sum_array (int array[][m_g], int n, int m)  int sum =0; for (int i=0; in; i++)  for (int j=0; jm; j++)  sum = sum + array[i][j]; std::cout  [i][j]  <" "; > std::cout  <"\n"; > std::cout  <"Сумма элементов массива sum color: #000080;">  <"\n"; return sum; >

Если убрать количество элементов в строке m_g, произойдет ошибка компиляции.

Т.к. строка является элементов одномерного массива, а размер элемента массива должен быть известен.

  1. замена многомерного массива одномерным и имитация внутри функции доступа к двумерному массиву,
  2. использование одномерного массива указателей на одномерные массивы (строки).

Пример: Передача двумерного массива в качестве параметра функции (в двух файлах).

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#include #include #include "sum_array.h" int main ()  const int n=3, m=4; int sum_a; int array[n][m] = 1,4,5,3>,4,5,6,7>>; int *p[n]; for (int i=0; in; i++)  p[i] = array[i]; > sum_a = sum_array(p,n,m); srand((unsigned)time(NULL)); for (int i=0; in; i++)  for (int j=0; jm; j++)  array[i][j]=1+rand()%8; > > sum_a = sum_array(p,n,m); > 

Пример: Файл (sum_array.h) с функцией "sum_array".

1 2 3 4 5 6 7 8 9 10 11 12 13
int sum_array (int **mas, int n, int m)  int sum =0; for (int i=0; in; i++)  for (int j=0; jm; j++)  sum = sum + mas[i][j]; std::cout  [i][j]  <" "; > std::cout  <"\n"; > std::cout  <"Сумма элементов массива sum color: #000080;">  <"\n"; return sum; >

Т.к. нет необходимости передавать двумерный массив, передаем только указатель на одномерный массив, можно избавиться от глобальных переменных.

Двумерные массивы в куче (обобщение)

Создадим стандартные функции для работы с массивами в куче:

mem_new - выделение памяти в куче для массива
mem_del - освобождение памяти в куче для массива
add_array - заполнение массива
out_array - вывод массива

Пример: Файл (mem_new.h) с функцией "mem_new".

1 2 3 4 5 6 7 8 9
//Функция выделения памяти в куче для двухмерного массива void mem_new (int **&p, int n)  p = new int *[n]; for (int i=0; in; i++)  p[i] = new int [n]; > >

Пример: Файл (mem_del.h) с функцией "mem_del".

1 2 3 4 5 6 7 8 9
// Функция освобождения памяти void mem_del(int **p, int n)  for (int i=0;in; i++) delete [] p[i]; > delete [] p; >

Пример: Файл (add_array.h) с функцией "add_array".

1 2 3 4 5 6 7 8 9 10
// Функция заполнения массива случайными числами void add_array(int **p, int n)  srand((unsigned)time(NULL)); for (int i=0; in; i++)  for (int j=0; jn; j++)  p[i][j] = 1 + rand()%9; > > >

Пример: Файл (out_ar)(color: #0000ff;(color: #800080;ray.h) с функцией "out_array".

1 2 3 4 5 6 7 8 9 10 11
//Функция вывода матрицы на консоль void out_array(int **p, int n)  for (int i=0; in; i++)  for (int j=0; jn; j++)  std::cout [i][j] <" "; > std::cout  <"\n"; > >

Пример: Файл (main.cpp) с функцией "main".

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#include #include #include #include "mem_new.h" #include "mem_del.h" #include "add_array.h" #include "out_array.h" int main ()  int n; std::cout  <"Введите размер матрици color: #008080;">; std::cin >> n; int **p; mem_new(p,n); add_array(p,n); out_array(p,n); mem_del(p,n); >

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *