Главная страница

Язык Си - Уэйт, Прата, Мартин. M. уэит с. Прата д. Мартин


Скачать 4.69 Mb.
НазваниеM. уэит с. Прата д. Мартин
АнкорЯзык Си - Уэйт, Прата, Мартин.pdf
Дата15.03.2018
Размер4.69 Mb.
Формат файлаpdf
Имя файлаЯзык Си - Уэйт, Прата, Мартин.pdf
ТипПрограмма
#16711
страница22 из 42
1   ...   18   19   20   21   22   23   24   25   ...   42
count равно 0, элементу массива score[0] присваивается величина переменной
temp, а затем count возрастает на 1. После каждой итерации цикла while величина счетчика count
становится на единицу больше последнего использованного индекса массива. Это как раз то, что
173
нам нужно, поскольку score[0] - первый элемент, score[20] - 2-й элемент и т. д. Когда работа цикла в программе завершается, значение count оказывается равным полному чиcлу прочитанных элементов данных. Затем величина count используется в качестве верхней границы числа итераций для последующих циклов.
Этот алгоритм хорошо работает, пока у нас имеется запас таких чисел, которые никогда не будут вводиться как данные. Но что делать, если мы захотим иметь программу, допускающую ввод в качестве данных любых чисел, относящихся к некоторому определенному типу? В таком случае мы не сможем использовать ни одно из чисел как признак конца ввода.
Мы столкнулись с аналогичной проблемой, когда искали подходящий символ для признака
End-of-File. Тогда было принято решение использовать для ввода символов специальную функцию(getchar( )), которая при обращении к ней фактически возвращала величину типа int. Это позволяло функции читать "символ" EOF, который на самом деле не был обычным символом. В
рассматриваемом нами примере полезной оказалась бы функция, которая осуществляла бы ввод целых чисел, могла бы, кроме того, читать данные не только целого типа, но и использовать их в качестве признака конца ввода.
Мы можем одновременно и обрадовать и огорчить вас: такое решение оказывается возможным,
но вы должны узнать несколько больше о работе функций; поэтому обсуждение данной идеи откладывается до гл. 10.
РЕЗЮМЕ
Далее
Содержание
Основной темой данной главы было обсуждение возможностей управления ходом выполнения программы. Язык Си предоставляет много средств для структурирования программ. С помощью операторов while и for реализуются циклы с предусловием. Второй оператор особенно подходит для циклов, включающих в себя инициализацию и коррекцию переменной. Использование операции "запятая" в цикле for позволяет инициализировать и корректировать более одной переменной. Для тех редких случаев, когда требуется использовать цикл с постусловием, язык Си предоставляет оператор do while. Операторы break, continue и goto обеспечивают дополнительные возможности управления ходом выполнения программы.
Мы обсудили здесь также и понятие массива. Массивы в программе описываются так же, как обычные переменные, но при этом в квадратных скобках указывается число элементов. Первому элементу массива присваивается номер 0, второму - номер 1 и т. д. Индексы, используемые для нумерации элементов массива, могут обрабатываться обычным образом при помощи циклов.
ЧТО ВЫ ДОЛЖНЫ БЫЛИ УЗНАТЬ В ЭТОЙ ГЛАВЕ
Далее
Содержание
Три типа циклов в языке Си: while, for и do while.
Различие между циклами с предусловием и с постусловием.
Почему циклы с предусловием используются гораздо чаще, чем циклы с постусловием.
Дополнительные операции присваивания: += -= *= /= %=.
Как пользоваться операцией "запятая".
Когда использовать операторы break и continue: по возможности редко.
Когда использовать оператор goto: когда вы хотите иметь неудобные, трудные для понимания программы.
Как использовать оператор while для защиты программы от ошибок при вводе данных.
Что такое массив и как его описать: long arms[8].
ВОПРОСЫ И ОТВЕТЫ
Далее
Содержание
174

