Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Велосипедист выехал из А и в первый день проехал



Км. В последующие дни он проезжал со скоростью,

На 0, 5 раз большей, чем в предыдущий день. За сколько

дней велосипедист доберется до города В. */

#include< stdio.h>

#include< conio.h>

float km=10;

int d;

main()

{

clrscr(); /* чистка экрана, функция берется

из головного файла conio.h*/

d=1; /* первый день, за который велосипедист

проехал 10 км.*/

while(km< 20) /* пока выполнено условие цикла,

подсчитываются километры и дни*/

{

km+=(km*0.5);

d++;

}

printf(" велосипедист был в пути %d дней", d);

getch();

}

 

Изучение и использование функций printf( ) и scanf( )

Функции printf( ) и scanf( ) дают нам возможность взаимодействовать с программой. Мы называем их функциями ввода-вывода. Это не единственные функции, которыми мы можем воспользоваться для ввода и вывода данных с помощью программ на языке Си, но они наиболее универсальны. Эти функции входят в описание языка Си и они даны в библиотеке stdio.h. Обычно функции printf( ) и scanf( ) работают во многом одинаково - каждая использует управляющую строку и список аргументов. Сначала мы рассмотрим работу функции printf( ), затем scanf( ).

Формат Тип выводимой информации
%d десятичное целое число
%c один символ
%s строка символов
%e экспоненциальная запись
%f число с плавающей точкой, десятичная запись
%g используется вместо записи %f или %e
%u десятичное целое число без знака
%o восьмеричное целое число без знака
%x шестнадцатеричное целое число без знака

Инструкции, передаваемые функции printf( ), когда мы хотим напечатать некоторую переменную, зависят от того, какого типа эта переменная. Например, при выводе на печать целого числа применяется формат %d, а при выводе символа - %c. Форматы перечислены в таблице.

Посмотрим теперь, как эти формы применяются:

/* печать */

#define PI 3.14159

main( )

