C++.Бархатный путь


Массивы и параметры - часть 2


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

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

Следующий пример демонстрирует возможный вариант решения проблемы передачи в вызываемую функцию переменного количества однотипных значений. Подлежащие обработке данные в вызывающей функции располагаются в непрерывной области памяти (в нашем примере это целочисленный массив Arr). При этом обрабатывающая функция имеет два параметра, один из которых является указателем на объект обрабатываемого типа (в определении функции закомментированы альтернативные варианты объявления этого параметра), второй - целочисленного типа. В выражении вызова значением первого параметра оказывается адрес первого элемента массива, значением второго параметра - количество обрабатываемых элементов массива. Таким образом, функция с постоянным количеством параметров позволяет обрабатывать заранее неизвестное количество значений. #include <iostream.h> void fun(int * = NULL, int = 0); void main() { int Arr[10] = {0,1,2,3,4,5,6,7,8,9}; fun(Arr, 10); fun(Arr, sizeof(Arr)/sizeof(Arr[0])); } void fun(int* pArr /* int pArr[] */ /* int pArr[150] */, int key) { for ( key--; key >= 0; key--) cout << pArr[key] << endl; }

Фактическое тождество одномерного массива и указателя при объявлении параметров определяет специфику объявления многомерных массивов-параметров. В C++ многомерный массив - понятие условное. Как известно, массив размерности n является одномерным массивом множества объектов производного типа - массивов размерности n-1. Размерность массива является важной характеристикой производного типа. Отсюда - особенности объявления многомерных массивов как параметров функций.

В следующем примере определена функция fun с трёхмерным параметром размерности 5*5*25. Транслятор спокойно реагирует на различные варианты прототипов функции fun в начале программы. Если последовательно комментировать варианты объявлений функции, ошибка будет зафиксирована лишь тогда, когда будут закомментированы все объявления, у которых характеристика второй и третьей размерности совпадает с аналогичной характеристикой многомерного параметра-массива в определении функции. #include <iostream.h> #define DIM1 3 #define DIM2 5 // void fun(int rrr[][][]); /* Такой прототип неверен! Квадратные скобки в объявлении параметра, начиная со второй, обязательно должны содержать константные выражения, значения которых должны соответствовать значениям в квадратных скобках (начиная со второй!) в объявлении параметра в определении функции. Эти значения в контексте объявления параметров являются элементами спецификации ТИПА параметра, а не характеристиками его РАЗМЕРОВ. Типы составляющих одномерные массивы элементов в прототипе и заголовке определения функции должны совпадать. */ //void fun(int rrr[5][DIM1][DIM2]); void fun(int rrr[][3][5]); void fun(int rrr[15][DIM1][5]); void fun(int *rrr[3][DIM2]); /* Во всех этих случаях параметр rrr является указателем на двумерный массив из 3*5 элементов типа int. "Массив из трёх по пять элементов типа int" - такова спецификация типа объекта. */ /* Следующие два прототипа, несмотря на одно и то же имя функции, объявляют ещё пока неопределённые фунции. Одноимённые функции с различными списками параметров называются перегруженными функциями. */ void fun(int *rrr[25][250]); void fun(int rrr[50][100][DIM1]); void main() { int Arr[2][DIM1][DIM2] = { { {1 ,2 ,3 ,4 ,5 }, {10,20,30,40,50}, {11,12,13,14,15}, }, { {1,}, {2,}, {3,}, } }; fun(Arr); // Вызов fun. Значение параметра - адрес начала массива. } void fun(int pArr[75][DIM1][DIM2]) { cout << sizeof(pArr) << endl; cout << pArr << " " << &pArr << " " << &pArr[0][0] << endl; /* Параметр проявляет свойства указателей. */ cout << sizeof(*pArr) << endl; cout << *pArr << " " << &*pArr << " " << &*pArr[0][0] << endl; /* Если применить к указателю операцию разыменования, можно убедиться в том, что параметр указывает на массив. При этом о топологии многомерного массива можно судить исключительно по косвенной информации (в данном случае - по значениям константных выражений DIM1 и DIM2) или по значениям дополнительных параметров. */ }

При работе с параметрами-массивами мы имеем дело с указателями. Это немаловажное обстоятельство позволяет непосредственно из вызываемой функции изменять значения объектов, определённых в вызывающей функции.

| |

 




- Начало -  - Назад -  - Вперед -