Упражнение 6.17. Напишите функцию, определяющую, содержит ли строка какие-нибудь заглавные буквы. Напишите функцию, переводящую всю строку в нижний регистр. Использованные в этих функциях параметры имеют тот же тип? Если да, то почему? Если нет, то тоже почему?
Упражнение 6.18. Напишите объявления для каждой из следующих функций. Написав объявления, используйте имя функции для обозначения того, что она делает.
(a) Функция compare()
возвращает значение типа bool
и получает два параметра, являющиеся ссылками на класс matrix
.
(b) Функция change_val()
возвращает итератор vector
и получает два параметра: один типа int
, а второй итератор для вектора vector
.
Упражнение 6.19. С учетом следующего объявления определите, какие вызовы допустимы, а какие нет. Объясните, почему они недопустимы.
double calc(double);
int count(const string &, char);
int sum(vector
vector
(a) calc(23.4, 55.1); (b) count("abcda", 'a');
(c) calc(66); (d) sum(vec.begin(), vec.end(), 3.8);
Упражнение 6.20. Когда ссылочные параметры должны быть ссылками на константу? Что будет, если сделать параметр простой ссылкой, когда это могла быть ссылка на константу?
6.2.4. Параметры в виде массива
Массивы обладают двумя особенностями, влияющими на определение и использование функций, работающих с массивами: массив нельзя скопировать (см. раздел 3.5.1), имя массива при использовании автоматически преобразуется в указатель на его первый элемент (см. раздел 3.5.3). Поскольку копировать массив нельзя, его нельзя передать функции по значению. Так как имя массива автоматически преобразуется в указатель, при передаче массива функции фактически передается указатель на его первый элемент.
Хотя передать массив по значению нельзя, вполне можно написать параметр, который выглядит как массив:
//
//
//
void print(const int*);
void print(const int[]); //
void print(const int[10]); //
Независимо от внешнего вида, эти объявления эквивалентны: в каждом объявлена функция с одним параметром типа const int*
. Когда компилятор проверяет вызов функции print()
, он выясняет только то, что типом аргумента является const int*
:
int i = 0, j[2] = {0, 1};
print(&i); //
print(j); //
Если передать массив функции print()
, то этот аргумент автоматически преобразуется в указатель на первый элемент в массиве; размер массива не имеет значения.
Поскольку массивы передаются как указатели, их размер функции обычно неизвестен. Они должны полагаться на дополнительную информацию, предоставляемую вызывающей стороной. Для управления параметрами указателя обычно используются три подхода.
Первый подход к управлению аргументами в виде массива требует, чтобы массив сам содержал маркер конца. Примером этого подхода являются символьные строки в стиле С (см. раздел 3.5.4). Строки в стиле С хранятся в символьных массивах, последний символ которых является нулевым. Функции, работающие со строками в стиле С, прекращают обработку массива, когда встречают нулевой символ:
void print(const char *cp) {
if (cp) //
while (*cp) //
cout << *cp++; //
}
Это соглашение хорошо работает с данными, где есть очевидное значение конечного маркера (такое, как нулевой символ), который не встречается в обычных данных. Это работает значительно хуже с такими данными, как целые числа, где каждое значение в диапазоне вполне допустимо.