- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Язык Си - руководство для начинающих - M. УЭИТ
Шрифт:
Интервал:
Закладка:
4. Если нет, выдать предупреждение.
Этот план так хорош, что он должен работать. (Тот факт, что он представляет собой стандартный подход, существовавший на протяжении многих лет, придает нам также некоторую уверенность в возможности его выполнения. Но, прежде чем начать программировать, нужно подумать, что будет делать наша функция.
В частности, до того как мы займемся содержанием нашей функции getint( ), нужно точно решить, как она должна взаимодействовать со своим окружением: с какой информацией? Какую информацию она должна получать от вызывающей программы? Какую информацию должна возвращать? В каком виде должна быть эта информация? Снова мы рассматриваем функцию как черный ящик. Мы хотим знать, что входит в функцию и что выходит из нее и, наконец, что находится внутри ее. Этот подход помогает обеспечивать более однородное взаимодействие между различными частями программы. Иначе вы можете оказаться в положении человека, пытающегося установить трансмиссию автомашины "Волво" в автомобиль "Тойота". Сама функция правильная, но интерфейс является проблемой.
Поток информации для getint( )
Какой выход должна иметь наша функция? Во-первых, несомненно, что она должна была бы выдавать значение прочитанного числа. Конечно, функция scanf( ) уже делает так. Во-вторых, и это очень существенно, мы собираемся создать такую функцию, которая будет выдавать сообщения о состоянии, т. е. найдено или нет целое число. Чтобы функция была действительно полезной, она должна также сообщать о нахождении ею символа EOF. Тогда мы могли бы использовать функцию getint( ) в цикле while, который читает целые числа до тех пор, пока не обнаружит символ EOF. Короче говоря, нам нужно, чтобы getint( ) возвращала два значения: целое числе и состояние.
Так как мы хотим иметь два значения, то с одной функцией return с этой задачей нам не справиться. Нам следует иметь два указателя. Однако полное решение задачи мы получим, если используем указатели для выполнения основной работы функции и функцию return для выдачи некоторого кода состояния. Именно это и делает функция scanf( ). Она возвращает количество символов, которые нашла, и символ EOF, если встречает его. Ранее мы не пользовались такой возможностью, но могли бы, если бы применяли вызов вида
status = scanf(" % d", &number);
Теперь будем это делать. Тогда наш вызов функции выглядел бы следующим образом:
status = getint(&number);
Правая часть равенства использует адрес переменной number, чтобы получить ее значение, a returnприменяется для получения значения переменной status.
РИС. 10.2. Создание функции getint( )
Мы должны выбрать коды для выдачи сообщения о состоянии. Так как предполагается, что неописанные функции имеют тип int, наши коды должны состоять из целых чисел. Используем следующие коды для сообщения о состоянии:
-1 означает, что найден символ EOF.
1 означает, что найдена строка, содержащая не цифры.
0 означает, что найдена строка, содержащая только цифры.
Нашу функцию getint( ) можно представить себе (рис. 10.2) как имеющую один вход и два выхода. На ее вход поступает адрес целой переменной, значение которой считывается. На первом выходе имеем значение считанного целого, полученного через указатель. (Таким образом, аргумент-указатель является двусторонним каналом передачи информации.) На втором выходе получаем код состояния, что обеспечивается функциейreturn. Отсюда следует, что "скелет" нашей функции должен выглядеть примерно так:
getint(ptint)
int *ptint; /* указатель на целое число */
{
int status;
...
return (status);
}
Замечательно! Теперь мы должны просто заполнить внутренность функции.
Содержание getint( )
Наш основной план для getint( ) в общих чертах на псевдокоде выглядит примерно так:
читаем на входе информацию в виде символов
помещаем символы в строку, пока не встретим символ EOF
если встретился символ EOF, устанавливаем состояние в STOP
в противном случае проверяем строку,
преобразуем символы в целое число, если возможно, и выдаем сообщение о состоянии (YESNUM или NONUM).
Здесь мы используем STOP, YESNUM и NONUM как символические константы, равные -1, 0 и 1, как описано выше.
Рассмотрим еще некоторые вопросы. Как функция будет решать, что она достигла конца входной строки? Должны ли мы ограничивать длину строки?
Мы вошли в область, где нам предстоит решать, что предпочесть: удобство программиста или удобство пользователя. Самым простым было бы предложить пользователю нажимать на клавишу [ввод], когда строку надо закончить. Это означало бы один ввод на строку. Для пользователя все же было бы приятнее, если бы функция могла размещать несколько чисел в одной и той же строке:
2 34 4542 2 98
Мы решили предоставить привилегию пользователю. Пусть функция будет считать, что строка начинается с символа, не являющегося пробелом или "новой строкой", и заканчивается символом пробела или "новой строкой". Такой ввод может производиться в одну строку или в несколько строк.
Мы ограничим вводимую строку 80 символами. Так как строки заканчиваются нуль-символом, нам нужен массив из 81 символа для включения в него этого символа. Это слишком щедро, потому что нам нужно только 6 символов для 16-разрядного целого числа и знака. Вы можете вводить более длинные числа, но их размер будет сокращен до размера строки.
Чтобы сделать программу более модульной, мы поручим преобразование "строка в целое число" другой функции, и назовем ее stoi( ). У нас будет также возврат функцией stoi( ) соответствующего кода состояния в функцию getint( ), a getint( ), в свою очередь, может передать код состояния своей вызывающей программе. Функция stoi( ) выполнит последние две строки нашего плана (на псевдокоде).
Рис. 10.3 представляет программу для функции getint( );. Функция stoi( ) будет показана позже:
/* getint( ) */
#include
#define LEN 81 /* максимальная длина строки */
#define STOP-1 /* коды состояний */
#define NONUM 1
#define YESNUM О
getint(ptint)
int *ptint; /* указатель на вывод целого числа */
{
char intarr[LEN]; /* запоминание вводимой строки */
int ch;
int ind = 0; /* индекс массива */
while((ch = getchar( )) = = 'n' || ch == ' ' || ch == 't');
/* обход начальных символов "новая строка", пробелов и табуляций */
while(ch != EOF && ch != 'n' && ch != ' ' && ind < LEM)
{
intarr[ind++] = ch; /* запись символа в массив */
ch = getchar( ); /* получение очередного символа */
}
intarr[ind] = ' '; /* конец массива по нуль-символу */
if(ch == EOF)
return(STOP);
else
return(stoi(intarr, ptint) ); /* выполнение преобразования */
}
РИС. 10.3. Программа функции getint( )
Мы получаем символ сh. Если он является символом пробела, или "новой строки", или табуляции, мы берем следующий символ и так продолжаем до тех пор, пока не получим символ, отличающийся от перечисленных. Затем, если этот символ не EOF, помещаем его в массив. Продолжаем брать символы и помещать их в массив, пока не найдем запрещенный символ или не достигнем предельного размера строки. Далее помещаем нуль-символ (' ') в следующую позицию массива, чтобы отметить конец строки. Таким образом, мы создали массив в виде стандартной символьной строки. Если EOF был последним прочитанным символом, возвращаем STOP; иначе идем дальше и пытаемся преобразовать строку. Мы вызываем новую функцию stoi( ), чтобы выполнить эту работу. Что делает stoi( )? При вводе она берет символьную строку и указатель на целую переменную, использует указатель для присваивания значения самой переменной, а также return для пересылки сообщения о состоянии, которое getint( ) передает затем функции getarray( ). Поразительно! Двойная игра! Вот менее компактный способ использования функции stoi( ):
status = stoi(intarr, print);
return (status);
Здесь status была бы переменной типа int. Первый оператор дает значение, на которое указывает ptint; она также присваивает значение переменной status. Второй оператор возвращает это значение программе, которая вызвала getint( ). Наша единственная строка программы имеет точно такой же эффект, за исключением того, что нам не нужна промежуточная переменная status. Теперь напишем функцию stoi( ).

