Главная » Просмотр файлов » Керниган и Ритчи - Язык программирования Си

Керниган и Ритчи - Язык программирования Си (793773), страница 21

Файл №793773 Керниган и Ритчи - Язык программирования Си (Керниган и Ритчи - Язык программирования Си) 21 страницаКерниган и Ритчи - Язык программирования Си (793773) страница 212019-04-24СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 21)

Если в объявлении функции аргументы не указаны,как вdouble atof();то и в этом случае считается, что ничего об аргументах atof не известно, и все проверки на соответствие еепараметров будут выключены. Предполагается, что такая специальная интерпретация пустого спискапозволит новым компиляторам транслировать старые Си-программы. Но в новых программах пользоватьсяэтим — не очень хорошая идея. Если у функции есть аргументы, опишите их, если их нет, используйте словоvoid.Располагая соответствующим образом описанной функцией atof, мы можем написать функцию atoi,преобразующую строку символов в целое значение, следующим образом:/* atoi: преобразование строки s в int с помощью atof */int atoi (char s[]){double atof (char s[]);return (int) atof (s);}Обратите внимание на вид объявления и инструкции return.

Значение выражения вreturn выражение;перед тем, как оно будет возвращено в качестве результата, приводится к типу функции. Следовательно,поскольку функция atoi возвращает значение int, результат вычисления atof типа double в инструкцииreturn автоматически преобразуется в тип int.

При преобразовании возможна потеря информации, инекоторые компиляторы предупреждают об этом. Оператор приведения явно указывает на необходимостьпреобразования типа и подавляет любое предупреждающее сообщение.Упражнение 4.2. Дополните функцию atof таким образом, чтобы она справлялась с числами вида123.456e-6в которых после мантиссы может стоять е (или Е) с последующим порядком (быть может, со знаком).4.3.

Внешние переменныеПрограмма на Си обычно оперирует с множеством внешних объектов: переменных и функций.Прилагательное "внешний" (external) противоположно прилагательному "внутренний", которое относится каргументам и переменным, определяемым внутри функций. Внешние переменные определяются внефункций и потенциально доступны для многих функций. Сами функции всегда являются внешнимиобъектами, поскольку в Си запрещено определять функции внутри других функций. По умолчаниюодинаковые внешние имена, используемые в разных файлах, относятся к одному и тому же внешнемуобъекту (функции). (В стандарте это называется редактированием внешних связей (external linkage7).) В этомсмысле внешние переменные похожи на области COMMON в фортране и на переменные самого внешнегоблока в Паскале. Позже мы покажем, как внешние функции и переменные сделать видимыми только внутриодного исходного файла.Поскольку внешние переменные доступны всюду, их можно использовать в качестве связующих данныхмежду функциями как альтернативу связей через аргументы и возвращаемые значения.

Для любой функциивнешняя переменная доступна по ее имени, если это имя было должным образом объявлено.7Сейчас уже и в русский язык прочно вошло слово "линкование". — Примеч. ред.Если число переменных, совместно используемых функциями, велико, связи между последними черезвнешние переменные могут оказаться более удобными и эффективными, чем длинные списки аргументов.Но, как отмечалось в главе 1, к этому заявлению следует относиться критически, поскольку такая практикаухудшает структуру программы и приводит к слишком большому числу связей между функциями по данным.Внешние переменные полезны, так как они имеют большую область действия и время жизни.Автоматические переменные существуют только внутри функции, они возникают в момент входа в функцию иисчезают при выходе из нее.

Внешние переменные, напротив, существуют постоянно, так что их значениясохраняются и между обращениями к функциям. Таким образом, если двум функциям приходитсяпользоваться одними и теми же данными и ни одна из них не вызывает другую, то часто бывает удобнооформить эти общие данные в виде внешних переменных, а не передавать их в функцию и обратно черезаргументы.В связи с приведенными рассуждениями разберем пример.

