MyTetra Share
Делитесь знаниями!
Смотрите http://norma-life.ru/katalog/test-poloski тест полоски на глюкозу, zakaz.
Передача параметров в функцию по указателю (C стиль) и по ссылке (C++ стиль). Особенности модификатора Const
05.04.2010
14:40
Автор: Xintrea
Текстовые метки: указатель, ссылка, язык C, язык C++, язык Си, язык Си++, const
Раздел: Компьютер - Программирование - Язык C

Передача через указатель


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


Если передавать параметры через указатель (так называемый С-стиль), код функции выглядит так:


mul5(int *x)

{

*x = *x * 5;

}


Вызов:


int var=10;

mul5(&var); // Здесь символ & обозначает операцию взятия адреса переменной


Такой синтаксис неудобен. Внутри тела функции, перед переменной, которая является указателем, приходится ставить звездочку * для работы со значением, на который указывает указатель. Кроме того, при вызове функции приходится ставить амперсанд & перед именем переменной для того, чтобы передать адрес переменной (каоторый будет принят в функцию как указатель).



Передача через ссылку


Если передавать параметры через ссылку, код функции выглядит так:


mul5(int &x)

{

x = x * 5;

}


А вызов выглядит так:


int var=10;

mul5(var);


Видно, что нет никаких разыменовываний в теле функции функции. Так же при таком вызове не требуется передача адреса переменной.



Однако, следует помнить, что такая передача по ссылке возможна только для базовых типов и и для объектов в C/C++. И не работает для передачи массивов!



Поэтому, к примеру, если функция принимает:

  • одномерный массив block из элементов char, элементы которого надо изменить внутри функции (обозначим это как сложный/составной тип)
  • целочислительную переменную shift, которую тоже надо изменить внутри функции (это простой базовый тип)

то реализация функции будет выглядеть так:


void clear(unsigned char *block, int &shift)

{

block[shift]=0;

shift++;

}


А вызов функции будет выглядеть так:


unsigned char* anyBlock="Long string";

int anyShift=0;

int len=strlen(anyBlock);


for(int i=0; i<len; ++i)

clear(anyBlock, anyShift); // Вызов функции


То есть, в вызове нет никаких спецсимволов указателей/адресов ни для первого ни для второго параметра. Для первого параметра нет спецсимвола взятия адреса (хоть и идет работа с указателем) из-за того, что имя массива имеет тип указателя. Для второго параметра нет спецсимвола взятия адреса из-за того, что передача идет по ссылке.


При таком вызове будут изменяться как ячейки массива anyBlock, так и переменная anyShift.



Ключевое слово Const и указатели


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


void show(const unsigned char * block)


с модификатором const есть много путанницы. Вопрос: что значит запись "const unsigned char *" - запрет модификации элементов массива, или запрет модификации указателя на массив? Правильный ответ - запрет модификации элементов массива. Чтобы понять, почему так, нужно знать, что на самом деле, такая запись - это историческое "расширение" синтаксиса C++. В первых версиях стандарта такого синтаксиса предусмотрено не было. Предолагалась только четкая запись в виде:


<Тип> <Модификатор доступа>


и правильная запись (эквивалент вышеприведенной) будет выглядеть так:


void show(unsigned char const * block)


То есть, модификатор доступа const влияет на тип, написанный слева от него, вот и все дела. То есть, данная запись означает, что константным будет тип unsigned char, таким образом неизменными будут оставаться данные массива, а не указатель на массив. Но потом в стандарт была добавлена возможность написания модификатора доступа в начало определения, и однозначность сразу исчезла. Теперь модификатор доступа const пишется по такому правилу:



1. Модификатор доступа const пишется после типа, и, соответственно, влияет на тип, расположенный слева от него.

2. Но если const написан в начале определения, то он влияет на "короткий" тип справа от него.


"Короткий тип" - это имеется в виду минимально возможное написание типа, которое расположено справа от const. То есть, в нашем примере "const unsigned char * block", минимально возможный тип будет unsigned char без звездочки. Таким образом получаем, что запись вида "const в начале" говорит о невозможности изменить сами данные в массиве, а не невозможность изменить указатель на массив.


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


void show(unsigned char * const block)


Здесь работает первая часть правила. Можно написать невозможность изменения как данных в массиве, так и указателя на массив:


void show(unsigned char const * const block)


Здесь тоже работает первая часть правила. Но на практике чаще будут встречаться описания с ведущим const (по второму пункту правила):


// Неизменны только данные массива

void show(const unsigned char * block)


// Неизменны и данные массива и указатель

void show(const unsigned char * const block)



Ключевое слово Const и ссылки


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


Поэтому имеет смысл говорить только о синтаксисе параметров функций, который бы блокировал изменение значения, на которое указывает ссылка. И этот синтаксис полностью эквивалентен синтаксису указателей, только вместо звездочки (*) используется амперсанд (&).


Следующие прототипы функций полностью эквивалентны:


void showValue(const double & value)

void showValue(double const & value)


Такая форма записи запрещает изменять значение, на которое указывает ссылка.


Хорошим тоном считается писать модификатор const для ссылок, у которых значение, на которое она указывает, не должно меняться внутри функций.



Так же в этом разделе:
← Содержание ...
 
MyTetra Share v.0.43
Яндекс индекс цитирования