C++ - [43]

Шрифт
Интервал

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

double f() (* // ... return 1; // неявно преобразуется к double(1) *)

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

int* f() (* int local = 1; // ... return amp;local; // так не делайте *)

Эта ошибка менее обычна, чем эквивалентная ошибка при использовании ссылок:

int amp; f() (* int local = 1; // ... return local; // так не делайте *)

К счастью, о таких возвращаемых значениях предупреждает компилятор. Вот другой пример:

int amp; f() (* return 1;*) // так не делайте

4.6.5 Векторные Параметры

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

int strlen(const char*);

void f() (* char v[] = «a vector» strlen(v); strlen(«Nicholas»); *);

Иначе говоря, при передаче как параметр параметр типа T[] преобразуется к T*. Следовательно, присваивание элементу векторного параметра изменяет значение элемента вектора, кторый является параметром. Другими словами, вектор отличается от всех остальных типов тем, что вектор не передается (и не может передаваться) по значению.

Размер вектора недоступен вызываемой функции. Это может быть неудобно, но эту сложность можно обойти несколькими спсобами. Строки оканчиваются нулем, поэтому их размер можно легко вычислить. Для других векторов можно передавать второй

параметр, который задает размер, или определить тип, содержщий указатель и индикатор длины, и передавать его вместо просто вектора (см. также #1.11). Например:

void compute1(int* vec_ptr, int vec_size); // один способ

struct vec (* // другой способ int* ptr; int size; *);

void compute2(vec v);

С многомерными массивами все хитрее, но часто можно вместо них использовать векторы указателей, которые не требют специального рассмотрения. Например:

char* day[] = (* «mon», «tue», «wed», «thu», «fri», «sat», «sun» *);

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

void print_m34(int m[3][4]) (* for (int i = 0; i«3; i++) (* for (int j = 0; j„4; j++) cout «« " " «« m[i][j]; cout «« «\n“; *) *)

Матрица, конечно, все равно передается как указатель, а размерности используются просто для удобства записи.

Первая размерность массива не имеет отношения к задаче поиска положения элемента (#2.3.6). Поэтому ее можно передвать как параметр:

void print_mi4(int m[][4], int dim1) (* for (int i = 0; i«dim1; i++) (* for (int j = 0; j„4; j++) cout «« " " «« m[i][j]; cout «« «\n“; *) *)

Сложный случай возникает, когда нужно передавать обе размерности. «Очевидное решение» просто не работает:

void print_mij(int m[][], int dim1, int dim2) // ошибка (* for (int i = 0; i«dim1; i++) (* for (int j = 0; j„dim2; j++) cout «« " " «« m[i][j]; // сюрприз! cout «« «\n“; *) *)

Во-первых, описание параметра m[][] недопустимо, покольку для нахождения положения элемента должна быть известна вторая размерность многомерного массива. Во-вторых, выражение m[i][j] интерпретируется (правильно) как *(*(m+i)+j), но нпохоже, чтобы это имел в виду программист. Вот правильное решение:

void print_mij(int** m, int dim1, int dim2) (* for (int i = 0; i«dim1; i++) (* for (int j = 0; j„dim2; j++) cout «« " " «« (int*)m[i*dim2+j]; // туманно cout «« «\n“; *) *)

Выражение, которое применяется для доступа к элементам, эквивалентно тому, которое генерирует компилятор, когда он знает последнюю размерность. Чтобы немного прояснить програму, можно ввести дополнительную переменную:

int* v = (int*)m; // ... v[i*dim2+j]

4.6.6 Параметры по Умолчанию

Часто в самом общем случае функции требуется больше праметров, чем в самом простом и более употребительном случае. Например, в библиотеке потоков есть функция hex(), порождащая строку с шестнадцатиричным представлением целого. Второй параметр используется для задания числа символов для предтавления первого параметра. Если число символов слишком мало для представления целого, происходит усечение, если оно сликом велико, то строка дополняется пробелами. Часто програмист не заботится о числе символов, необходимых для предсталения целого, поскольку символов достаточно. Поэтому для нуля в качестве второго параметра определено значение «использвать столько символов, сколько нужно». Чтобы избежать засорния программы вызовами вроде hex(i,0), функция описывается так:

extern char* hex(long, int =0);

Инициализатор второго параметра является параметром по умолчанию. То есть, если в вызове дан только один параметр, в качестве второго используется параметр по умолчанию. Напрмер:


Еще от автора Мюррей Хилл
Справочное руководство по C++

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


Рекомендуем почитать
Программное обеспечение и его разработка

Автор книги — американский специалист по программированию, один из руководителей фирмы IBM, в своей книге делает попытку изложить общие проблемы создания программного обеспечения, его сопровождения и использования. Особенно подробно рассматриваются все фазы разработки программ разных типов. Изложение ясное, удачно иллюстрировано примерами.Для программистов разной квалификации и пользователей ЭВМ.fb2: ВНИМАНИЕ. В тексте присутствуют таблицы. Рекомендуется читать файл с помощью программы, поддерживающей их отображение.


Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Программирование приложений для мобильных устройств под управлением Android. Часть 1

Книга посвящена разработке программ для мобильных устройств под управлением операционной системы Android. Рассматривается создание приложений с использованием системных компонентов и служб Android. Приведены базовые данные о структуре приложений, об основных классах и их методах, сопровождаемые примерами кода. Часть 1 содержит шесть глав, описывающих основные принципы создания приложений, пользовательский интерфейс, полномочия приложений, а так же базовые классы: Activity, Intent, Fragment. Книга предназначена для программистов, владеющих языком программирования Java и желающих освоить написание приложений, работающих под ОС Android.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


FreeBSD - полезные советы

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


Тонкости дизассемблирования

Очень часто под рукой не оказывается ни отладчика, ни дизассемблера, ни даже компилятора, чтобы набросать хотя бы примитивный трассировщик. Разумеется, что говорить о взломе современных защитных механизмов в таких условиях просто смешно, но что делать если жизнь заставляет?..