Поставим себе задачу написать программукалькулятор, понимающую операторы +, -, * и /. Такой калькулятор легче будет написать, еслиориентироваться на польскую, а не инфиксную запись выражений. (Обратная польская запись применяется внекоторых карманных калькуляторах и в таких языках, как Forth и Postscript.)В обратной польской записи каждый оператор следует за своими операндами. Выражение в инфикснойзаписи, скажем(1 - 2) * (4 + 5)в польской записи представляется как1 2 - 4 5 + *Скобки не нужны, неоднозначности в вычислениях не бывает, поскольку известно, сколько операндовтребуется для каждого оператора.Реализовать нашу программу весьма просто. Каждый операнд посылается в стек; если встречается оператор,то из стека берется соответствующее число операндов (в случае бинарных операторов два) и выполняетсяоперация, после чего результат посылается в стек.

В нашем примере числа 1 и 2 посылаются в стек, затемзамещаются на их разность -1. Далее в стек посылаются числа 4 и 5, которые затем заменяются их суммой (9).Числа -1 и 9 заменяются в стеке их произведением (т. е. -9). Встретив символ новой строки, программаизвлекает значение из стека и печатает его.Таким образом, программа состоит из цикла, обрабатывающего на каждом своем шаге очереднойвстречаемый оператор или операнд:while (следующий элемент не конец-файла)if (число)послать его в стекelse if (оператор)взять из стека операндывыполнить операциюрезультат послать в стекelse if (новая-строка)взять с вершины стека число и напечататьelseошибкаОперации "послать в стек" и "взять из стека" сами по себе тривиальны, однако по мере добавления к ниммеханизмов обнаружения и нейтрализации ошибок становятся достаточно длинными.

Поэтому их лучшеоформить в виде отдельных функций, чем повторять соответствующий код по всей программе. И конечнонеобходимо иметь отдельную функцию для получения очередного оператора или операнда.Главный вопрос, который мы еще не рассмотрели, — это вопрос о том, где расположить стек и какимфункциям разрешить к нему прямой доступ. Стек можно расположить в функции main и передавать сам стеки текущую позицию в нем в качестве аргументов функциям push ("послать в стек") и pop ("взять из стека").Но функции main нет дела до переменных, относящихся к стеку, — ей нужны только операции по помещениючисел в стек и извлечению их оттуда.

Поэтому мы решили стек и связанную с ним информацию хранить вовнешних переменных, доступных для функций push и pop, но не доступных для main.Переход от эскиза к программе достаточно легок. Если теперь программу представить как текст,расположенный в одном исходном файле, она будет иметь следующий вид:#include /* могут быть в любом количестве */#define /* могут быть в любом количестве */объявления функций для mainmain () {...}внешние переменные для push и popvoid push (double f) {...}double pop (void) {...}int getop(char s[] ) {...}подпрограммы, вызываемые функцией getopПозже мы обсудим, как текст этой программы можно разбить на два или большее число файлов.Функция main — это цикл, содержащий большой переключатель switch, передающий управление на ту илииную ветвь в зависимости от типа оператора или операнда.

Здесь представлен более типичный случайприменения переключателя switch по сравнению с рассмотренным в параграфе 3.4.#include <stdio.h>#include <stdlib.h> /* для atof() */#define MAXOP 100 /* макс. размер операнда или оператора */#define NUMBER '0' /* признак числа */int getop (char []);void push (double);double pop (void);/* калькулятор с обратной польской записью */main (){int type;double op2;char s[MAXOP];while ((type = getop (s)) != EOF) {switch (type) {case NUMBER:push (atof (s));break;case '+':push (pop() + pop());break;case '*':push (pop() * pop());break;case '-':op2 = pop();push (pop() - op2);break;case '/' :op2 = pop();if (op2 != 0.0)push (pop() / op2);elseprintf("ошибка: деление на нуль\п");break;case '\n' :printf("\t%.8g\n", pop());break;default:printf("ошибка: неизвестная операция %s\n", s);break;}}return 0;}Так как операторы + и * коммутативны, порядок, в котором операнды берутся из стека, не важен, однако вслучае операторов - и /, левый и правый операнды должны различаться.

