(d) char *screenInit( int height = 24, int width,
char background );
(e) void putValues( int (ia)[] );
Повторные объявления всех приведенных ниже функций содержат ошибки. Найдите их.
(a) char *screenInit( int height, int width,
char background = ' ' );
char *screenInit( int height = 24, int width,
char background );
(b) void print( int (*arr)[6], int size );
void print( int (*arr)[5], int size );
(c) void manip( int *pi, int first, int end = 0 );
void manip( int *pi, int first = 0, int end = 0 );
Даны объявления функций.
void print( int arr[][5], int size );
void operate(int *matrix[7]);
char *screenInit( int height = 24, int width = 80,
char background = ' ' );
Вызовы этих функций содержат ошибки. Найдите их и объясните.
(a) screenInit();
(b) int *matrix[5];
operate( matrix );
(c) int arr[5][5];
print( arr, 5 );
Перепишите функцию putValues( vectorint ), приведенную в подразделе 7.3.4, так, чтобы она работала с контейнером liststring. Печатайте по одному значению на строке. Вот пример вывода для списка из двух строк:
( 2 )
"first string"
"second string"
Напишите функцию main(), вызывающую новый вариант putValues() со следующим списком строк:
"put function declarations in header files"
"use abstract container types instead of built-in arrays"
"declare class parameters as references"
"use reference to const types for invariant parameters"
"use less than eight parameters"
В каком случае вы применили бы параметр-указатель? А в каком – параметр-ссылку? Опишите достоинства и недостатки каждого способа.
7.4. Возврат значения
В теле функции может встретиться инструкция return. Она завершает выполнение функции. После этого управление возвращается той функции, из которой была вызвана данная. Инструкция return может употребляться в двух формах:
return;
return expression;
Первая форма используется в функциях, для которых типом возвращаемого значения является void. Использовать return в таких случаях обязательно, если нужно принудительно завершить работу. (Такое применение return напоминает инструкцию break, представленную в разделе 5.8.) После конечной инструкции функции подразумевается наличие return. Например:
void d_copy( double "src, double *dst, int sz )
{
/* копируем массив "src" в "dst"
* для простоты предполагаем, что они одного размера
*/
// завершение, если хотя бы один из указателей равен 0
if ( !src || !dst )
return;
// завершение,
// если указатели адресуют один и тот же массив
if ( src == dst )
return;
// копировать нечего
if ( sz == 0 )
return;
// все еще не закончили?
// тогда самое время что-то сделать
for ( int ix = 0; ix sz; ++ix )
dst[ix] = src[ix];
// явного завершения не требуется
}
Во второй форме инструкции return указывается то значение, которое функция должна вернуть. Это значение может быть сколь угодно сложным выражением, даже содержать вызов функции. В реализации функции factorial(), которую мы рассмотрим в следующем разделе, используется return следующего вида:
return val * factorial(val-1);
В функции, не объявленная с void в качестве типа возвращаемого значения, обязательно использовать вторую форму return, иначе произойдет ошибка компиляции. Хотя компилятор не отвечает за правильность результата, он сможет гарантировать его наличие. Следующая программа не компилируется из-за двух мест, где программа завершается без возврата значения:
// определение интерфейса класса Matrix
#include "Matrix.h"
bool is_equa1( const Matrix ml, const Matrix m2 )
{
/* Если содержимое двух объектов Matrix одинаково,
* возвращаем true;
* в противном случае - false
*/
// сравним количество столбцов
if ( ml.colSize() != m2.co1Size() )
// ошибка: нет возвращаемого значения
return;
// сравним количество строк
if ( ml.rowSize() != m2.rowSize() )
// ошибка: нет возвращаемого значения
return;
// пробежимся по обеим матрицам, пока
// не найдем неравные элементы
for ( int row = 0; row ml.rowSize(); ++row )
for ( int col = 0; co1 ml.colSize(); ++co1 )
if ( ml[row][col] != m2[row][col] )
return false;
// ошибка: нет возвращаемого значения
// для случая равенства
}
Если тип возвращаемого значения не точно соответствует указанному в объявлении функции, то применяется неявное преобразование типов. Если же стандартное приведение невозможно, происходит ошибка компиляции. (Преобразования типов рассматривались в разделе 4.1.4.)