Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Скидка до 20% на услуги дата-центра. Аренда серверной стойки. Colocation от 1U!

Миграция в облако #SotelCloud. Виртуальный сервер в облаке. Выбрать конфигурацию на сайте!

Виртуальная АТС для вашего бизнеса. Приветственные бонусы для новых клиентов!

Виртуальные VPS серверы в РФ и ЕС

Dedicated серверы в РФ и ЕС

По промокоду CITFORUM скидка 30% на заказ VPS\VDS

VPS/VDS серверы. 30 локаций на выбор

Серверы VPS/VDS с большим диском

Хорошие условия для реселлеров

4VPS.SU - VPS в 17-ти странах

2Gbit/s безлимит

Современное железо!

Массивы и параметры

В C++ возможно лишь поэлементное копирование массивов. Этим объясняется то обстоятельство, что в списке объявлений параметров не объявляются параметры-массивы. В Borland С++ 4.5 транслятор спокойно реагирует на объявление одномерного массива в заголовке функции, проверяет корректность его объявления (размеры массива должны быть представлены константными выражениями), однако сразу же игнорирует эту информацию. Объявление одномерного массива-параметра преобразуется к объявлению указателя. Подтверждением этому служит тот факт, что "массив"-параметр невозможно проинициализировать списком значений, что совершенно нормально для обычных массивов:

void ff(int keyArr[  ] = {0,1,2,3,4,5,6,7,8,9});// Ошибка объявления.
void ff(int keyArr[10] = {0,1,2,3,4,5,6,7,8,9});// Ошибка объявления.

Оба варианта прототипа функции будут отвергнуты. При этом транслятор утверждает, что указателю (и это несмотря на явное указание размеров массива!) можно присваивать значение адреса, либо NULL.

int keyArr[100]; // Глобальный массив.
int xArr[5]; // Ещё один глобальный массив.
int XXX; // Простая переменная.
void ff(int keyArr[ 1] = keyArr, //Объявление одноименного параметра.
        int pArr1 [10] = xArr,
        int pArr2 [  ] = &XXX, // Адрес глобальной переменной.
        int pArr3 [  ] = &xArr[10], //Адрес несуществующего элемента.
        int pArr4 [50] = NULL);
/* Допустимые способы инициализации массивов в прототипе функции
свидетельствуют о том, что здесь мы имеем дело с указателями. */

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

#include <iostream.h>
void fun(int *, int[], int qwe[10] = NULL);
/* Все три объявления параметров на самом деле являются объявлениями указателей. */
void main()
{
 int Arr[10] = {0,1,2,3,4,5,6,7,8,9};
 int *pArr =  Arr;
/* В функции main определены массив и указатель.*/
cout << Arr << "   " << &Arr << "   " << &Arr[0] << endl;
cout << pArr << "   " << &pArr << "   " << &pArr[0] << endl;
/* Разница между массивом и указателем очевидна: значение выражения,
представленного именем массива, собственный адрес массива и адрес
первого элемента массива совпадают. */
 fun(Arr, Arr, Arr);
}
void fun(int* pArr1, int pArr2[], int pArr3[100])
{
cout << sizeof(pArr1) << endl;
cout << sizeof(pArr2) << endl;
cout << sizeof(pArr3) << endl;
cout << pArr1 << "   " << &pArr1 << "   " << &pArr1[0] << endl;
cout << pArr2 << "   " << &pArr2 << "   " << &pArr2[0] << endl;
cout << pArr3 << "   " << &pArr3 << "   " << &pArr3[0] << endl;
/* Все параметры проявляют свойства указателей. */
}

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

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

Следующий пример демонстрирует возможный вариант решения проблемы передачи в вызываемую функцию переменного количества однотипных значений. Подлежащие обработке данные в вызывающей функции располагаются в непрерывной области памяти (в нашем примере это целочисленный массив 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) или по значениям дополнительных
параметров. */
}

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

Назад | Содержание | Вперед

 

Бесплатный конструктор сайтов и Landing Page

Хостинг с DDoS защитой от 2.5$ + Бесплатный SSL и Домен

SSD VPS в Нидерландах под различные задачи от 2.6$

✅ Дешевый VPS-хостинг на AMD EPYC: 1vCore, 3GB DDR4, 15GB NVMe всего за €3,50!

🔥 Anti-DDoS защита 12 Тбит/с!

VPS в России, Европе и США

Бесплатная поддержка и администрирование

Оплата российскими и международными картами

🔥 VPS до 5.7 ГГц под любые задачи с AntiDDoS в 7 локациях

💸 Гифткод CITFORUM (250р на баланс) и попробуйте уже сейчас!

🛒 Скидка 15% на первый платеж (в течение 24ч)

Новости мира IT:

Архив новостей

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 7861149
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2019 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...