Так, вpush(pop() - рор()); /* НЕПРАВИЛЬНО */очередность обращения к pop не определена. Чтобы гарантировать правильную очередность, необходимопервое значение из стека присвоить временной переменной, как это и сделано в main.#define MAXVAL 100 /* максимальная глубина стека */int sp = 0; /* следующая свободная позиция в стеке */double val[ MAXVAL ]; /* стек *//* push: положить значение f в стек */void push(double f){if (sp < MAXVAL)val[sp++] = f;elseprintf( "ошибка: стек полон, %g не помещается\п", f);}/* pop: взять с вершины стека и выдать в качестве результата */double pop(void){if (sp > 0)return val[--sp];else {printf( "ошибка: стек пуст\п");return 0.0;}}Переменная считается внешней, если она определена вне функции.

Таким образом, стек и индекс стека,которые должны быть доступны и для push, и для pop, определяются вне этих функций. Но main неиспользует ни стек, ни позицию в стеке, и поэтому их представление может быть скрыто от main.Займемся реализацией getop — функции, получающей следующий оператор или операнд. Нам предстоитрешить довольно простую задачу.

Более точно: требуется пропустить пробелы и табуляции; если следующийсимвол — не цифра и не десятичная точка, то нужно выдать его; в противном случае надо накопить строкуцифр с десятичной точкой, если она есть, и выдать число NUMBER в качестве результата.#include <ctype.h>int getch(void);void ungetch(int);/* getop: получает следующий оператор или операнд */int getop(char s[]){int i, c;while ((s[0] = с = getch()) == ' ' || с == '\t' );s[1] = '\0';if (!isdigit(c) && с != '.')return с; /* не число */i = 0;if (isdigit(c)) /* накапливаем целую часть */while (isdigit(s[++i] = с = getch()));if (с == '.') /* накапливаем дробную часть */while (isdigit(s[++i] = с = getch()));s[i] = '\0';if (c != EOF)ungetch(c);return NUMBER;}Как работают функции getсh и ungetch? Во многих случаях программа не может "сообразить", прочла лиона все, что требуется, пока не прочтет лишнего.

Так, накопление числа производится до тех пор, пока невстретится символ, отличный от цифры. Но это означает, что программа прочла на один символ больше, чемнужно, и последний символ нельзя включать в число.Эту проблему можно было бы решить при наличии обратной чтению операции "положить-назад", с помощьюкоторой можно было бы вернуть ненужный символ. Тогда каждый раз, когда программа считает на одинсимвол больше, чем требуется, эта операция возвращала бы его вводу, и остальная часть программы моглабы вести себя так, будто этот символ вовсе и не читался. К счастью, описанный механизм обратной посылкисимвола легко моделируется с помощью пары согласованных друг с другом функций, из которых getchпоставляет очередной символ из ввода, a ungetch отправляет символ назад во входной поток, так что приследующем обращении к getch мы вновь его получим.Нетрудно догадаться, как они работают вместе. Функция ungetch запоминает посылаемый назад символ внекотором буфере, представляющем собой массив символов, доступный для обеих этих функций; getchчитает из буфера, если там что-то есть, или обращается к getchar, если буфер пустой.

Характеристики

Тип файла
PDF-файл
Размер
2,25 Mb
Тип материала
Высшее учебное заведение

Список файлов книги

Свежие статьи
Популярно сейчас
А знаете ли Вы, что из года в год задания практически не меняются? Математика, преподаваемая в учебных заведениях, никак не менялась минимум 30 лет. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
7021
Авторов
на СтудИзбе
260
Средний доход
с одного платного файла
Обучение Подробнее