Это гарантирует, что при любом вызове printf() ей будет передан первый аргумент типа const char*. Содержание такой строки, называемой форматной, определяет, необходимы ли дополнительные аргументы при вызове. При наличии в строке формата метасимволов, начинающихся с символа %, функция ждет присутствия этих аргументов. Например, вызов
printf( "hello, world\n" );
имеет один строковый аргумент. Но
printf( "hello, %s\n", userName );
имеет два аргумента. Символ % говорит о наличии второго аргумента, а буква s, следующая за ним, определяет его тип – в данном случае символьную строку.
Большинство функций с многоточием в объявлении получают информацию о типах и количестве фактических параметров по значению явно объявленного параметра. Следовательно, первый формат многоточия употребляется чаще.
Отметим, что следующие объявления неэквивалентны:
void f();
void f( ... );
В первом случае f() объявлена как функция без параметров, во втором – как имеющая ноль или более параметров. Вызовы
f( someValue );
f( cnt, a, b, с );
корректны только для второго объявления. Вызов
f();
применим к любой из двух функций.
Какие из следующих объявлений содержат ошибки? Объясните.
(a) void print( int arr[][], int size );
(b) int ff( int a, int b = 0, int с = 0 );
(c) void operate( int *matrix[] );
(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;
// завершение,