Вопросы
1. Определите значение переменной quack после выполнения каждого оператора из приведенной ниже их послесдовательности.
int quack = 2;
quack + = 5;
quack * = 10;
quack - = 6;
quack / = 8;
quack % = 3;
2. Что будет получено на выходе в результате работы следующего цикла?
for(value = 36; value > 0; value /= 2) printf("%3d", value);
3. Как можно модифицировать операторы if в программе угадывание числа2 чтобы был возможен ввод как прописных, так и строчных букв?
4. Мы подозреваем, что следующая программа не совсем правильная. Какие ошибки вы сможете в ней обнаружить?
main( ) /* строка 1 */
{ /* строка 2 */
int i, j, lisl[10]; /* строка 3 */
for (i = 1, i < = 10, i++ ) /* строка 5 */
{ /* строка 6 */
list[i] = 2*i + 3; /* строка 7 */
for(j = 1, j >= i, j++ ) /* строка 8 */
printf(" %d \n", lisl[j]); /* строка 9 */
} /* строка 10 */
5. Воспользуйтесь пложенными циклами при написании программы, выводящей на печать следующую фигуру:
$$$$$$$$ $$$$$$$$ $$$$$$$$ $$$$$$$$
6. Напишите программу, которая создает массив из 26 элементов и помещает в него 26 строчных букв.
Ответы
1. 2, 7, 70, 64, 8, 2 2. 36 18 9 4 2 1.
Вспомните, как выполняется деление целых чисел. Результатом деления 1 на 2 будет 0, поэтому работа цикла завершится после того, как переменная value станет равной 1.
3. if(response == 'б' || response == 'Б').
4. строка 3: должно быть list[10].
строка 5: вместо запятых должны стоять символы "точка с запятой".
строка 5: переменная i должна изменяться в диапазоне от 0 до 9, а не от 1 до 10.
строка 8: вместо запятых должны стоять символы "точка с запятой".
строка 8: знак >= должен быть заменен на <=. В противном случае при значении i, равном 1,
цикл никогда не завершится.
175
строка 10: между строками 9 и 10 должна находиться еще одна закрывающая фигурная скобка.
Одна скобка закрывает составной оператор, а другая тело программы.
5.
main( )
{ int i, j;
for(i = 1; i <= 4; i++)
{
for( j = 1; j <= 8; j++)
printf("$");
}
printf("\N");
}
6.
main( )
{ int i;
char ch, alpha[26];
for(i = 0, ch = 'a'; i <= 26; i++, ch++)
alpha[i] == ch;
}
УПРАЖНЕНИЯ
Содержание
1. Модифицируйте программу угадывание числа2 в соответствии с нашими предположениями об улучшении ее работы.
2. Реализуйте наше предложение о повышении эффективности pаботы программы нахождения
простых чисел.
3. Воспользуйтесь вложенными циклами при написании программы, выводящей на печать следующую фигуру:
$
$$
$$$
$$$$
$$$$$
1)
Валентин(а) - возлюбленный (возлюбленная), выбираемые в день св. Валентина, 14 февраля.- Прим. перев.
2)
Зеион Элейскии (ок. 490-430 до н.э.) - древнегреческий философ. Известен своими знаменитыми парадоксами
(апориями).- Прим. перев.
3)
Читатель должен понимать, что философский смысл апории Зенона о стреле не исчерпывается приведенными выше рассуждениями.- Прим. перев.
176

