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

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

  • автор:

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

Здесь рассмотрена операция по передаче массивов в качестве аргументов функции, поскольку существуют исключения из стандартного правила передачи по значению.

Когда массив используется в качестве аргумента функции, передается только адрес массива, а не копия всего массива. При вызове функции с именем массива в функцию передается указатель на первый элемент массива. (Надо помнить, что в С имена массивов без индекса — это указатели на первый элемент массива.) Параметр должен иметь тип, совместимый с указателем. Имеется три способа объявления параметра, предназначенного для получения указателя на массив. Во-первых, он может быть объявлен как массив, как показано ниже:

#include
void display(int num[10]);
int main (void) /* вывод чисел */
int t [10], i;
for (i=0; i display(t);
return 0;
>

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

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

где num объявлен как целочисленный массив неизвестного размера. Поскольку С не предоставляет проверку границ массива, настоящий размер массива не имеет никакого отношения к параметру (но, естественно, не к программе). Данный метод объявления также определяет num как целочисленный указатель.

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

Он допустим, поскольку любой указатель может быть индексирован с использованием [], если он является массивом. (На самом деле массивы и указатели очень тесно связаны друг с другом.) Все три метода объявления параметра приводят к одинаковому результату — указателю. С другой стороны, элемент массива используется как аргумент, трактуемый как и другие простые переменные. Например, программа может быть написана без передачи всего массива:

void display(int num)
printf («%d «, num);
>

Как можно видеть, в display() передается параметр типа int. Не имеет значения, что display() вызывается с элементом массива в качестве параметра, поскольку передается только одно значение.

Важно понять, что при использовании массива в качестве аргумента функции происходит передача в функцию его адреса. Это означает, что код внутри функции действует и может изменять настоящее значение массива, используемого при вызове. Например, рассмотрим функцию print_upper(), выводящую строку прописными буквами:

#include
#include
void print_upper(char *string);
int main(void) /* вывод строки в верхнем регистре */
char s[80];
gets (s);
print_upper(s) ;
return 0;
>

void print_upper(char *string)
register int t;
for(t=0; string[t]; ++t)
string[t] = toupper(string[t]);
printf(«%c», string[t]);
>
>

После вызова print upper() происходит изменение содержимого массива s в main(). Если это не нужно, следует переписать программу следующим образом:

# include
#include
void print upper(char *string);
int main(void) /* вывод строки в верхнем регистре */
char s[80];
gets(s);
print_upper(s);
return 0;
>

void print_upper(char *string)
register int t;
for(t=0; string[t]; ++t)
printf («%c», toupper (string[t]));
>

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

Классический пример передачи массивов в функции находится в стандартной библиотечной функции gets(). Хотя gets() из библиотеки Borland С++ гораздо сложнее, функция, показанная в данном примере, содержит основную идею работы. Для того, чтобы избежать путаницы и не вызвать стандартную функцию, данная функция называется xgets().

/* простейшая версия стандартной библиотечной функции gets() */

void xgets (char *s)
register char ch;
register int t;
for(t=0; t ch = getche();
switch(ch)
case ‘ \r’:
s[t] = ‘\0’; /* null завершает строку */
return;
case ‘\b’:
if(t>0) t-;
break;
default:
s[t] = ch;
t++;
>
>
s[79] = ‘ \0’;
>

Функция xgets() должна вызываться с указателем на символ. Это может быть имя символьного массива, который по определению является указателем на символ. xgets() организует цикл for от 0 до 79. Таким образом предотвращается ввод больших строк с клавиатуры. Если набирается более 80 символов, функция завершает работу. Поскольку C не имеет проверки границ массива, следует убедиться, что массив, передаваемый в xgets(), может принять, по крайней мере, 80 символов. По мере набора символов на клавиатуре они вводятся в строку. Если набирается забой, счетчик t уменьшится на 1. При нажатии на ввод помещается нулевой символ в конец строки, то есть строка оканчивается. Поскольку массив, используемый при вызове xgets(), модифицируется, после возврата он будет содержать набранные символы.

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

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

Это можно сделать по-разному, но результат будет одинаковый:

  • void some_function(int array[]);
  • void some_function(int *array);

При этом обязательно нужно указать тип элемента массива.

Размер массива в функцию автоматически не передается, поэтому если размер массива заранее (на этапе компиляции) не оговорен, то нужно передать параметр, который содержит количество элементов в массиве, например number_of_elements:

void some_function(int array[], int number_of_elements);

Следующая программа передает массивы в функцию show_array, которая использует цикл for для вывода значений массивов:

show_array.c

void show_array (int array [], int number_of_elements)
for ( int i = 0; i < number_of_elements; i++) printf("%d\t", array[i]);
>
printf(«\n»);
>

int main()
int little_numbers[5] = ;
int big_numbers[3] = ;
show_array(little_numbers, 5);
show_array(big_numbers, 3);
>

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

Изменение массива из функции

Возможно ли поменять значения элементов из функции?

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

Следующая программа использует функцию get_values, чтобы присвоить три значения массиву numbers:

values_from_keyboard.c

#include
void read_array(int array[], int number_of_elements)
for(int i = 0; i < number_of_elements; i++)
printf(«Введите значение №%d: «, i);
scanf(«%d», &array[i]);
>
>

int main()
int numbers[3] = ;
read_array (numbers, 3); //массив будет изменен!
printf(» Значения массива\n»);
for (int i = 0; i < 3; i++) printf(" numbers [%d] \n", i);
>

Как видите, программа передает массив в функцию по имени, а функция присваивает массиву элементы.

Таким образом, функция может изменить элементы массива, если ей это нужно.

Передать массив по значению функции в C/C++

В этом посте мы обсудим, как передать массив по значению в функцию на C/C++.

Мы знаем, что аргументы функции по умолчанию передаются по значению в C. Однако массивы в C не могут быть переданы функции по значению, и мы можем изменить содержимое массива из вызываемой функции. Это связано с тем, что в функцию передается не массив, а копия указателя на его адрес в памяти. Итак, когда мы передаем массив в функцию, это будет распадаться на указатель независимо от того, объявлен ли параметр как int[] или нет.

Однако несколько трюков позволяют нам передавать массив по значению в C/C++.

1. Использование структур в C

Идея состоит в том, чтобы обернуть массив составным типом данных, таким как структуры в C. Это работает, поскольку структуры передаются в функцию по значению и не распадаются на указатели. В C++ мы можем использовать class.

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

Если размер массива неизвестен, то можно использовать шаблон:

template void f(int (&arr)[N]) <> 

Если то что передается в функцию — это не массив, а указатель (т.е. не T[N] a T* ), то функция должна принимать указатель, а размер надо передавать дополнительным параметром или как-то еще.

void f(int* ptr, std::size_t n) <> 

Однако это очень ненадежное решение, нет никакой гарантии что будет передан правильный размер массива, или что ptr не равен nullptr .
По этому правильно — это использовать span из C++ Core Guidelines

void f(gsl::span arr) <> 

Также, вместо массива T[N] можно передавать ссылку на std::array

void f(std::array& v) <> 

А вместо динамического массива — использовать std::vector :

void f(std::vector& v) <> -- или -- void f(const std::vector& v) <> 

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

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