{

int number = 2003;

printf(" Интернет-университет информационных

технологий был открыт в %d году \n", number);

printf(" Значение числа pi равно %f.\n", PI);

}

Формат, указываемый при обращении к функции printf( ), выглядит следующим образом:

printf(Управляющая строка, аргумент1, аргумент2, _);

аргумент 1, аргумент 2 и т.д. - это печатаемые параметры, которые могут быть переменными, константами или даже выражениями, вычисляемыми перед выводом на печать.

Управляющая строка - строка символов, показывающая, как должны быть напечатаны параметры. Например, в операторе

printf(" %d студентов получили оценку %f.\n",

number, z);

управляющей строкой служит фраза в кавычках, а number и z - аргументы или в данном случае значения двух переменных.

Мы видим, что в управляющей строке содержится информация двух различных типов:

1. Символы, печатаемые текстуально.

2. Идентификаторы данных, называемые также спецификациями преобразования.

Каждому аргументу из списка, следующего за управляющей строкой, должна соответствовать одна спецификация преобразования. Если нужно напечатать какую-нибудь фразу, то нет необходимости использовать спецификацию преобразования; если же требуется только вывести данные на печать, то можно обойтись и без использования комментария. Поэтому каждый из операторов, приведенных ниже, вполне приемлем:

printf(" Эта книга не очень дорогая! \n" );

printf(" %c%d\n", '$', cost);

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

Например:

int i=2+3;

printf(" Только %d%% населения способно учиться самостоятельно! \n", i);

Результат работы программы будет выглядеть следующим образом:

Только 5% населения способно учиться самостоятельно!

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

Модификаторы Значение
- Аргумент будет печататься с левой позиции поля заданной ширины. Обычно печать аргумента оканчивается в самой правой позиции поля Пример: %-10
строка цифр Задает минимальную ширину поля. Большее поле будет использоваться, если печатаемое число или строка не помещается в исходном поле Пример: %4d
строка цифр Определяет точность: для типов данных с плавающей точкой число печатаемых цифр справа от десятичной точки; для символьных строк - максимальное число печатаемых символов Пример: %4.2f (две десятичные цифры для поля шириной в четыре символа)
l Соответствующий элемент данных имеет тип long, а не int Пример: %ld

Примеры:

main( )

{

printf(" /%d/\n", 135);

printf(" /%2d/\n", 135);

printf(" /%10d/\n", 135);

printf(" /%-10d/\n", 135);

}

Первая спецификация преобразования %d не содержит модификаторов. Это так называемый выбор по умолчанию, т. е. результат действия компилятора в случае, если вы не дали ему никаких дополнительных инструкций. Вторая спецификация преобразования - %2d. Она указывает, что ширина поля должна равняться 2, но, поскольку число состоит из трех цифр, поле автоматически расширяется до необходимого размера. Следующая спецификация %10d показывает, что ширина поля равна 10. Последняя спецификация %-10d также указывает ширину поля, равную 10, а знак - приводит к сдвигу всего числа к левому краю.

 

Применение функции scanf( )

 

Поскольку мы будем пользоваться функцией scanf( ) эпизодически, мы рассмотрим здесь только основные особенности ее применения. Для функции scanf( ) указывается управляющая строка и следующий за ней список аргументов. Основное различие функций printf( ) и scanf( ) заключается в особенностях данного списка. Функция printf( ) использует имена переменных, константы и выражения, а функция scanf( ) - только указатели на переменные. Мы ничего не должны знать о таких указателях. Необходимо помнить только два правила:

1. Если нам нужно ввести некоторое значение и присвоить его переменной одного из основных типов, то перед именем переменной требуется писать символ &.

2. Если мы хотим ввести значение строковой переменной, использовать символ & не нужно.

Пример:

main()

{

int age;

float assets;

char fio[50];

printf(" Введите ваш возраст, оклад, фамилию. \n" );

scanf(" %d %f", & age, & assets);

scanf(" %s", fio); /* & отсутствует при указании

массива символов */

printf(" %d $%.0f %s\n", age, assets, fio);

}

Функция scanf( ) использует некоторые специальные знаки, пробелы, символы табуляции и " новая строка", для разбиения входного потока символов на отдельные поля. Она согласует последовательность спецификаций преобразования с последовательностью полей, опуская упомянутые специальные знаки между ними. Исключением является спецификация %c, обеспечивающая чтение каждого следующего символа даже в том случае, если это пустой символ.

Функция scanf( ) использует тот же набор символов спецификации преобразования, что и функция printf( ). Основные отличия функции scanf( ) следующие:

1. Отсутствует спецификация %g.

2. Спецификации %f и %e эквивалентны. Обе спецификации допускают наличие или отсутствие знака строки цифр с десятичной точкой или без нее и поля показателя степени.

3. Для чтения целых чисел типа short применяется спецификация %h.

Функция scanf( ) не является одной из наиболее часто используемых функций языка Си. Мы обсуждаем ее из-за универсальности.

Особенности работы с языком Си. Задание фиксированной ширины полей оказывается полезным при печати данных столбиком.

Например:

printf(" %d %d %5d\n", val1, val2, val3);

Результат выглядит так:

11 222 3333

4 5 23

22222 3332 11111

Эти же данные можно представить в улучшенном виде, если задать достаточно большую фиксированную ширину поля:

printf(" %9d %9d %9d\n" val1, val2, val3);

Результат будет выглядеть так:

11 222 3333

4 5 23

22222 3332 11111

Если печатаемое число включено в некоторую фразу, то часто при его выводе оказывается удобным задать ширину поля равной или меньше требуемой. Это дает возможность включить число во фразу без добавления лишних пробелов.

А теперь рассмотрим два примера работы с циклом while:

/*квадраты чисел*/

main( ) /*получение квадратов*/

{

int n=1;

while(n < 11) {

printf(" %10d %10d\n", n, n*n);

n=n+1;

}

}

Эта программа выводит на печать первые 10 чисел и их квадраты.

Второй пример.

Согласно легенде, один правитель обещал наградить ученого, оказавшего ему большую услугу. Ученый, когда его спросили, что бы он хотел получить в награду, указал на шахматную доску и сказал: " Положите одно пшеничное зерно на первую клетку, два - на вторую, четыре на третью, восемь на следующую и т.д." Правитель был поражен, услышав такую скромную просьбу. Программа, приведенная ниже, показывает, в какое положение попал правитель!

/* пшеница*/

#define NUMBER 64 /* число клеток на шахматной доске*/

#define CROP 7E14 /* весь урожай пшеницы,

выраженный в числе зерен*/

main( )

{

double current, total;

int count =1;

printf(" КЛЕТКА ЧИСЛО СУММА ЗЕРЕН ДОЛЯ\n" );

total = current = 1.0; /*начинаем с одного зерна*/

printf(" %4d %15.2e %13.2e %12.2e\n", count,

current, total, total/CROP);

while(count < NUMBER) {

count = count + 1;

current = 2.0*current;

/*удвоенное число зерен на следующей клетке */

total = total +current; /* коррекция суммы*/

printf (" %4d %15.2e %13.2e %12.2e\n", count,

current, total, total/CROP);

}

}

Это пример составного оператора. От открывающей фигурной скобки оператора while до закрывающей фигурной скобки.

Составной оператор используется в следующих случаях:

1. Чтобы сгруппировать несколько логических связанных операторов в один оператор.

2. В качестве тела функции.

3. Для ограничения видимости определений частью программы, т.е. для локализации действия описаний.

Составной оператор имеет следующую форму:

{

определения и описания

операторы

}

Определения переменных внутри составного оператора имеют больший приоритет, чем определения переменных с тем же именем для области действия составного оператора. Эти переменные видимы, т.е. доступны, только внутри составного оператора. Глобальные переменные являются видимыми внутри составного оператора только при условии, что их определения не изменены локальными определениями.

! Применяйте отступы от поля в строках, чтобы сделать структуру программы наглядной!

 

Подведем итог.

Выражение состоит из операций и операндов.

Оператор служит командой компилятору. Операторы бывают простыми и составными. Простые операторы оканчиваются символом " точка с запятой". Примеры:

Оператор описания: int name;
Оператор присваивания: current=12;
Оператор вызова функции: printf(" Текст\n" );
Управляющий оператор: while (n < 111) n=n+5;
Пустой оператор: ;

Составные операторы, или блоки, состоят из одного или более операторов, заключенных в фигурные скобки, которые в свою очередь сами могут быть составными.

Примеры:

/* Задача № 1.

Вычислить величину дохода по вкладу. Процентная

ставка (в процентах годовых), время хранения

(в днях) и сумма задаются во время работы программы.*/

#include < stdio.h>

float р, t, s, d;

main()

{

puts(" Введите сумму s" );

scanf(" %f", & s);

puts(" Введите процентную ставку р" );

/* вывод строки */

scanf(" %f", & p);

puts(" Введите время хранения в днях t" );

scanf(" %f", & t);

d=p*s*t/36500;

printf(" \n Величина дохода d=%f", d);

}

 

/* Задача № 2

По заданной стороне куба А определить его объем, площадь

грани и площадь поверхности.*/

#include < stdio.h>

float a, v, s, si;

main()

{

puts(" \n Введите сторону а" );

scanf(" %f", & a);

v=a*a*a;

s=a*a;

si=s*6;

printf(" \n объем v=%f", v);

printf(" \n площадь грани s=%f", s);

printf(" \n площадь поверхности si=%f", si);

}

 

/* Задача № 3

Определить реальное расстояние между населенными

пунктами. Указан масштаб карты и расстояние между

двумя точками, изображающими населенные пункты.*/

#include < stdio.h>

float m, s, si;

main()

{

puts(" Введите масштаб карты m" );

scanf(" %f", & m);

puts(" Введите расстояние на карте si" );

scanf(" %f", & si);

s=si*m;

printf(" \n реальное расстояние s=%f", s);

}

 

 

5. Лекция: преобразование типов.

 

-Эквивалентность типов.

-Преобразование типов.

-Неявное преобразование типа.

-Арифметические преобразования.

-Явное преобразование типов.

-Синтаксис типов.

 

Эквивалентность типов

 

Существует несколько схем для определения того, являются ли типы двух объектов эквивалентными. Две схемы, наиболее часто используемые, называются структурная эквивалентность типов и именная эквивалентность типов. В соответствии со схемой структурной эквивалентности типов два объекта относятся к одному и тому же типу только в том случае, если их компоненты имеют одинаковые типы. В соответствии со схемой именной эквивалентности типов два объекта имеют один и тот же тип только в случае их определения с использованием имени того же типа.

Большинство реализаций языка Си используют схему структурной эквивалентности типов. Однако в книге (Ritche, D.M. 1980/ The C Programming Language - Reference Manual/ AT& T Bell Laboratories, Murray Hill, N.J. 07974) вопрос об эквивалентности типов игнорируется, и при каждой реализации может быть выбрана своя схема определения эквивалентности типов. Следовательно, вполне возможно, что результаты правильно работающей программы станут неверными при замене компилятора!

 

Преобразование типов

 

В операторах и выражениях должны использоваться переменные и константы только одного типа. Если все же мы смешиваем типы в одном выражении, то компилятор с языка Си не считает программу неправильной, как это произошло бы при программировании на языке Паскаль. Вместо этого компилятор использует набор правил для автоматического преобразования типов. Это очень удобно, но может оказаться и опасным, особенно если мы допустили смешение типов нечаянно.

Приведем несколько основных правил, касающихся преобразования типов:

1. Если операция выполняется над данными двух различных типов, обе величины приводятся к высшему из двух типов. Этот процесс называется повышением типа.

2. Последовательность имен типов, упорядоченных от высшего типа к низшему, выглядит так: double, float, long, int, short, char. Применение ключевого слова unsigned повышает ранг соответствующего типа данных со знаком.

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

Повышение типа обычно происходит гладко, в то время как понижение может привести к затруднениям. Причина этого проста: все число целиком может не поместиться в элементе данных низшего типа. Переменная типа char может иметь целое значение 101, но не 22225.

Пример, приведенный ниже, иллюстрирует применение этих правил:

/*преобразования*/

main( )

{

char ch;

int i;

float f1;

f1=i=ch='A'; /***8***/

printf(" ch=%c, i=%d, f1=%2.2f\n", ch, i, f1); /***9***/

ch=ch+1; /***10***/

i=f1=f1+2*ch; /***11***/

f1=2.0*ch+i; /***12***/

printf(" ch=%c, i=%d, f1=%2.2f\n", ch, i, f1); /***13***/

ch=2.0e30; /***14***/

printf(" Теперь ch=%c\n", ch);

}

Выполнив программу " преобразования", получим следующие результаты:

ch = A, i = 65, f1 = 65.00

ch = B, i = 197, f1= 329.00

Теперь ch =

 

Разбор программы

Строки 8 и 9: величина 'A' присваивается символьной переменной ch. Переменная i получает целое значение, являющееся преобразованием символа 'A' в целое число, т.е. '65'. Переменная f1 получает значение 65.00, являющееся преобразованием числа 65 в число с плавающей точкой.

Строки 10 и 13: значение символьной переменной 'A' преобразуется в целое число 65, к которому затем добавляется 1. После этого получившееся в результате число 66 преобразуется в код символа В и помещается в переменную ch.

Строки 11 и 13: при умножении на 2 значение переменной ch преобразуется в целое число 66. При сложении с величиной переменной f1 получившееся в результате число 132 преобразуется в число с плавающей точкой. Результат 197.00 преобразуется в число целого типа и присваивается переменной i.

Строки 12 и 13: перед умножением на 2.0 значение переменной ch('B') преобразуется в число с плавающей точкой. Перед выполнением сложения величина переменной i(197) преобразуется в число с плавающей точкой, а результат 329.00 присваивается переменной f1.

Строки 14 и 15: здесь производится попытка осуществить преобразование типов в порядке убывания старшинства - переменная ch полагается равной сравнительно большому числу. Результаты оказываются неутешительными. Независимо от переполнения и усечения, которые имеют место, в итоге мы получили код, соответствующий какому-то непечатаемому знаку.

 

Существует еще один вид преобразования типов. Для сохранения точности вычислений при арифметических операциях все величины типа float преобразуются в данные типа double. Это существенно уменьшает ошибку округления. Конечный результат преобразуется обратно в число типа float, если это диктуется соответствующим оператором описания.

 

Операция приведения

Самое лучшее - это вообще избегать преобразования типов, особенно в порядке убывания ранга. Но иногда оказывается удобным применять такие преобразования при условии, что мы ясно представляем смысл выполняемых действий. Преобразования типов, которые мы обсуждали до сих пор, выполнялись автоматически. Существует возможность точно указывать тип данных, к которому необходимо привести величину. Этот способ называется приведением типов, и используется следующим образом: перед данной величиной в круглых скобках записывается имя требуемого типа. Скобки и имя типа вместе образуют операцию приведения. В общем виде она записывается так:

(тип)

где фактическое имя требуемого типа представляется вместо слова тип.

 

Рассмотрим пример:

int nice;

nice = 1.6+1.7;

nice = (int)1.6+(int)1.7;

В первом примере используется автоматическое преобразование типов. Сначала числа 1.6 и 1.7 складываются - результат равен 3.3. Затем путем отбрасывания дробной части полученное число преобразуется в 3 для согласования с типом int переменной nice. Во втором примере 1.6 и 1.7 преобразуются в целые числа 1, так что переменной nice присваивается значение, равное 1+1, или 2.

Особенности работы с языком Си. Мы не должны смешивать типы; вот почему в некоторых языках это запрещено. Но бывают ситуации, когда это оказывается полезным. Философия языка Си заключается в том, чтобы не устанавливать барьеров на вашем пути, но при этом возложить на вас всю ответственность за злоупотребление предоставленной свободой.

 

Неявное преобразование типа

 

Неявные преобразования типа выполняются главным образом для согласования аргументов оператора или функции (если это возможно) со значениями, предполагаемыми в этих операторах или функциях. Все неявные преобразования типа, которые могут встретиться, перечислены ниже (слева указывается преобразуемый тип, а справа - список типов, в которые он может быть преобразован):

 

char - int, short int, long int (Преобразование к значению с большим числом двоичных разрядов может включать, а может не включать расширение знакового разряда - это зависит от реализации языка. Для элементов заданного набора знаков гарантируется преобразование в неотрицательные целые значения).

 

int - char, short int, long int (Преобразование к целому большей длины включает расширение знакового разряда. Преобразование к целому меньшей длины вызывает отбрасывание лишних старших разрядов). float, double, unsigned int (интерпретация комбинации битов в виде беззнакового целого значения).

 

short int - аналогично типу int.

 

long int - аналогично типу int.

 

float - double, int, short int, long int (машинно-зависимое преобразование, если преобразуемое значение слишком велико, то результат неопределен).

 

double - float (преобразование с округлением и последующим отбрасыванием лишних разрядов), int, short int, long int.

 

Арифметические преобразования

 

Арифметические операторы языка Си преобразуют операнды к соответствующим типам автоматически, если операнды не имели таких типов с самого начала. Схема преобразования, используемая этими операторами, называется обычные арифметические преобразования; эта схема может быть описана следующими правилами:

Преобразовать операнды типов char и short int к типу int; преобразовать операнды типа float к типу double.

Если хотя бы один из операндов имеет тип double, то и другой операнд преобразуется к типу double (если он другого типа); результат имеет тип double.

Если хотя бы один операнд имеет тип long, то и другой операнд преобразуется к типу long (если он другого типа); результат имеет тип long.

Если хотя бы один из операндов имеет тип unsigned, то и другой операнд преобразуется к типу unsigned (если его тип не unsigned); результат имеет тип unsigned.

Если ни один из случаев 1-4 не имеет места, то оба операнда должны иметь тип int; такой же тип будет и у результата.

 

Явные преобразования типов

 

Выражения могут быть преобразованы из одного типа в другой явным указанием. Выражение E может быть явно преобразовано к типу имя-типа с помощью записи вида

(имя - типа) Е

где имя типа представляется в форме

указатель-типа абстрактный-описатель

Абстрактный описатель аналогичен описателю, за исключением того, что он не содержит определяемого или описываемого идентификатора. Смысл слов имя-типа, представляемого в форме

Т абстрактный описатель

где Т является указателем типа, может быть определен одним из таких способов:

форма абстрактного описателя - смысл слов " Т абстрактный описатель";

пустой (абстрактный описатель) - абстрактный описатель типа Т;

*(абстрактный описатель) - указатель на тип Т;

абстрактный описатель ( ) - функция, возвращающая значение типа Т;

абстрактный описатель [n] - массив с n элементами типа Т, n - выражение с постоянным значением;

Приведем примеры явного преобразования. Предположим, что даны следующие определения и описания:

int i;

char *pc, *name;

char *calloc( ), *strcpy( );

тогда можно привести следующие примеры явных преобразований типов:

(char) i - преобразует значение типа int в значение типа char.

pc=(char *) 0777 - преобразует восьмеричный литер 0777 в значение указателя на знак таким образом, что оно может быть присвоено переменной " pc".

(emp *) calloc(1, sizeof(emp)) - преобразует значение " знакового" указателя, возвращаемого функцией calloc, в значение указателя emp.

(void) strcpy(name, " gehani" ) - опускает значение, возвращенное функцией strcpy.

 

Синтаксис типов

 

Можно отметить, что синтаксис типов в языке Си нерегулярен и беспорядочен, о чем свидетельствуют:

· - Трудность создания форматеров.

· - Большое число ошибок, допускаемых даже опытными программистами.

· - Трудность создания синтаксических анализаторов для трансляторов с языка Си - не существует двух трансляторов с языка Си, синтаксис входного языка для которых полностью совпадал бы.

Отсутствие формального описания синтаксиса языка Си - даже книга (Kernighan, B.W., and D.M. Ritchie, The C Programming Language, prentice-Hall, Engleewood Cliffs, NJ (1978)) может служить лишь черновым описанием такового. Сказанное касается в полной мере и синтаксиса типов. Имеется три случая, когда необходимо использовать типы:

  1. Описания, связывающие тип с именем, как, например, в случае описания (глобальных) переменных и формальных параметров;
  2. Описания, связывающие значения (и тип) с именем, как, например, описания программ;
  3. Приведения, обеспечивающие, например, возможность трактовки символов как целых.

 


Поделиться:



Последнее изменение этой страницы: 2017-04-13; Просмотров: 454; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.107 с.)
Главная | Случайная страница | Обратная связь