ФУНКЦИИ
СТРОИТЕЛЬНЫЕ БЛОКИ ПРОГРАММЫ
СВЯЗЬ МЕЖДУ ФУНКЦИЯМИ: АРГУМЕНТЫ, УКАЗАТЕЛИ, ВОЗВРАТ ЗНАЧЕНИЯ
ТИПЫ ФУНКЦИЙ
КЛЮЧЕВОЕ СЛОВО
return
Принципы программирования на языке Си основаны на понятии функции. В представленных ранее примерах программирования мы уже воспользовались несколькими функциями: printf( ),
scanf( ), getchar( ), putchar( ) и strlen( ). Эти функции являются системными, однако мы создали и несколько своих собственных функций под общим именем main( ). Выполнение программы всегда начинается с команд, содержащихся в функции main( ), затем последняя вызывает другие функции,
например getchar( ). Теперь мы переходим к вопросу о том, как создавать свои собственные функции н делать их доступными для функции main( ), а также друг для друга.
Во-первых, что такое функция? Функция - самостоятельная единица программы,
спроектированная для реализации конкретной задачи. Функции в языке Си играют ту же роль, какую играют функции, подпрограммы и процедуры в других языках, хотя детали их структуры могут быть разными. Вызов функции приводит к выполнению некоторых действии. Например, при обращении к функции printf( ) осуществляется вывод данных на экран. Другие же функции позволяют получать некоторую величину, используемую затем в программе. К примеру, функция strlen( ) "сообщает"
программе длину конкретной строки. В общем функции могут выполнять действия и получать значения величин, используемых в программе.
Почему мы пользуемся функциями? Во-первых, они избавляют нас от повторного программирования. Если конкретную задачу необходимо выполнить в программе несколько раз, мы напишем соответствующую функцию только один раз, а затем будем вызывать ее всегда, когда это требуется. Во-вторых, мы можем применять одну функцию, например putchar( ), в различных программах. Даже в том случае, если некоторая задача выполняется только в одной программе,
лучше оформить ее решение в виде функции, поскольку функции повышают уровень модульности программы и, следовательно, облегчают ее чтение, внесение изменений и коррекцию ошибок.
Предположим, например, что мы хотим написать программу, которая делает следующее:вводит набор чисел сортирует, эти числа, находит их среднее, выводит на печать гистограмму.
Соответствующую программу можно записать так:
main( )
{
float list [50];
readlist(list);
sort(list);
average(list);
bargrapli(list);
}
Разумеется, мы должны были бы запрограммировать четыре функции readlist( ), sort( ), average( )
и bargraph( ), но... это уже детали. Используя смысловые имена функции, мы четко определяем,
что программа делает и как она организована. После этого можно заниматься каждой функцией отдельно и совершенствовать ее до тех пор, пока она не будет правильно выполнять требуемую задачу. Дополнительное преимущество указанного подхода заключается в том, что если мы создадим функции достаточно общего вида, то их можно будет использовать и в других программах.
Многие программисты предпочитают думать о функции, как о "черном ящике"; они задают ее через поступающую информацию (вход) и полученные результаты (выход). Все, что происходит внутри черного ящика, их не касается до тех пор, пока не нужно писать программу, реализующую
177
эту функцию. Когда мы используем, например, функцию printf( ), мы знаем, что должны передать ей управляющую строку и возможно, несколько аргументов. Мы знаем также результат вы зова функций printf( ). He нужно полагать, что при программнровании вам придется заниматься созданием функции printf( ). Использование функций указанным выше способом позволяет сконцентрироват внимание на обшей структуре программы, а не на деталях.
Что нам требуется знать о функциях? Нужно знать, как их можно определять, как к ним обращаться и как устанавливать связи между функцией и программой, ее вызывающей. Чтобы изучить это, мы рассмотрим очень простои пример, а затем будем обобщать его, вводя дополнительные характеристики до тех пор, пока не получим полную и ясную картину.
СОЗДАНИЕ И ИСПОЛЬЗОВАНИЕ ПРОСТОЙ ФУНКЦИИ
Далее
Содержание
Наша первая скромная цель - создание функции, которая печатает 65 символов * в ряд. Чтобы эта функция выполнялась в некотором контексте, мы включили ее в программу, которая печатает простой титул фирменного бланка. Ниже приведена полная соответствуюшая программа. Она состоит из функции main( ) и starbar( ).
/* титул фирменного бланка! */
#define NAME "MEGATHINK, INC."
#define ADDRESS "10 Megabuck Plaza"
#define PLACE "Megapolis, CA 94904"
main( )
{
starbar( );
printf("%s\n", NAME); printf(" %s\n", ADDRESS);
printf("%s\n", PLACE);
starbar( );
}
/* далее следует функция starbar( ) */
#include
#define LIMIT 65 starbar( );
{ int count; for (count = 1; count <= LIMIT; count++)
putchar('*'); putchar('\n');
}
Результат работы программы выглядит так:
***********************************************************
MEGATHINK, INC 10 Megabuck Plaza Megapolis, CA 94904
***********************************************************
При рассмотрении этой программы необходимо обратить внимание на следующие моменты:
1. Мы вызвали функцию starbar( ) (или, можно сказать, обратились к ней) из функции main( ),
используя только ее имя. Это несколько напоминает заклинание, вызывающее злого духа, но,
вместо того чтобы чертить пятиугольник, мы помещаем вслед за именем функции точку с запятой,
создавая таким образом оператор: starbar( );
178

РИС. 9.1. Схема выполнения операторов программы титул "фирменною бланка 1".
Это одна из форм вызова функции, но далеко не единственная. Когда в процессе выполнения программы компьютер достигает оператора starbar( ), он находит указанную функцию, после чего начинает выполнять соответствующие ей команды. Затем управление возвращается следующей строке "вызывающе" программы" - в данном случае main( ).
2. При написании функции starbar( ) мы следовали тем же правилам, что и при написании main(
): вначале указывается имя, затем идет открывающая фигурная скобка, приводится описание используемых переменных, даются операторы, определяющие работу функции, и, наконец,
закрывающая фигурная скобка. Мы даже поместили перед описанием функции starbar( ) директивы
#define и #include, требующиеся для нее, а не для функции main( ).
179

