Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Стандарные подпрограммы (функции Printf, Scanf)↑ Стр 1 из 4Следующая ⇒ Содержание книги
Поиск на нашем сайте
Книга по С
Стандарные подпрограммы (функции Printf, Scanf) Сейчас мы познакомимся с важнейшими понятиями и особенностями языка Си на нескольких примерах. При этом мы сконцентрируем наше внимание на таких понятиях, как константа и переменные, арифметические действия над ними, основные управляющие структуры, функции и простейший ввод-выод. К наиболее интересным и важным функциям языка относится printf. Она предназначена для форматного вывода данных. Например, чтобы вывести некоторое сообщение на экран дисплея, достаточно использовать вызов функции: printf ("Интересное сообщение \n"); Одним из механизмов взаимодействия являются параметры. Список параметров (аргументов) идет вслед за именем функции в круглых скобках. В данном случае аргументом служит строковая константа - любая последовательность символов, в кавычках. Комбинация " \n " означает переход на новую строку. Первый пример можно заменить вот на такую строчку: printf ("Интересное сообщение "); printf(" \n "); - результат будет точно таким же, как и в первом случае! Первым аргументом служит строка форматов, а вторым, если они есть, - выводимые объекты. Строка форматов может включать обычные символы, которые начинаются со знака %, за ним следует символ преобразования. Каждая спецификация преобразования соответствует одному из аргументов, которые следуют за форматной строкой.Буква d в спецификации преобразования указывает, что значение аргумента должно быть напечатано как десятичное целое число. Из других символов отметим: c - для вывода отдельного символа; s - для печати символьной строки; x и o -для вывода шестнадцатиричных и восьмиричных чисел соответственно; f - для вывода чисел с плавающей точкой. В следующем примере printf(" %c = %d \n",g,g); значение переменной g выводиться как символ алфавита, а после знака равенства - как числовое значение, соответствующее внутреннему (машинному) коду этого символа. Перед символом преобразования может стоять, явно указывающий количество позиций в выводимой строке, отведенных для элемента вывода. printf(" %c = %5d \n",g,g); Пример простой программы на языке Си Следующий простой пример, но вполне законченной программы поможет понять многие из расмотренных ранее принципов построения программ на языке Си. Наша первая программа вводит два числа, вычисляет их сумму и печатает результат с поясняющим текстом " Cумма "
Дадим некоторые пояснения. В языке Си любая пограмма, состоит из нескольких программных едениц и каждая из них - функция. Функции в Си подобны функциям или подпрограммам в Фортране или процедурам в Паскале, Имена функций выбираются произвольно (только латинскими буквами), но одно из них main, именно с нее начинается выполнение программы. Такая главная функция обычно обращается к другим функциям, которые находятся в одном файле с головной программой или извлекают из библиотеки предварительно подготовленных функций.Функция main не имеет аргументов, поэтому список ее выглядит так: (). Скобки { } обрамляют операоры, которые реализуют собственно алгоритм. Эти скобки аналогичны BEGIN - END в Паскале. Рассмотрим теперь функцию scanf предназначенную для форматного ввода данных. Функция scanf в качестве фактических параметров использует адреса переменных, а не их значения. Для этого перед соответствующим параметром ставят знак & - символ взятия адресса. Например, &XL означает "адрес перменной XL ", а не значение, которое переменная имеет в данный момент. Строка форматов функции scanf указывает, какие данные ожидаются на входе. Если функция встречает в форматной строке знак %, за которым следует символ преобразования, то она будет пропускать на входе символы до тех пор, пока не встретит какой-нибудь не пустой символ. Предыдущяя программа страдает одним недостатком: программа вычисления суммы годится только для одного конкретного случая, когда a=5, b=7. Улучшим ее, заменив соответствующие операторы присваивания вызовом функции scanf (пример 1.2):
Форматная строка предписывает функции scanf ввести десятичное число, которое надо поместить в переменную a, затем через пробел ввести второе десятичное число, которое надо присвоить переменной b. Обратите внимание, что программа начинается со строки коминтарием: /*.. */, транслятор пропускает любые символы между /* и */ и их можно использовать для пояснений. Операторы IF - ELSE Рассмотрим организацию ввода- вывода и реализацию основных управляющих структур. Любой конкретный алгоритм может быть записан на языке программиррования, использующем только три управляющий структуры: последовательное выполнение, ветвление и повторение.
где часть else может и отсутствовать. Сначала вычисляется "выражение"в скобках; если оно истинно то выполняется оператор_1. Если " выражение" ложно (равно нулю - NULL), то оператор_1 пропускается, а выполняется оператор_2. Если на месте условно выполняемых операторов должна располагаться группа из нескольких операторов языка, то они заключаются в фигурные скобки - { }. Часто "выражение" в скобках представляет условие, заданное с помощью операций отношений и логических операций. Операции отношения обозначаются в Си следующим образом: = = равно;! = не равно; < меньше; > больше; Символ! в языке Си обозначает логическое отрицание. Есть еще две логические операции: || означает или, а && - логическое И. Операции отношения имеют приоретет ниже арифметических операций, так что выражение вида k > n%i вычисляется как k > (n%i). Приоритет && выше, чем у ||, но обе логические операции выполняются после операций отношения и арифметических. В сомнительных случаях лучше расставлять скобки. Для иллюстрации применения условного оператора рассмотрим программу определения большего из трех чисел. Первый if оператор представляет полную условную конструкцию, во втором случае else отсутствует. Обратите внимание, что точка с запятой, завершая оператор присваивания max=x, не нарушает единство if - оператора. Если else - ветвь пропускается во вложенных условиях, возможна неоднозначность их толкования. Во избежание двусмысленностей решают так: else соответствует ближайшему if, не имеющего своего else. Пример 1.3.
Рассмотрим пример программы, в которой применяются несколько вложенных друг в друга условных операторов. В этой программе сторока float A, B, X объявляет эти три переменные как величины вещественного типа. Форматная строка функции scanf предписывает ввести два вещественные числа, которые станут значениями переменных A и B соответственно. Пример 1.4
Посмотрите, как выглядит ветвление, когда глубина вложенности условных операторов равна трем (пример 1.5). Если хоть одно условие истинно, то все оставшиеся, разумеется, пропускаются. При глубине вложенности условных операторов свыше трех ветвление теряет наглядность и понятность.
Пример 1.5
Оператор WHILE
Определение функции В библиотеке стандартных подпрограмм языка Си имеется много полезных библиотечных функций. Для нас особый интерес представляютя функции, которые мы определяем сами. Не следует думать, что выделение функции как самостоятельной единицы целесообразно только тогда, когда к ней приходится многократно обращаться. Часто встречаются функции всего в несколько строк, вызываемые единожды, но оформление как функции только для более ясного написания. Определение функции состоит из двух частей: заголовка и тела. Заголовок определяет имя функции, ее тип и формальные параметры, тело определяет действия над данными, выполняемые функцией. Возращающее функцией значение передается в вызывающюю программу опрератором return (выражение). Значение "выражения" и есть результат функции (возращаемого значения). Если в нашей программе функция физически следует за вызывающей ее функцией main, то надо в последней объявить функцию внешней с помощью описателя extern: extern int fun(); или еще проще int fun();. В противном случае при компиляции будет выдана ошибка. Всякая функция имеет вид:
Здесь квадратные скобки указываютя, что заключенная в них конструкция может отсутствовать. По умолчанию тип функции целый. Описание формальных параметров расположено между списком параметров и левой скобкой. Каждое описание заканчивается точкой с запятой. Формальные параметры функции полностью локализированы в ней и недоступны для других функций. Аргументы функции передаются по значению, а не их адреса. Рассмотрим пример программы возведения числа в степень. Для этого составим функцию power(t,n); В нашей реализации функция power предшествует головной программе, поэтому она предварительно не объявлена. Описание формальных параметров функции происходит в заголовке (int t,n;) Оператор int p=1; в теле функции определяет переменную p целого типа и присваивает ей начальное значение равное 1. Выражение int p=1; в точности эквиалентно последовательности операторов int p; p=1; Обращение к функции задает один из аргументов стнадартной функции printf в программе main. Выражение power(t,n) предписывает вызов функции. Когда программа main достигает этой точки, то все управление передается функции power. Операторы, содержащиеся в теле функции power фактически оперируютя данными. Когда достигается оператор return, осуществляется переход в ту точку программы main, из которой мы пришли в power. Значение, вычисляемое функцией power, передается в головную программу с помощью оператора return(p). В скобках в общем случае может быть любое значение. Прмер 2.0
Рекурсия. В языке Си можно использовать рекурсивно, т.е. функция может вызывать сама себя. Простейший пример 2.1, где функция main вызывает сама себя остановить которую можно только с помощью CTRL+C - ^С. При рекурсивном обращении к функции - создается новый экземпляр данных. Пример 2.1
Следущий пример 2.2 использует рекурсию для вычисления k!. При первом вызове fact(i), если не равно 1, функция порождает выражение i*fact(i-1); в свою очередь, вызов fact(i-1) производит (i-1)*fact(i-2), что вместе с ранее полученным результатом дает i*(i-1)*fact(i-2). Рекурсия закончистся, как только следующий вызов функции получит аргумент, равный еденице. Нетрудно сообразить, что в конечном счете мы получим требуемое произведение. Прмер 2.2
Классы памяти Все переменные в программе характеризуются не только типом, но и классом памяти. В языке Си существует четыре класса памяти: автоматический (automatic), регистровый (register), статический (static) и внешний (external). Автоматические переменные в программе можно описать так: auto A; auto char c1; auto int x= 125; Если мы этим не пользовались, то только потому что опущенный описатель auto используется по умолчанию. Зона действия автоматической переменной ограничена блоком или функцией, где она описана. Она начинает существовать после обращения к функции и исчезает после выхода из нее. Таким образом автоматические переменные не занимают область в памяти. Значение автоматической переменной не может быть изменено другими функциями и в этих функциях может находится переменные с таким же именем. Проанализируем результаты работы следующей программы. Пимер 2.3
В этой программе перменная t описана в нескольких блоках, в каждом блоке она может принимать разные значения не зависимо от других. С ней могут выполнятся разные операции. В нашей програамме значение переменной t выводится на дисплей. В нашем случае выведятся числа 2, 3, 746. Число 746 - так называемое число "мусор" оно такое так как ей не присваивали значение в первом блоке. Внешние переменные вводятся как нечто противоположное автоматическим. Это глобальные переменные и к ним можно обращаться именами из любой функции. Поскольку внешеие переменные доступны везде, их можно использовать для связи между функциями, не пренебрегая механизму формальных параметров. Пример 2.4
Внешнии переменные могут определятся вне квкой-либо функции; при этом выделяется фактическая память. В любой другой функции, обращающейся к этим переменным, они должны описываться; делается явно с помощью описателя extern. Обычно поступают так, как показано на прмере 2.5. Все внешние переменные размещают в начале исходного модуля (вне всяких функций!), опуская дополнительные описания со словом extern внутри функций. Конечно, если внешняя переменная и функция, которая ее использует, размещены в разных файлах, описывать эту переменную в функции необходиммо. Но самым важным способом является описание каждой внешней перемнной с ключевого слова extern в любой функции, которая ее использует. А еще лучше избегать применения внешних переменных, так как они часто служат источником труднообнаруживаемых ошибок. Пример 2.5
Статические переменные, подобно автоматическим, локальны в той функции или блоке, где они описаны. Разница заключается в том, что статические переменные не исчезают, когда функция (блок)завершает работу, и их значения сохраняются для последующих вызовов функции. Описание статических переменных выглядит так: static char c; static int a=1; Рассмотрим пример 2.6, в котором переменная объявлена как статическая. Пример 2.6
Начальное значение равное нулю присваивает переменной x только один раз. Затем в программе main, функция plus1() несколько раз запускается, так как при каждом запуске функции аргумент x не изменяется, а оставляет значение из предыдущей функции. Таким образом повторение функции plus1 обеспечивает увелечение переменной x на 1 при каждом запуске 1, 2, 3... Регистровые переменные объявляются в программе с помощью ключевого слова register и по замыслу автора языка Си должны хранится в сверх быстрой памяти ЭВМ - регистрах. Используются аналогично автоматическим переменным. Целесообразность их применения для увелечения быстродействия программы представляется в большинстве случаев сомнительной. Обработка символьных данных Язык Си лучше всего подходит для системной работы: написания компиляторов, интерпретаторов, опрерационных систем, редакторов текста и.т.п. В стнадартной библиотеке Си предусмотренымногие полезные функции, выполняющие простые действия с символьными данными. Рассмотрим из них - putchar и getchar выполняющие ввод и вывод символа соответственно и создадим на их основе ряд своих полезных функций. Функция getchar за одно обращение к ней выдает в качестве результата один символ, поступивший с системного ввода. Мы можем рассматривать getchar как функцию, имеющую заголовок Int getchar() видите, у нее совсем нет аргументов и она возращает значение типа - это значение символа во внутреннем представлении его для данной ЭВМ(напрмер в ACSII). Таким образом после обращения c = getchar() переменная с содержит очередной символ, набранный вами на клавиатуре. Функция putchar за одно обращение к ней выдает один символ в стандарный выходной поток. Вызов этой функции имеет вид: putchar(c); c - переменная символьного типа, котрой предварительно было присвоено некоторое значение. Рассмотрим примеры. Программа (пример 2.7) вывводит на экран все прописные латинские буквы. Мы уже напоминали что типы char и int взаимозаменяемы. Последовательное прибавление к очередному значению с обеспечивает выбор очередной буквы ввиду их лексической упорядоченности. Пример 2.7
Прежде, чем перейти к рассмотрению примеров, обсудим, как машина должна определять конец входного потока символов, вводимых с клавиатуры терминала. Можно, конечно, выбрать некоторый символ как признак конца потока, но нужна гарантия, что он нигде не повторится. В использованной нами операционной системе для получения такого символа надо нажать CTRL+Z. В программе значение этого символа мы будем использовать через символическое имя EOF (end of file). Теперь мы можем написать программы копирования файла(прмер 2.8). Пока не обнаружен конец входного потока, ЭВМ получает с клавиатуры символ (это делает функция getchar) и сразу же выодит его на экран дисплея с помощью функции putchar. Для завершения программы достаточно нажать CTRL+Z. Пример 2.8
Программу копирования можно написать и более компактно. В языке Си любое присваивание например, c=getchar(), можно использовать в любом выражении в качестве операнда; его значение - это просто значение, присваиваемое левой части. Учитывая сказанное, перепишем Эхо Программу (Пример 2.9). Это компактная, элегантная программа принимает символ с клавиатуры и присваивает его переменной с, а затем сравнивает его с признаком конца файла. Пока этот признак не обнаружен, выполняется тело цикла и символ выдается на экран. В противном случае цикл, а вместе с ним и вся программа завершаются. Пример 2.9
Отметим, что включение присваиваний в проверки - силбное единство языка, способствующее созданию программ. Учтите, что скобки вокруг присваивания внутри условия необходимы: приоритет операции != выше приоритета операции присваивания. Пример 3.0
Массивы Как известно, массив - это конечная совокупность данных одного типа. Можно говорить о массивах целых чисел, массивов символов и.т.д. Мы можем даже определить масссив, элементы которого - массивы(массив массивов), определяя, таким образм, многомерные массивы. Любой массив в программе должен быть описан: после имени массива добаляют квадратные скобки [], внутри которых обычно стоит число, показывающее количество элементов массива. Например, запись int x[10]; определяет x как массив из 10 целых чисел. В случае многомерных массивов показывают столько пар скобок, какова размерность массива, а число внутри скобок показывает размер массива по данному измерению. Например, описание двумерного массива выглядит так: int a[2][5];. Такое описание можно трактовать как матрицу из 2 строк и 5 столбцов. Для обрщения к некоторому элементу массива указывают его имя и индекс, заключенный в квадратные скобки(для многомерног массива - несколько индексов, заключенные в отдельные квадратные скобки): a[1][3], x[i] a[0][k+2]. Индексы массива в Си всегда начинаются с 0, а не с 1, т.е. описание int x[5]; порождает элементы x[0], x[1], x[2], x[3], x[4], x[5]. Индекс может быть не только целой константой или целой переменной, но и любым выражением целого типа. Переменная с индексами в программе используется наравне с простой переменной (например, в операторе присваивания, в функциях ввода- вывода). Начальные значения массивам в языке Си могут быть присвоены при компиляции только в том случае, если они объявлены с классом памяти extern или static, например: static int a[6]={5,0,4,-17,49,1}; static int matr[2][5] = {{3,4,0,1,2},{6,5,1,4,9}}; Матрица хранится в памяти построчно, т.е. самый правый индекс в наборе индексов массива меняется наиболее быстро. Пример 3.6
Следующяя программа (пример 3.7)позволяет в целочисленном массиве найти разность максимального и минимального элемента. Обратите внимание, что функция fmax при первом обращении к ней дает максимальный элемент массива, а при повторном вызове - минимальный, так как предварительно мы изменили знаки элементов на противоположные. Это изменение знаков учитывается при вызове функции printf. В языке Си отсутствует возможность динамически распределять память под массивы: надо при описании массива задать точно его размер. Но если тот же массив описывается еще раз в другой программе, размеры можно не указывать;достаточно после имени сохранить пару квадратных скобок, например int x[]. Если при вызове функции в качестве аргумента ей передается имя массива, то, в отличае от простых переменных, берется фактически адрес начала этого массива. Поэтому записи fmax(a, 10) и fmax(&a[0], 10) равносильны. Пример 3.7
В следующем пример 3.8 массив описан как внешний. Функция main подсчитывает наибольшее число одинаковых идущих подряд элементов массива, определенного вне функции main. Пример 3.8
Если, как в данном примере, размер массива пропущен, то транслятор определит его дляну, считая присваиваемые значения во время начальной инициализации. Условная операция (k>max) ?k:max в операторе printf предусмотрена для того частного случая, когда весь массив состоит из одинаковых элементов. Приведем несколько примеров, в которых ведется обработка двумерных массивов. Но прежде одну полезную возможносить языка Си. Речь идет о препроцессорном утверждении #difine, позволяющем присваивать символические имена константам. В общем случае это утверждение записывают так: #define строка1 строка2 (точка с запятой не ставится). Пример 3.9
В программе (пример 4.0) определяется минимальный элемент кажой строки матрицы и выполняется обмен местами найденого и диагональю этой же строки. Пример 4.0
Массивы символов Любая символьная константа, например "ОЙ У ПОЛИ КРИНИЧКА", представляет собой массив символов. Во внутреннем представлении компилятор завершает такой массив символом "\0", так что любая программа может по нему легко обнаружить конец строки. Поэтому строка занимает в паямяти на один символ больше, чем записано между двойными кавычками. Нумерация элементов массива начинается с нуля. Надо помнить, что, например 'T' - это символ(буква), а ' T ' - это строка, состоящая из двух символов: 'T' и '\0'. Отсюда следует, что пустых строк не бывает. char str[]="ТЕКСТ"; Такая запись и короче и понятнее, чем общепринятая для начальной инициализации массивов: char str[]={'Т','Е','К','С','Т',}; Если длина строки в квадратных скобках опущена, то она определяется автоматически, по количеству присваеваемых символов. В приведенном выше примере она равна шести. Пример 4.1
|