Как правило, все аргументы в объявлении имеют имена. Рассмотрим пример.
int my_find(vector<string> vs, string s, int hint)
// поиск строки s в векторе vs, начиная с позиции hint
{
if (hint<0 || vs.size<=hint) hint = 0;
for (int i = hint; i<vs.size; ++i) // поиск, начиная
// с позиции hint
if (vs[i]==s) return i;
if (0<hint) { // если строка s
не была найдена на позиции до hint
for (int i = 0; i<hint; ++i)
if (vs[i]==s) return i;
}
return –1;
}
Переменная
hint
немного усложняет код, но она введена на основании предположения, что пользователю может быть примерно известно, где в векторе находится строка. Однако представим себе, что мы использовали
my_find
, а затем выяснили, что пользователи редко используют переменную
hint
, так что она лишь снижает производительность программы. В таком случае переменная
hint
больше не нужна, но за пределами нашего фрагмента есть множество вызовов функции
my_find
с аргументом
hint
. Переписывать код мы не хотим (или не можем), поэтому изменять объявления функции
my_find
не будем. Вместо этого мы просто не будем использовать последний аргумент. Поскольку мы его не используем, оставим его без имени.
int my_find(vector<string> vs, string s, int) // 3-й аргумент
// не используется
{
for (int i = 0; i<vs.size; ++i)
if (vs[i]==s) return i;
return –1;
}
Полная грамматика объявлений функций изложена в книге Язык программирования С++ Страуструпа и в стандарте ISO C++.
8.5.2. Возврат значения
Функция возвращает вычисленное значение с помощью инструкции
return
.
T f // функция f возвращает объект класса T
{
V v;
// ...
return v;
}
T x = f;
Здесь возвращаемое значение — это именно то значение, которые мы получили бы при инициализации переменной типа
T
значением типа
V
.
V v;
// ...
T t(v); // инициализируем переменную t значением v
Таким образом, возвращаемое значение — это форма инициализации. Функция, объявившая возвращение значения, должна его возвращать. Например, в следующем фрагменте возникает ошибка:
double my_abs(int x) // предупреждение: этот код содержит ошибки
{
if (x < 0)
return –x;
else if (x > 0)
return x;
} //
ошибка: если х равно нулю, функция ничего не возвращает
На самом деле компилятор может не заметить, что вы “забыли” про вариант
x=0
. Лишь некоторые компиляторы умеют это делать. Тем не менее, если функция сложна, компилятор может не разобраться, возвращает ли она значение или нет, так что следует быть осторожным. Это значит, что программист сам должен убедиться, что функция содержит инструкцию
return
или вызов функции
error
как возможный вариант выхода.
По историческим причинам функция
main
представляет собой исключение из правила. Выход из функции
main
в ее последней точке эквивалентен инструкции
return 0
, означающей успешное завершение программы.
В функции, не возвращающей никаких значений, инструкцию
return
можно использовать для выхода из нее, не указывая возвращаемую переменную. Рассмотрим пример.
void print_until_s(vector<string> v, string quit)
{
for(int i=0; i<v.size; ++i) {
if (v[i]==quit) return;
cout << v[i] << '\n';
}
}
Как видим, достичь последней точки функции, перед именем которой стоит ключевое слово
void
, вполне возможно. Это эквивалентно инструкции
return;
.
8.5.3. Передача параметров по значению
Простейший способ передать аргумент функции заключается в пересылке копии его значения. Аргумент функции
f
является локальной переменной, которая инициализируется при каждом ее вызове. Рассмотрим пример.
// передача по значению (функция получает копию передаваемого
// значения)
int f(int x)
{
x = x+1; // присваиваем локальной переменной x новое значение
return x;
}
int main
{
int xx = 0;
cout << f(xx) << endl; // вывод: 1
cout << xx << endl; // вывод: 0; функция f не изменяет xx
int yy = 7;
cout << f(yy) << endl; // вывод: 8
cout << yy << endl; // вывод: 7; функция f не изменяет yy