Перейти к содержимому

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

  • автор:

Динамические двумерные массивы

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

Рассмотрим одномерный массив из 10 указателей на объекты типа int:

A представляет собой указатель на указатель на int.

Кроме того, массив указателей может быть не статическим, а динамическим:

Следующий шаг сделать очень просто — по указателям, хранящимся в массиве A могут лежать не по одному значению, а по одномерному динамическому массиву таких значений.

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

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

Пример работы с динамическим двумерным массивом

#include
#include

#define MATRIX_HEIGHT 4
#define MATRIX_WIDTH 5

void dynamic_array_print(int **A, size_t N, size_t M)
for(int i = 0; i < N; i++) for(int j = 0; j < M; j++) printf("%*d", 5, A[i][j]);
>
printf(«\n»);
>
>

/*
return pointer on 2d dynamic array
!allocates memory -> to be freed later
*/
int ** dynamic_array_alloc(size_t N, size_t M)
int **A = (int **)malloc(N*sizeof(int *));
for(int i = 0; i < N; i++) A[i] = (int *)malloc(M*sizeof(int));
>
return A;
>

void dynamic_array_free(int **A, size_t N)
for(int i = 0; i < N; i++) free(A[i]);
>
free(A);
>

void dynamic_array_test(size_t N, size_t M)
int **A = dynamic_array_alloc(N, M);
int x = 1;
for(int i = 0; i < N; i++) for(int j = 0; j < M; j++) A[i][j] = x;
x += 1;
>
>
dynamic_array_print(A, N, M);
/*memory investigation*/
printf(«\n Pointers to lines: «);
for(int **p = A; p < A + 3; p++)
printf(«%10d», (long int)*p);
printf(«\n Direct memory access (dangerous. ):\n»);
for(int *p = (int*)*A; p < (int*)*A + 25; p++)
printf(«%d\t», *p);
dynamic_array_free(A, N);
>

int main()
dynamic_array_test(MATRIX_HEIGHT, MATRIX_WIDTH);
return 0;
>

Выделение памяти под динамический массив

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

int **A = (int **)malloc(N*sizeof(int *));
for(int i = 0; i < N; i++) A[i] = (int *)malloc(M*sizeof(int));
>

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

Правильное очищение таково:

for(int i = 0; i < N; i++) <
free(A[i]);
>
free(A);

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