РИС. 9.2. Структура простой функции.
3. Мы включили функции starbar() и main() в один файл. Вообще говоря, можно было создать два отдельных файла. Один файл несколько упрощает компиляцию, а два отдельных файла облегчают использование одной функции в разных программах. Случай двух и более файлов мы обсудим позже, а пока будем держать все наши функции в одном месте. Закрывающая фигурная скобка функции main( ) указывает компилятору на се конец. Круглые скобки в имени starbar( )
говорят о том, что starbar( ) - это функция. Обратите внимание, что здесь за именем starbar( ) не следует символ "точка с запятой"; его отсутствие служит указанием компилятору, что мы
определяем функцию starbar( ), а не используем ее.
Если рассматривать функцию starbar( ) как черный ящик, то ее выход - это напечатанная строка,
состоящая из символов *. Какие бы то ни было данные на входе у нее отсутствуют, потому что eй не нужно использовать информацию из вызывающей программы. Вообще, этой функции не требуется связь с вызывающей программой. Обратимся к случаю, когда такая связь необходима.
АРГУМЕНТЫ ФУНКЦИИ
Далее
Содержание
Титул фирменного бланка выглядел бы несколько лучше, если бы текст был сдвинут к центру.
Мы сможем поместить текст в центре, если напечатаем нужное число пробелов перед выводом требуемой строки. Воспользуемся некоторой функцией для печати пробелов. Наша функция space(
) (давайте назовем ее так) будет очень напоминать функцию starbar( ), за исключением того, что на этот раз между функцией main( ) и функцией space( ) должна быть установлена связь, так как необходимо сообщить последней функции о требуемом числе пробелов.
Рассмотрим это более конкретно. В строке, состоящей из звездочек, 65 символов, а в строке
MEGATHINK, INC. - 15. Поэтому в нашем первом варианте программы вслед за этим сообщением шло 50 пробелов. Чтобы сместить текст к центру, нужно сначала напечатать 25 пробелов, а потом текст, в результате чего слева и справа от данной фразы окажется по 25 пробелов. Следовательно,
необходимо иметь возможность передать величину "25" функции, печатающей пробелы. Мы применяем тот же способ, что и при передаче символа '*' функции putchar( ): используем аргумент.
Тогда запись space(25) будет означать, что необходимо напечатать 25 пробелов. 25 - это аргумент.
Мы будем вызывать функцию space( ) три раза: один раз для каждой строки адреса. Вот как
180
выглядит эта программа:
/* титул фирменного бланка2 */
#define NAME "MEGATHINK, INC."
#define ADDRESS "10 Megabuck Plaza"
#define PLACE "Mcgapolis, CA 94904"
main( )
{
int spaces;
starbar( );
space(25); /* space( ) использует в качестве аргумента константу */
printf("%s\n", NAME);
spaces = (65 - strlen(ADDRESS))/2;
/* мы заставляем программу вычислять, сколько пропустить пробелов */
space(spaces); /* аргументом является переменная */
printf("%s\n", ADDRESS);
space((65 - strlen(PLACE))/2); /* аргументом является выражение */
printf(" %s \n", PLACE);
starbar( );
}
/ *определение функции starbar( ) */
#include
#define LIMIT 65
starbar( )
{
int count;
for (count = 1;count <= LIMIT;count++) putchar('*');
putchar('\n');
}
/* определение функции space( ) */
space(number)
int number; /* аргумент описывается перед фигурной скобкой */
{
int count /* дополнительная переменная описывается после фигурной скобки */
for (count = 1;count <= number;count++) putchar(' ');
}
РИС. 9.3. Программа, печатающая титул фирменного бланка.
Обратите внимание на то, как мы экспериментировали при вы зовах функции space( ): мы задавали аргумент тремя различными способами. Являются ли все они работоспособными? Да - и вот доказательство.
*********************************************************************
MEGATHINK, INC.
10 Megabuck Plaza
Megapolis, CA 94904
*********************************************************************
Рассмотрим сначала, как определить функцию с одним аргументом, после чего перейдем к вопросу о том, как она используется.
Определение функции с аргументом:
формальные аргументы
Далее
Содержание
Определение нашей функции начинается с двух строк:
space(number)
181
int number;
Первая строка информирует компилятор о том, что у функции space( ) имеется аргумент и что его имя number. Вторая строка - описание, указывающее компилятору, что аргумент number имеет тип
int. Обратите внимание: аргумент описывается перед фигурной скобкой, которая отмечает начало тела функции. Вообще говоря, вы можете объединить эти две строки в одну:
space(int number;)
Независимо от формы записи переменная
1   ...   18   19   20   21   22   23   24   25   ...   42


написать администратору сайта