cpp

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

Передача одномерных массивов и строк осуществляется с помощью указателей. Обратите внимание на то, что при вызове функции перед названием переменной не нужно добавлять оператор &, так как название переменной содержит адрес первого элемента массива. Пример передачи C-строки приведен в листинге 12.10.

Листинг 12.10. Передача C-строки в функцию

#include <iostream>

void func1(char *s);
void func2(char s[]);

int main() {
   char str[] = "String";
   std::cout << sizeof(str) << std::endl; // 7
   func1(str); // Оператор & перед str не указывается!!!
   func2(str);
   std::cout << str << std::endl; // strinG
   return 0;
}
void func1(char *s) {
   s[0] = 's'; // Изменяется значение элемента массива str
   std::cout << sizeof(s) << std::endl;
    // 8 (размер указателя), а не 7!!!
}
void func2(char s[]) {
   s[5] = 'G'; // Изменяется значение элемента массива str
}

Объявление char *s эквивалентно объявлению char s[]. И в том и в другом случае объявляется указатель на тип char. Чаще используется первый способ. Обратите внимание на значения, возвращаемые оператором sizeof вне и внутри функции. Вне функции оператор возвращает размер всего символьного массива, в то время как внутри функции оператор sizeof возвращает только размер указателя. Это происходит потому что внутри функции переменная s является указателем, а не массивом. Поэтому, если внутри функции необходимо знать размер массива, то количество элементов (или размер в байтах) следует передавать в дополнительном параметре.

При передаче многомерного массива необходимо явным образом указывать все размеры (например, int a[2][4]). Самый первый размер допускается не указывать (например, int a[][4]). Пример передачи двумерного массива в функцию приведен в листинге 12.11.

Листинг 12.11. Передача двумерного массива

#include <iostream>

void func(int a[][4]);

int main() {
   const int ARR_ROWS = 2, ARR_COLS = 4;
   int i, j;
   int arr[ARR_ROWS][ARR_COLS] = {
      {1, 2, 3, 4},
      {5, 6, 7, 8}
   };
   func(arr);
   // Выводим значения
   for (i = 0; i < ARR_ROWS; ++i) {
      for (j = 0; j < ARR_COLS; ++j) {
         std::cout.width(2);       // Ширина поля
         std::cout << arr[i][j];
      }
      std::cout << std::endl;
   }
   return 0;
}
void func(int a[][4]) { // или void func(int a[2][4])
   a[0][0] = 80;
}

Такой способ передачи многомерного массива нельзя назвать универсальным, так как существует жесткая привязка к размеру. Одним из способов решения проблемы является создание дополнительного массива указателей. В этом случае в функцию передается адрес первого элемента массива указателей, а объявление параметра в функции выглядит так:

int *a[]

или так:

int **a

Пример передачи массива указателей приведен в листинге 12.12.

Листинг 12.12. Передача массива указателей

#include <iostream>

void func(int *a[], int rows, int cols);

int main() {
   const int ARR_ROWS = 2, ARR_COLS = 4;
   int arr[ARR_ROWS][ARR_COLS] = {
      {1, 2, 3, 4},
      {5, 6, 7, 8}
   };
   // Создаем массив указателей
   int *parr[] = {arr[0], arr[1]};
   // Передаем адрес массива указателей
   func(parr, ARR_ROWS, ARR_COLS);
   return 0;
}
void func(int *a[], int rows, int cols) {
   // или void func(int **a, int rows, int cols)
   for (int i = 0, j; i < rows; ++i) {
      for (j = 0; j < cols; ++j) {
         std::cout.width(2);
         std::cout << a[i][j];
      }
      std::cout << std::endl;
   }
}

Однако и этот способ имеет недостаток, так как нужно создавать дополнительный массив указателей. Наиболее приемлемым способом является передача двумерного массива как одномерного. В этом случае в функцию передается адрес первого элемента массива, а в параметре объявляется указатель. Так как все элементы двумерного массива располагаются в памяти последовательно, зная количество элементов или размеры можно вычислить положение текущего элемента, используя адресную арифметику. Пример передачи двумерного массива как одномерного приведен в листинге 12.13.

Листинг 12.13. Передача двумерного массива как одномерного

#include <iostream>

void func(int *pa, int rows, int cols);

int main() {
   const int ARR_ROWS = 2, ARR_COLS = 4;
   int arr[ARR_ROWS][ARR_COLS] = {
      {1, 2, 3, 4},
      {5, 6, 7, 8}
   };
   // Передаем в функцию адрес первого элемента массива
   func(arr[0], ARR_ROWS, ARR_COLS);
   return 0;
}
void func(int *pa, int rows, int cols) {
   for (int i = 0, j; i < rows; ++i) {
      for (j = 0; j < cols; ++j) {
         std::cout.width(2);
         // Вычисляем положение элемента
         std::cout << *(pa + i * cols + j);
         // std::cout << pa[i * cols + j];
      }
      std::cout << std::endl;
   }
}

Передача в функцию массива C-строк осуществляется так же как передача массива указателей. Чтобы в функцию не передавать количество элементов можно при инициализации массива C-строк последнему элементу присвоить нулевой указатель. Этот элемент будет служить ориентиром конца массива. В качестве примера выведем все строки внутри функции (листинг 12.14).

Листинг 12.14. Передача массива C-строк

#include <iostream>

void func(const char *s[]);

int main() {
   const char *str[] = {"String1", "String2", "String3",
      nullptr // Вставляем нулевой указатель, чтобы был ориентир
   };
   func(str);
   return 0;
}
void func(const char *s[]) { // или void func(const char **s)
   while (*s) {        // Выводим все строки
      std::cout << *s << std::endl;
      ++s;
   }
}

Учебник C++ (Qt Creator и MinGW)
Учебник C++ (Qt Creator и MinGW) в формате PDF

Реквизиты

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов

cpp