int ** A = malloc(n*sizeof(int*) + n*m*sizeof(int));
char * pc = A;
pc += n*sizeof(int*);
for (int i=0; i A[i] = pc + i*sizeof(m*sizeof(int));

Тогда освобождение памяти будет происходить очень легко:

Передача динамического массива в функцию через указатель

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

Отслеживать
11.5k 8 8 золотых знаков 42 42 серебряных знака 69 69 бронзовых знаков
задан 4 ноя 2017 в 17:18
47 1 1 золотой знак 1 1 серебряный знак 3 3 бронзовых знака

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Вас интересует это?

int func(int * arr, int n) < . >. int * array = new int[20]; func(array,20); 

Если нет — сформулируйте свой вопрос поточнее.

Отслеживать
ответ дан 4 ноя 2017 в 17:21
219k 15 15 золотых знаков 119 119 серебряных знаков 230 230 бронзовых знаков

Когда говорят про передачу массива в виде указателя, на самом деле подразумевают передачу пары «указатель на первый элемент массива — количество элементов массива»:

int func(int* base, size_t count) < // . >

Доступ же к элементам производится, как и в случае обычных массивов, через индексацию (при этом мы притворяемся, что указатель base — это и есть сам массив):

int item = base[i]; 

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

Теперь о том, почему мы передаём количество элементов (параметр count ). Дело в том, что пока мы работаем с переменной-массивом, компилятор знает его размер и может в любой момент предоставить его нам (через sizeof(array) / sizeof(array[0]) ). Однако, как только мы начинаем работать с указателями, всякая информация о массиве теряется, а потому мы должны передавать её явно, вместе с указателем. При создании же динамического массива мы сразу же получаем указатель, а потому вынуждены хранить и передавать количество его элементов явно.

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

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

Добрый день! пытаюсь разобраться что лучше и как передавать ?
например у меня есть вот такой код : — в нем я передаю массив одномерный по ссылке ?
как правильно передать его по указателю ? я столкнулся при передачи по указателю что не понимаю где и что нужно разыменовывать например в этом кусочке кода !
следующий вопрос как передать тогда двумерный массив по ссылке и по указателю и как к ним обращаться ?

for (int i = 0; i < N; i++) < for (int j = N - 1; j >i; j--) < if (mass[j - 1] >mass[j]) < T3 temp = mass[j]; mass[j] = mass[j - 1]; mass[j - 1] = temp;
template void Bubble( T4 &mass,T3 N) < for ( int i =0;ifor (int i = 0; i < N; i++) < for (int j = N - 1; j >i; j--) < if (mass[j - 1] >mass[j]) < T3 temp = mass[j]; mass[j] = mass[j - 1]; mass[j - 1] = temp; >> > > int main()< int n; int m; cout>n; cout>m; cout cout return 0; >
  • Вопрос задан более трёх лет назад
  • 4594 просмотра

Комментировать
Решения вопроса 1
̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻̻

Зачем усложнять? Динамический массив, как у тебя - это указатель на массив указателей, вот его и передавай. А лучше всего конечно vector.

#include #include const size_t SIZE = 10; // const нужен для защиты данных от модификации template void print1DArray(const T* array, const size_t size) < for (size_t i = 0; i < size; ++i) < std::cout std::cout template void print2DArray(const T* const* array, const size_t rows, const size_t columns) < for (size_t y = 0; y < rows; ++y) < for (size_t x = 0; x < columns; ++x) < std::cout std::cout std::cout template void printVector(const std::vector& vector) < for (const auto& item : vector) < std::cout std::cout int main() < int* array1D = new int[SIZE]; array1D[0] = 99; array1D[1] = 55; print1DArray(array1D, SIZE); delete[] array1D; int** array2D = new int*[SIZE]; for (size_t i = 0; i < SIZE; ++i) < array2D[i] = new int[SIZE * 2]; for (size_t j = 0; j < SIZE * 2; ++j) < array2D[i][j] = i + j; >> print2DArray(array2D, SIZE, SIZE * 2); for (size_t i = 0; i < SIZE; ++i) < delete[] array2D[i]; >delete[] array2D; std::vector vector(SIZE, 14); printVector(vector); return 0; >

Ответ написан более трёх лет назад
Vadim kyklaed @kyklaed Автор вопроса

так вот например я передаю
int *mass = new int [n]; - указатель на массив указателей
передача в функцию не по ссылке ?

int** array2D = new int*[SIZE] - вот это что значит int*[SIZE] - еще разыменование ?

мне не понятно где то пишут что когда передаешь указатель в функцию ты ты должен отдать ссылку на объект

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

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

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

Возможный вариант решения:

using namespace std;

void print(int x[], int n);

void print(int x[], int n)

При вызове функции оператором

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

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

С учётом того, что массив в подпрограмму чаще всего передаётся весь и с начала, разработчики языка запись вида &x[0] сократили до x , т.е. обращение к массиву по имени эквивалентно обращению по адресу к элементу с индексом 0 .

В заголовке функции

void print(int x[], int n) // 1-й вариант

два формальных параметра. Запись x[] говорит о том, что в подпрограмму передаётся именно массив.

Заголовок может выглядеть и так:

void print(int *x, int n) // 2-й вариант

Массив передаётся по адресу, поэтому и записываем первый параметр как адрес на объект типа int . Этот объект-указатель принимает адрес того элемента массива, который вычисляется в вызывающей функции (например, в main() ).

Какую форму использовать? Это дело вкуса. Компилятор рассматривает 1-й вариант как эквивалент 2-го, хотя для человека нагляднее именно 1-й вариант. По нему видно, что формальный параметр — это именно массив, а не указатель, например, на одиночный элемент.

Трактовка при вызове x как &x[0] позволяет при необходимости передать в подпрограмму не весь массив, а только его часть, начиная с какого-либо адреса. Например, вызов

приводит к выводу на экран монитора трёх элементов массива, начиная с элемента с индексом 2 . При этом сама функция не требует каких либо доработок. В этом плане языки С/С++ гораздо удобнее многих других языков. Так, в Паскале или Бейсике пришлось бы передавать в подпрограмму ещё один параметр — номер элемента, с которого необходимо начать обработку массива, а затем этот номер использовать в операторе цикла.

Матрица как параметр функции

Передача в подпрограмму матрицы в качестве параметра несколько сложнее, чем передача одномерного массива.

Матрица также передаётся по адресу. При вызове функции достаточно указать имя матрицы (это будет адресом начала двумерного массива), но как задать описание матрицы в списке формальных параметров? Матрица, как было сказано ранее, — это массив из массивов. Поэтому можно попробовать записать формальный параметр так:

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

Таким образом, допустима запись

Рассмотрим небольшой пример, поясняющий сказанное выше.

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

Возможный вариант реализации:

using namespace std;

void PrintMatr(int a[][M], int n, int m);

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

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