Так же, как и другие переменные, массивы могут быть переданы в функции в виде аргументов. Рассмотрим такую программу:
#include <stdio.h>
#include <time.h>
 
#define N 10
 
void arr_make(int arr[], int min, int max);
 
int main () {
  int arrI[N], i;
 
  arr_make(arrI, 30, 90);
 
  for (i=0; i<N; i++)
    printf("%d ", arrI[i]);
  printf("\n");
}
 
void arr_make(int arr[], int min, int max) {
  int i;
 
  srand(time(NULL));
 
  for (i=0; i<N; i++)
    arr[i] = rand() % (max - min + 1) + min;
}Внутри функции main() создается массив из 10 элементов. Затем вызывается функция arr_make(),
        в которую передаются имя массива и два целых числа как аргументы.
При взгляде на функцию arr_make() можно заметить, что ее первый параметр выглядит необычно. Она принимает массив
        неизвестного размера. Если предположить, что массивы передаются по значению, то есть копируются, как компилятор определит необходимую
        память для arr_make(), не зная точного размера ее параметра?
Ранее мы узнали, что имя массива является указывающим на первый элемент константным указателем, т.е. содержит адрес. По сути, мы передаем в функцию копию адреса, а не копию самих значений. Это позволяет редактировать локальные переменные в вызывающей функции из внешней. Несколько переменных могут ссылаться на одну и ту же память, и изменение значения через одну из них приведет к изменению значений всех связанных переменных.
Обозначение arr[] в параметрах функций означает, что фактически передается указатель на массив, а не скалярная
        переменная типа int, char, float и подобных.
Разберем это далее. Если функция принимает только адрес массива, внутренняя структура массива не существует, и выражение типа arr[i]
        внутри функции использует arr как указатель с добавлением смещения. Поэтому внутри функции arr_make() цикл
        можно выразить как:
for(i=0; i<N; i++)
	*arr++ = rand() % (max - min + 1) + min;В цикле происходит запись результата выражения справа от знака равно в адрес, на который указывает arr. Это обеспечивает
        выражение *arr. Затем указатель arr сдвигается к следующей ячейке памяти прибавлением единицы (arr++).
        Сначала происходит запись по адресу, хранимому в arr, после чего меняется сам адрес, сдвигаясь на одну ячейку памяти заданного
        размера.
Поскольку мы меняем arr, это доказывает, что оно является обычным указателем, а не именем массива. Тогда зачем в заголовке
        функции такой вид arr[]? В большинстве случаев предпочитается использовать просто переменную-указатель:
        void arr_make(int *arr, int min, int max);
Хотя в этом случае сразу не ясно, принимает ли функция указатель на одиночную переменную или же на массив. В любом случае она будет работать корректно.
При передаче массивов в функцию часто также передают количество его элементов в виде отдельного параметра. В примере выше
        N является глобальной константой, поэтому доступна как из функции main(), так и arr_make().
        Более корректно было бы изменить функцию arr_make() следующим образом:
void arr_make(int *arr, int n, int min, int max) {
  int i;
 
  srand(time(NULL));
 
  for (i=0; i<n; i++)
    arr[i] = rand() % (max - min + 1) + min;
}Параметр n определяет число элементов в массиве, которые будут обрабатываться.
Стоит отметить, что передача имени массива в функцию позволяет последней модифицировать его. Но такой эффект нужен не всегда. Можно просто не менять данные в массиве из функции, например, при подсчете суммы элементов множества; сами элементы тогда неизменяемы:
int arr_sum(int *arr) {
  int i, s=0;
 
  for(i=0; i<N; i++) {
	s = s + arr[i];
  }
 
  return s;
}Однако, если необходимо создать более надежную программу, в которой большинство функций не должны менять данные массива, стоит объявить параметр-указатель как константу, например:
int arr_sum(const int *arr);
Таким образом, любые попытки изменения значения через такой указатель приведут к ошибке, и программист будет уведомлен, что функция пытается поменять содержимое массива.
Модернизируем программу, приведенную в начале урока:
#include <stdio.h>
#include <time.h>
 
#define N 10
 
void arr_make(int *arr, int min, int max);
void arr_inc_dec(int arr[], char sign);
void arr_print(int *arr);
 
int main () {
  int arrI[N], i, minimum, maximum;
  char ch;
 
  printf("Enter minimum & maximum: ");
  scanf("%d %d", &minimum, &maximum);
  arr_make(arrI, minimum, maximum);
  arr_print(arrI);
 
  scanf("%*c"); // избавляемся от \n
 
  printf("Enter sign (+,-): ");
  scanf("%c", &ch);
  arr_inc_dec(arrI, ch);
  arr_print(arrI);
}
 
void arr_make(int *arr, int min, int max) {
      int i;
      srand(time(NULL));
 
      for(i=0; i<N; i++)
	    *arr++ = rand() % (max - min + 1) + min;
}
 
void arr_inc_dec(int *arr, char sign) {
	int i;
	for (i=0; i<N; i++) {
		if (sign == '+') arr[i]++;
		if (sign == '-') arr[i]--;
	}
}
 
void arr_print(int *arr) {
	int i;
	printf("The array is: ");
	for (i=0; i<N; i++)
		printf("%d ", *arr++);
      printf("\n");
}Теперь пользователю предлагается ввести минимальное и максимальное значения, после чего создается массив с элементами в этом диапазоне.
        Массив выводится на экран функцией arr_print(). Далее пользователь вводит символ + или -, и в зависимости от этого
        выбора функция arr_inc_dec() увеличивает или уменьшает на единицу значения элементов массива.
В функциях arr_make() и arr_print() используется указательная нотация, и значения указателей
        изменяются: сначала они указывают на первый элемент, затем на второй и так далее. В функции arr_inc_dec() реализовано
        обращение к элементам массива. При этом сам указатель остается неизменным: к arr добавляется смещение, увеличивающееся на каждой
        итерации цикла. Отметим, что выражение arr[i] представляет собой *(arr+i).
Использование нотации обращения к элементам массива делает программы более читаемыми, а запись с помощью указателей позволяет компилировать
        их немного быстрее, так как при встрече выражения arr[i] компилятор выполняет дополнительную операцию преобразования
        в *(arr+i). Однако, целесообразнее сделать код более понятным и потерять немного времени при компиляции.
- Переделайте программу, чтобы она работала с вещественными числами. Вместо функции arr_inc_dec()создайте другую, изменяющую значения элементов массива на любое указанное пользователем число.
- Напишите программу, в которой из одной функции в другую передается указатель не на начало массива, а на его среднюю часть.
- Создайте программу, где из функции main()в иную функцию передаются два массива: один заполненный, другой пустой. Во второй функции элементам пустого массива должны присваиваться преобразованные элементы заполненного массива, который модулировать нельзя.
