Как передать двумерный массив в функцию c
Подскажите, пожалуйста, можно ли передать двумерный массив в функцию без использования указателей? Мне просто интересно. Если да, то как? С одномерным массивом это проходит. И изменения вносятся.
#include using namespace std; void fillArray(int Arr[], int size) < for (int i = 0; i < size; i++) < Arr[i] = i + 1; >> void showArr(int Arr[], int size) < for (int i = 0; i < size; i++) < cout > //================================== int main()
| marenko.lilia |
| Посмотреть профиль |
| Найти ещё сообщения от marenko.lilia |
Регистрация: 31.05.2010
Сообщений: 13,964
А чем не нравятся указатели? Лень две звёздочки поставить?
Пишем void function(int **A)<> и радуемся.
Пиши пьяным, редактируй трезвым.
Справочник по алгоритмам С++ Builder
| Smitt&Wesson |
| Посмотреть профиль |
| Найти ещё сообщения от Smitt&Wesson |
Пользователь
Регистрация: 25.12.2013
Сообщений: 91
Сообщение от Smitt&Wesson
А чем не нравятся указатели? Лень две звёздочки поставить?
Пишем void function(int **A)<> и радуемся.
Всё нравится )) И указатели, и две звездочки.
Но интересно человеку! Понимаете??
И почему надо использовать указатели в этом случае, если возможно и без них мы можем обойтись?
| marenko.lilia |
| Посмотреть профиль |
| Найти ещё сообщения от marenko.lilia |
Регистрация: 22.05.2007
Сообщений: 9,518
В С++ нет понятия двумерного массива, соответственно нет никакого специального для них механизма.
Пользователь
Регистрация: 25.12.2013
Сообщений: 91
Оказывается можно!
Немного поэкспериментировала — то получатся так:
#include using namespace std; void showArr(int Arr[][10], int size) < for (int i = 0; i < size; i++) < for (int j = 0; j < size; j++) cout > void fillArray(int Arr[][10], int size) < for (int i = 0; i < size; i++) < for (int j = 0; j < size; j++) Arr[i][j] = i; >> //================================== int main()
Главное при определении функции указать количество столбцов.
Тоже мне «профессионалы» Лишь бы поумничать.
| marenko.lilia |
| Посмотреть профиль |
| Найти ещё сообщения от marenko.lilia |
Регистрация: 31.05.2010
Сообщений: 13,964
Сообщение от marenko.lilia
Оказывается можно!
Тоже мне «профессионалы» Лишь бы поумничать.
У каждого свой стиль. Я статическими массивами не пользуюсь, а динамические в функцию передаются по указателям.
Пиши пьяным, редактируй трезвым.
Справочник по алгоритмам С++ Builder
| Smitt&Wesson |
| Посмотреть профиль |
| Найти ещё сообщения от Smitt&Wesson |
Пользователь
Регистрация: 25.12.2013
Сообщений: 91
Согласна.
Мне просто интересно было разобраться можно ли так сделать, как спрашивала.
Если вас задело — не обижайтесь ) Это шутка была! По Вам то видно, что Вы дядя серьезный ))
| marenko.lilia |
| Посмотреть профиль |
| Найти ещё сообщения от marenko.lilia |
Регистрация: 31.05.2010
Сообщений: 13,964
Сообщение от marenko.lilia
Согласна.
Мне просто интересно было разобраться можно ли так сделать, как спрашивала.
Если вас задело — не обижайтесь ) Это шутка была! По Вам то видно, что Вы дядя серьезный ))
Я ещё и весёлый. Шутки понимаю .
Пиши пьяным, редактируй трезвым.
Справочник по алгоритмам С++ Builder
| Smitt&Wesson |
| Посмотреть профиль |
| Найти ещё сообщения от Smitt&Wesson |
Регистрация: 16.12.2011
Сообщений: 2,329
Сообщение от marenko.lilia
Подскажите, пожалуйста, можно ли передать двумерный массив в функцию без использования указателей?
#include using namespace std; template void fillArray(int (&Arr)[N]) < for (int i = 0; i < N; i++) Arr[i] = i + 1; >template void showArr(const int (&Arr)[N]) < for (int i = 0; i < N; i++) cout //================================== int main()
Обратите внимание: размер сишного массива известен времени компиляции, поэтому передавать его размер в качестве аргумента функции не нужно.
Компилятор вычислит размер массива автоматически.
Сообщение от Smitt&Wesson
У каждого свой стиль. Я статическими массивами не пользуюсь, а динамические в функцию передаются по указателям.
На языке с++ не существует динамических массивов.
Последний раз редактировалось Stilet; 02.09.2014 в 19:35 .
Регистрация: 16.12.2011
Сообщений: 2,329
Сообщение от marenko.lilia
Оказывается можно!
void showArr(int Arr[][10], int size)
Вы ошиблись: в данном случае вы передали указатель.
Пусть вас не смущает отсутствие звездочки - это наследие языка си.
На языке си для массивов существует альтернативный синтаксис для аргументов функций являющихся массивами.
Вообще, у вас есть три способа передать данные в функцию:
1. По значению. В функцию передается копия аргумента.
2. По указателю. В функцию передается указатель, который инициализирован адресом аргумента.
3. По ссылке. В функцию передается ссылка аргумента.
Поскольку массив нельзя передать по значению - у него нет конструктора копии, то остается передавать либо по ссылке, либо по указателю.
На языке си нет ссылок, только указатели.
Поэтому единственный способ для языка си обеспечить данный синтаксис - передача по указателю.
#include #include using namespace std; void showArr(int Arr[][10], int size) < cout::value int main()
Резюмируя: если хотите передать массив в функцию не через указатель, то передавайте по ссылке.
23.2. Передача двумерных массивов в функции
Вместо одномерного массива функции передается указатель на его первый элемент. Точно так же не передается функции и двумерный массив. Массив массивов (т.е. двумерный массив в языке С) при передаче в функцию превращается в указатель на массив, а не в указатель на указатель. В функцию передается указатель на массив, число элементов которого равно длине строки двумерного массива.
Следующее описание является неверным:
Если в функцию передается двумерный массив:
описание функции должно соответствовать
Скобки (*pmas) в объявлении обязательны, т.к. int *pmas[M] – это массив указателей на int, а не указатель на массив.
Обратить внимание! Так как функция не выделяет место для массива, нет необходимости знать его точный размер. Поэтому количество строк N может быть опущено. В то же время количество элементов в строке (количество столбцов M) опускать нельзя, т.к. «форма» массива (количество столбцов) используется для вычисления смещения элемента относительно начала массива. Поэтому количество столбцов (вторую размерность M) надо указывать обязательно.
Задача. Разработать функции для печати массива из 10 столбцов и замены знака у всех элементов массива с 5-ю столбцами.
void print10(int mas[][10], int n)
void negative5(int (*mas)[5], int n, int m)
Обратить внимание! У двумерных (многомерных) массивов есть один неприятный недостаток при передаче их в функцию – для обработки массива с пятью столбцами нужно писать одну функцию, а для массива с десятью столбцами – другую!
При передаче функции двумерного массива как фактического параметра необходимо обязательно указывать количество столбцов. Однако, если работа с двумерным массивом не требует доступа к элементам посредством конкретного указания строк и столбцов, то функция может воспринимать многомерный массив как одномерный, хотя в качестве фактического параметра ей передается многомерный массив.
long sum(int m[], int n)
printf("Сумма массива a = %d\n", sum(a, 10));
printf("Сумма массива b = %d\n", sum((int *)b, 20));
printf("Сумма массива c = %d\n", sum((int *)c, 30));
Функция sum() работает с двумерными массивами так же, как и с одномерными массивами. Так работать с двумерным массивом позволяет способ хранения в памяти многомерных массивов в языке С. Правда, есть одно ограничение – реальное количество элементов в строке такого массива должно строго совпадать со второй размерностью массива, а вот количество строк в таком массиве может быть любым.
Функции в C++ для начинающих Передача в функцию двумерного динамического массива
Иногда возникает вопрос по работе массивов и функций. Многие испытывают проблемы при создании двумерного динамического массива для последующей его обработки с помощью функций. Найти информацию решения таких задач на момент написания статьи не так уж и просто. Да, описаны варианты создания, но лично я находил или простое создание двумерного динамического массива внутри main () или выделение памяти для массива непосредственно внутри принимающей его функции. Мне это очень не нравилось
Код С++ Создание динамического двумерного массива и обработка его с помощью функций
// Отображение массива
void ArrayShow (int ** A ,int N ,int M )
cout
for (int i = 0 ; i < N ; i ++)
for (int j = 0 ; j < M ; j ++)
if (!( j % M )) cout //Чтобы массив выглядел как массив
cout //Табуляция символов
// Инициализация массива случайными значениями
void ArrayInit (int ** A ,int N ,int M )
srand ( time ( 0 ));
for (int i = 0 ; i < N ; i ++)
for (int j = 0 ; j < M ; j ++)
A [ i ][ j ]= rand ()%( 100 )- 50 ; //Случайное значение в очередную ячейку массива
void main ()
clrscr ();
int ** A ; //Для создания двумерного массива удобен указатель на указатель
int N , M ; //Число колонок=N, Число строк= M
cin >> N >> M ; //Ввели размерность массива
// for ( int k=0; k<10;k++) Может кому нужно циклом
/* Создание динамического двумерного массива */
A =new int*[ N ];
for (int i = 0 ; i < N ; i ++) A [ i ]=new int[ M ];
ArrayInit ( A , N , M ); //Функция создания массива
ArrayShow ( A , N , M ); //Функция обработки массива
/*Очистка памяти от созданного двумерного массива*/
for ( i = 0 ; i < N ; i ++) delete [] A [ i ];
delete [] A ;
A = NULL ;
//> окончание цикла for
getch ();
return;
Не могу сильно и всё комментировать, потому что не обладаю глубокими знаниями. Это немного переделанный пример того, что я находил по передаче двумерного массива в функцию. По мне такие примеры, где массив создается непосредственно внутри функции или для него выделяется память внутри принимающей его функции не есть грамотное решение вопроса темы, поэтому пришлось переделывать на свой лад
Для того чтобы создать двумерный динамический массив, был использован указатель на указатель. Для решения обычных задач необязательно вникать в суть указателя и достаточно посмотреть, как указатели тут используются. Вообще что такое указатели, зачем они нужны, их недостатки и их преимущества любой уважающий себя программист наверняка знает, а, значит, если решили научиться программировать, то тоже должны изучить.
При написании приведенной программы, ячейки для двумерного массива были динамически созданы внутри функции main () Сразу же был дописан код очистки памяти от создаваемого массива. Если написать не сразу, то потом легко запутаться или забыть. Очистка памяти нужна только и только тогда когда массив больше не нужен . Между кусками кода выделения памяти под двумерный массив и очистки от него памяти был написан вызов двух функций. Первая функция принимает двумерный массив в качестве аргумента. Благодаря тому, что принимаемый параметр является указателем, то любые изменения массива внутри функции, влияют на этот массив вне функции напрямую (Передали на обработку -> Получили обновленный) . Нужно заполнить массив значениями. Чтобы заполнить массив значениями, нужно знать его размерность. Чтобы функция занесения данных в двумерный динамический массив знала размерность, туда были переданы эти данные. Осталось только использовать ввод данных с помощью циклов. Не думаю, что по этим циклам должны возникнуть вопросы. Функция маленькая и удобочитаемая. Главное понимать, что
Передавая двумерный массив, в функции можно принять указатель на указатель массива и указать число строк и колонок внутри массива .
Следующая функция принимает динамический массив как обычный двумерный. Чтобы массив принялся в таком виде, в котором был только что создан, обязательно принимающую его функцию вызывать до очистки памяти от нужного массива. По принимаемым параметрам эта функция похожа на ту, которая создавала двумерный массив. Используется указатель на указатель, и указываются данные размерности. Чтобы массив был не в одну строчку, была произведена проверка деления числа нацело. Если кто-то использует другие способы приведения массива к хорошему виду, то легко можно использовать удобные ему. Чтобы элементы массива не слились воедино, был использован элемент табуляции.
В качестве эксперимента была попытка реализовать создание динамического двумерного массива внутри цикла, потом передать этот массив в функции. Этот момент комментирован, но может оказаться кому-то полезным.
Главное четко осознавать
- если выделили память, то обязательно нужно её удалять.
- Удалять память нужно только и только тогда, когда динамически созданный массив больше реально не нужен
- Для передачи двумерного динамического массива в функцию удобно использовать указатель на указатель и при передаче его в функцию, в функцию стоит передавать размерность массива
Передать двумерный статический массив в функцию
То есть передать можно, используя различные ухищрения, но скорей всего функция не будет работать так, как вы предполагаете.
Есть такой универсальный подход. Это интерпретировать любой двумерный массив, как одномерный, и передавать значения размеров каждой размерности массива.
void f( int a[], size_t m, size_t n ); //. int A[3][4]; f( reinterpret_cast( A ), 3, 4 );
Вот демонстрационная программа
#include #include void f( int a[], size_t m, size_t n ) < for ( size_t i = 0; i < m; i++ ) < for ( size_t j = 0; j < n; j++ ) a[i * n + j ] = i * n + j; >> int main() < const size_t M = 3; const size_t N = 4; int a[M][N]; f( reinterpret_cast( a ), M, N ); for ( size_t i = 0; i < M; i++ ) < for ( size_t j = 0; j < N; j++ ) std::cout return 0; >
Ее вывод на консоль
0 1 2 3 4 5 6 7 8 9 10 11
Если же писать программу на C, а не на C++, то там есть массивы переменной длины, и поэтому вам было бы проще.
В C++ для этих целей лучше использовать стандартный класс std::vector
std::vector> v( 3, std::vector( 4 ) );
Что касается вашего вопроса
2)Статические 2D массивы хранятся в памяти линейно. Динамические хранятся тоже линейно или нет?
то если вы будете распределять его в памяти как двумерный массив, то естественно его элементы будут храниться линейно по строкам. Например
int ( *a )[4] = new int[3][4];
А что касается этого вопроса
3)Какую связь имеет статический 2D массив с указателями?
то любой массив в выражениях (за редким исключением) неявно преобразуется в указатель на свой первый элемент.
Отслеживать
ответ дан 6 ноя 2015 в 19:03
Vlad from Moscow Vlad from Moscow
44.8k 3 3 золотых знака 38 38 серебряных знаков 89 89 бронзовых знаков
А как сделать эту функцию универсальнее, чтобы она принимала любые A[x][y] ?
6 ноя 2015 в 19:08
@neko69 Что значит "любые"? Если любые двумерные массивы с любыми значениями размерностей, то сделайте ее шаблонной.
6 ноя 2015 в 19:10
Шаблонная, в смысле template
6 ноя 2015 в 19:12
@neko69 Если вы хотите иметь дело именно с двумерными массивами, то без этого не обойтись.
6 ноя 2015 в 19:13
@neko69 Смотрите мой обновленный ответ.
6 ноя 2015 в 19:17
В gcc сделать это совсем просто.
Вы можете передавать в функцию размерности матрицы (достаточно только "низших") и обращаться к элементам по индексам естестственным образом. Например:
void func (int n_lines, int n_columns, int array[][n_columns])
К сожалению g++ (и c++) не поддерживает такую передачу матриц в функцию. Поэтому проще всего (обладая знанием, что все элементы матрицы располагаются в памяти последовательно, сначала первая строка, за ней вторая и т.д.) передать в функцию адрес первого элемента матрицы, а в функции рассматривать ее как одномерный массив.
Естественно, пересчитывать индексы придется самому.
Вот пример файла, в котором представлены обе версии программы и результаты его запуска:
avp@avp-ubu1:hashcode$ cat c1.c #include #ifdef __cplusplus #include #endif static int aa[4][3] = < , , , >; #ifdef __cplusplus void func_matrix (int n, int m, int *x) < x[0] = x[(n - 1) * m + m - 1]; for (int i = 0; i < n; i++) for (int j = 0; j < m || !puts(""); j++) std::cout #else void func_matrix (int n, int m, int x[n][m]) < int i, j; x[0][0] = x[n - 1][m - 1]; for (i = 0; i < n; i++) for (j = 0; j < m || !puts(""); j++) printf("%d ", x[i][j]); >#endif int main (int ac, char *av[]) < #ifdef __cplusplus func_matrix(4, 3, &aa[0][0]); #else func_matrix(4, 3, aa); #endif >avp@avp-ubu1:hashcode$ gcc c1.c && ./a.out 43 12 13 21 22 23 31 32 33 41 42 43 avp@avp-ubu1:hashcode$ g++ c1.c && ./a.out 43 12 13 21 22 23 31 32 33 41 42 43 avp@avp-ubu1:hashcode$
Если вопросы еще остались, задавайте.
UPD
Вот вариант с указателями на строки "плотной" матрицы.
Берем статическую матрицу, делаем для нее массив указателей, передаем его в функцию транспонирования, которая делает в динамической памяти "плотную" транспонированную матрицу и возвращает новый массив указателей на ее строки.
#include #include int ** make_lines_ptrs (int *mx, int a, int b) < int **p = (int **)malloc(a * sizeof(int *)); for (int i = 0; i < a; i++) p[i] = mx + i * b; return p; >int ** transp (const int * const * m, int a, int b) < int *mx = (int *)malloc(a * b * sizeof(int)); for (int i = 0; i < a; i++) for (int j = 0; j < b; j++) mx[j * a + i] = m[i][j]; return make_lines_ptrs(mx, b, a); >void pri_mx (const int * const * m, int a, int b) < for (int i = 0; i < a; i++) for (int j = 0; j < b || !puts(""); j++) printf("%d ", m[i][j]); >static int aa[4][3] = < , , , >; int main (int ac, char *av[])
Ну, память перед выходом Вы уж сами освободите?