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

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

  • автор:

Как передать динамический массив в функцию 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);

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

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

Рассмотрим одномерный массив из 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 серебряных знака 70 70 бронзовых знаков
задан 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
220k 15 15 золотых знаков 120 120 серебряных знаков 231 231 бронзовый знак

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

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

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

int item = base[i]; 

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

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

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

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

Author24 — интернет-сервис помощи студентам

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

Пытался изменить объявление на

void readFile(const char* file, int ** array, int * size)

и передавать

readFile(inputFile, &array, &size);

но запутался в дальнейшем.

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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#include #include void readFile(const char* file, int * array, int * size) { FILE* f = fopen(file, "rt"); if (!f) { printf("Error! Can not open source file!\nExit!\n"); exit(EXIT_FAILURE); } *size = 0; while ( !feof(f)) { if (fgetc(f) == '\n') (*size)++; } array = (int * )malloc((*size) * sizeof(int)); rewind(f); int i = 0; for (; i  *size; ++i) { fscanf(f, "%d", &array[i]); } fclose(f); } int main(int argc, char **argv) { if (argc  4) { printf("Error! Not enought of arguments!\nExit!\n"); exit(EXIT_FAILURE); } if (argc > 4) { printf("Error! Too many arguments!\nExit!\n"); exit(EXIT_FAILURE); } const char* inputFile = argv[1]; const char* outputFile = argv[2]; int * array /*= NULL*/; int size = 0; readFile(inputFile, array, &size); /*int i=0; for (; i < size; ++i)   printf("%d%s",array[i],"\n"); >*/ }

94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

Не получается адрес динамического двумерного массива передать, как аргумент функции
/* Лабораторная работа №3 Во всех вариантах необходимо написать три функции, которые будут.

Передача массива как аргумент функции
Здравствуйте! Не подскажете — как передать функции массив как аргумент без использования Variant.

Передача динамического массива в функции
#include <iostream> #include <cstdlib> using namespace std; /*const*/ int k=3; //void sum.

Передача динамического массива функции
Всем привет Возникла такая вот проблема. Создаю динамический массив а точнее 3, 2 одномерных и 1.

133 / 131 / 51
Регистрация: 25.05.2013
Сообщений: 233

ЦитатаСообщение от Enesi Посмотреть сообщение

Как тогда правильно передавать динамический массив
Вот пример передачи динамического массива в функцию:

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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
#include #include #include #include //функция заполняет матрицу псевдослучайными данными void FillMatrix( int** matrix, const int size, const unsigned randRange, const int shift ); //функция печатает матрицу void PrintMatrix( int** matrix, const int size ); int main( void ) { srand( time( 0 ) ); // засеять генератор случайных чисел // запрашиваем у пользователя данные для матрицы int size; printf( "Введите размер квадратной матрицы " ); scanf( "%u", &size ); // объявляем нашу матрицу как указатель на int и выделяем необходимую память для нее int** a = ( int** ) calloc( size, sizeof(int*) ); int i; for ( i = 0; i  size; ++i ) a[ i ] = ( int* ) calloc( size, sizeof(int) ); // заполняем матрицу псевдослучайными значениями типа int FillMatrix( a, size, 100, 0 ); // выводим матрицу на экран puts( "Исходная матрица" ); PrintMatrix( a, size ); // освобождаем память, выделенную под матрицу for ( i = 0; i  size; ++i ) free( a[ i ] ); free( a ); return EXIT_SUCCESS; } void FillMatrix( int** matrix, const int size, const unsigned randRange, const int shift ) { int i, j; for ( i = 0; i  size; ++i ) for ( j = 0; j  size; ++j ) // shift - начальное значение диапазона, randRange - диапазон значений matrix[ i ][ j ] = shift + rand() % randRange; } void PrintMatrix( int** matrix, const int size ) { int i, j; for ( i = 0; i  size; ++i ) { for ( j = 0; j  size; ++j ) printf( "%4d ", matrix[ i ][ j ] ); puts( "" ); } }

Т.е. для массива двумерного передаем: ( указатель, количество строк, количество столбцов ).
Если массив квадратный, то количество строк == количетву столбцов == размер массива и передаем: ( указатель, размер массива ).

Регистрация: 02.10.2012
Сообщений: 46

Эмм, ну меня двумерные массивы пока не волнуют. Не смог вынести из примера нужной информации(( Вроде я так же объявляю и передаю.
Не подскажете, почему у меня функция не изменяет массив? Или другая причина возникновения дампа памяти?

Регистрация: 02.10.2012
Сообщений: 46

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

Z3JheSBoYXQ=
342 / 237 / 83
Регистрация: 08.07.2012
Сообщений: 577

ЦитатаСообщение от Enesi Посмотреть сообщение

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

1 2 3 4 5
{ if (fgetc(f) == '\n') (*size)++; } array = (int * )malloc((*size) * sizeof(int));
if (fgetc(f) == '\n') (*size)++;

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

Добавлено через 11 минут
И да еще, в довесок. Массив в функцию передается все равно в виде указателя.

void Some(Int *array); void Some2(int array[255]);

идентичны по коду, который генерит компилятор. Все приводится к виду указателя на первый элемент массива. &array[0].
но!. По факту мы имеем 2 вида массива, один динамический, другой статический. Поэтому используй, для дальнейшего более удобного сопровождения конкретное указание, какой массив передается. Статичный или динамичный.

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

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