Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Основы программирования на языке С. Учебное пособие

.pdf
Скачиваний:
1
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
☆
сваиваться идентификаторам по умолчанию следующим образом: самый левый в фигурных скобках идентификатор получит значение 0, а каждый последующий увеличивается на 1. Имена перечислимых констант должны быть уникальными, однако к значениям констант это не относится. Одно значение могут иметь разные константы. Для перечислимых констант можно ввести имя типа, соответствующего приведенному списку констант, например, определение
enum week {Sunday, Monday, Tuesday, Wednesday, Thursday,
Friday, Saturday};
не только определяет константы Sunday==0, Monday==1,…, но и вводит перечислимый тип с именем week, который может в дальнейшем использоваться в определениях и описаниях других типов.
Тип void можно использовать только для определений некоторых производных типов. Объектов типа void не существует, то есть описание void i; недопустимо.
Из основных типов с помощью операций *, &, [], () и механизмов определения структурированных
типов (классов, структур, объединений) можно конструировать множество производных типов. Приведем несколь­ко примеров:
int ar [5]; – массив, состоящий из пяти объектов типа int, доступ
к которым обеспечивают индексированные переменные ar[0], ar[1], ar[2]
ar[3], ar[4];
char t[]= “текст”; // массив, состоящий из пяти объектов типа char; void a1 (double); //функция, не возвращающая никакого значения
и имеющая аргумент типа double;
char *a2; // указатель на объекты типа char (значением указателей
являются
адреса участков памяти, выделенных для объектов конкретно-
го типа);
long a3;// не инициализированная переменная типа long; long &a4=a3; // инициализированная ссылка на объект типа long ; int *a5[];// массив указателей на объекты типа int; int (*a5)[]; // указатель на массив объектов типа int. Обратите внимание, что строка может быть описана как массив типа
char. Подробно назначение и синтаксис таких типов данных как указатели,
массивы,
ссылки, структуры данных и классы будет описаны в следующих
главах пособия.
Кроме того, используя спецификатор typedef, можно вводить в программе удобные обозначения для сложных описаний типов. Например,
typedef unsigned char UC;
UC simbol;
Здесь вводится новый тип UC и переменная этого типа simbol, зна­чениями которой являются беззнаковые числа в диапазоне от 0 до 255.
11
Для определения размера (в байтах) области памяти, выделяемой для переменной определенного типа, в языке С используется операция sizeof. Разрешены два формата операции
Sizeof (имя_переменной)
или
sizeof (тип данных).
Например, пусть определена переменная int i. Тогда операция sizeof(i) определит, сколько байт выделено для переменой i.
Соотношение между основными типами можно записать так:
1==sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long)<= <=sizeof(float) <= sizeof(double)
Каждый, описанный в программе объект (в частности, переменная), имеет следующие основные характеристики:
– область действия идентификатора – эта та часть программы, в ко­торой идентификатор может быть использован для доступа к связанному с ним объекту (обычно имя переменной действует с места ее определения и до конца блока {}, в котором она была определена);
– видимость объекта (данное понятие необходимо в связи с возможно­стью повторных определений идентификатора внутри вложенных блоков);
– продолжительность существования, которая определяет период, в течение которого идентификаторам в программе соответствуют конкрет­ные объекты в памяти. Определены три вида продолжительности: статиче­ская, локальная и динамическая;
– класс памяти – определяет размещение объекта в памяти
и про-
должительность его существования.
Определенные операции могут в зависимости от их операндов вызы­вать преобразование значения операнда от одного типа к другому. Например,
char сh= ‘a’;
int k = ch; // символьный тип преобразуется к целому
printf(“%d”, k;) // на экран выведется ASCII–код символа ch
Иногда необходимо явным образом преобразовывать типы, напри­мер, для вывода на экран ASCII-кода символа ch без использования вспо­могательной переменной целого типа будем писать
printf(“%d”, (int) ch); printf(“%d”, int (ch));
Использовать допустимые неявные преобразования типов необходи­мо с большой осторожностью.
Задание 2. Описание переменных и преобразование типов
Каждому студенту рекомендуется выполнить упражнения 1-3.
1. Опишите переменные всех типов, приведенных в табл. 2. Опреде-
лите количество байтов, которые занимают в памяти переменные этих ти­пов. Результат выведите на экран в виде
sizeof (int)=2
sizeof (long)=4…
12
2. Опишите в программе две переменные целого типа и введите их
значения с клавиатуры. Выведите на экран вещественное число, равное де­лению первой переменной на вторую. (Используйте операцию деления /. При делении целых чисел эта операция возвращает только целую часть ча­стого. Результат операции деления / будет вещественным, если делимое или (и) делитель –
вещественное число. Поэтому, в данной задачи необхо-
димо использовать явное преобразование типов).
3. Опишите в программе переменную символьного типа и введите ее значение с клавиатуры. Выведите на экран ASCII–код введенного символа в десятичном, восьмеричном и шестнадцатеричном виде, а также символы – больший и меньший «сосед» данного по ASCII-коду.
13
3. ВВОД-ВЫВОД ЗНАЧЕНИЙ ПЕРЕМЕННЫХ
Значение переменной может быть указано при описании, а может быть
введено с клавиатуры. Рассмотрим, как происходит ввод-вывод в языке С.
В языке С не определено никаких ключевых слов, с помощью кото­рых можно выполнять ввод-вывод. Вместо них используются библиотеч­ные функции. Заголовочным файлом для
функций ввода-вывода является
<stdio.h>. Имеются как консольные (ввод с клавиатуры, вывод на экран),
так и файловые функции ввода/вывода. С практической точки зрения кон­сольный и файловый ввод/вывод отличаются друг от друга очень мало. В данной главе мы рассмотрим консольные функции.
Самыми простыми из консольных функций ввода/вывода являются getchar(), которая читает символ с клавиатуры, и putchar(), которая отобра­жает символ на экране. Первая из этих функций ожидает, пока не будет нажата клавиша, а затем возвращает значение этой клавиши. Кроме того, при нажатии клавиши на клавиатуре на экране дисплея автоматически отображается соответствующий символ. Вторая же функция, putchar(), отображает символ на экране в
текущей позиции курсора.
Пример использования функций getchar() и putchar():
char c;
printf("Enter symbol: ");
c=getchar();
printf("Symbol= ");
putchar(c);
Для считывания и отображения строк можно использовать функции gets() и puts() соответственно.
Функция gets() читает строку символов, введенную с клавиатуры, и записывает ее в память по адресу, на который указывает ее аргумент. Символы можно вводить с клавиатуры до тех пор, пока не будет введен символ возврата каретки. Он не станет частью строки, а
вместо него в ее ко­нец будет помещен символ конца строки ('0'). Необходимо очень осторожно использовать gets(), потому что эта функция не проверяет границы массива, в который записываются введенные символы. Таким образом, может слу­читься, что пользователь введет больше символов, чем помещается в этом массиве. Хотя функция gets() прекрасно подходит для программ-примеров и
простых программ, предназначенных для «домашнего использования», но
в профессиональных программах ею лучше не пользоваться.
Функция puts() отображает на экране свой строковый аргумент, по­сле чего курсор переходит на новую строку. Отметим, что функция выпол­няется быстрее, чем printf(), но не позволяет числа или делать преобразо­вания формата.
Пример использования функций gets() и puts():
char str[10];
printf("Enter string: ");
14
gets(str); printf("String= "); puts(str);
Для консольного чтения и записи данных в разных форматах (фор­матный ввод-вывод) в языке С используются функции scanf() и printf() со­ответственно. Обе функции могут работать с любым встроенным типом данных, а также с символьными строками, которые завершаются символом конца строки ('0').
Функция printf(управляющая_строка) вывод данные на экран и в
качестве результата возвращает число выведенных символов или отри-
цательное значение в случае ошибки.
Управляющая_строка состоит из элементов двух видов. Первый из них – это символы, которые предстоит вывести на экран; второй – это спе­цификаторы преобразования, которые определяют способ вывода стоящих за ними аргументов. Каждый такой спецификатор начинается со знака процента,
за которым следует код формата. Аргументов должно быть ров­но столько, сколько и спецификаторов, причем спецификаторы преобразо­вания и аргументы должны попарно соответствовать друг другу в направ­лении слева направо. Например, в результате такого вызова printf()
printf("Мне нравится язык %c %s", 'C', "и к тому же очень
сильно!");
будет выведено Мне нравится язык C и к тому же очень сильно! В этом примере первому спецификатору преобразования (%c), соот-
ветствует символ 'C', а второму (%s), – строка «и к тому же очень сильно!».
Спецификаторы преобразования для функции printf() приведены
в табл. 3.
Таблица 3
Спецификаторы преобразования для функции printf()
Код Формат
%a %A %c %d %i %e %E %f %g
%G %o %s %u %x
Шестнадцатеричное в виде 0xh.hhhhp+d Шестнадцатеричное в виде 0Xh.hhhhP+d Символ Десятичное целое со знаком Десятичное целое со знаком Экспоненциальное представление ('е' на нижнем регистре) Экспоненциальное представление ('Е' на верхнем регистре) Десятичное с плавающей точкой В зависимости от того, какой вывод будет короче, используется %е или %f
В зависимости от того, какой вывод будет короче, используется %Е или %F Восьмеричное без знака Строка символов Десятичное целое без знака Шестнадцатеричное без знака (буквы на нижнем регистре)
15
Окончание табл. 3
Код Формат
%X %p
%n
%%
Шестнадцатеричное без знака (буквы на верхнем регистре) Выводит указатель Аргумент, соответствующий этому спецификатору, должен быть указателем на целочисленную переменную. Спецификатор позволяет сохранить в этой переменной количество записанных символов (записанных до того места, в котором находится код %n) Выводит знак %
Например,
printf("%s%d%c%o%c%Х","This is number 10 : ",10,
',',10,',',10);
выведет на экран
This is number 10 : 10,12,A
Во многих спецификаторах преобразования можно указать модифи­каторы, которые меняют их значение. Например, можно указывать мини­мальную ширину поля, количество десятичных разрядов и выравнивание по левому краю. Модификатор формата помещают между знаком процента и кодом формата.
Целое число, расположенное между знаком % и кодом формата, иг­рает роль модификатора минимальной ширины поля
. Если указан модифи­катор минимальной ширины поля, то чтобы ширина поля вывода была не меньше указанной минимальной длины, при необходимости вывод будет дополнен пробелами. Если же выводятся строки или числа, которые длин­нее указанного минимума, то они все равно будут отображаться полно­стью. По умолчанию для дополнения используются пробелы. А
если для этого надо использовать нули, то перед модификатором ширины поля сле­дует поместить 0. Например, %05d означает, что любое число, количество цифр которого меньше пяти, будет дополнено таким количеством нулей, чтобы число состояло из пяти цифр. Например, при выполнении следую­щего фрагмента программы
double item; item = 123.45; printf("%f\n", item); printf("%10f\n", item); printf("%012f\n", item);
на экран выведется:
123.450000
123.450000
00123.450000
Модификатор минимальной ширины поля чаще всего использует­ся при создании таблиц, в которых столбцы должны быть выровнены по вертикали.
Модификатор точности следует за модификатором минимальной ширины поля (если таковой имеется). Он состоит из точки и расположен-
16
ного за ней целого числа. Значение этого модификатора зависит от типа данных, к которым его применяют.
Когда модификатор точности применяется к данным с плавающей точкой, для преобразования которых используются спецификаторы преоб­разования %f, %e или %E, то он определяет количество выводимых деся­тичных разрядов. Например, %10.2f означает, что ширина поля вывода бу­дет не менее
5 символов, причем для десятичных разрядов будет отведено две позиции. Если модификатор точности применяется к %g или %G, то он определяет количество значащих цифр.
Примененный к строкам, модификатор точности определяет макси­мальную длину поля. Например, %5.7s означает, что длина выводимой строки будет составлять минимум пять и максимум семь символов. Если строка окажется длиннее, чем
максимальная длина поля, то конечные сим-
волы выводиться не будут.
Если модификатор точности применяется к целым типам, то он определяет минимальное количество цифр, которые будут выведены для каждого из чисел. Чтобы получилось требуемое количество цифр, добав­ляется некоторое количество ведущих нулей.
Пример, использования модификатора точности:
printf("%.3f\n", 123.1234567);
printf("%8.8d\n", 1000);
printf("%3.7s\n", "This is string");
При выполнении этого фрагмента программы на экран будет выве­дена следующая информация:
123.123
00001000
This is
По умолчанию весь вывод выравнивается по правому краю. То есть если ширина поля больше ширины выводимых данных, то эти данные располагаются по правому краю поля. Вывод по левому краю можно назначить принудительно, поместив знак минус прямо за %. Например, %–5.2f означает, что число с плавающей точкой и с двумя десятичными разрядами будет
выровнено по левому краю 5-символьного поля.
Например, при выполнении следующего фрагмента кода
printf("%15d\n", 100);
printf("%-15d\n", 100);
на экран выведется:
100
100
Непосредственное расположение # перед спецификаторами преобразо­вания g, G, f, Е или e означает, что при выводе обязательно появится деся­тичная точка – даже если десятичных цифр нет. Если вы поставите # непо­средственно перед x или X, то шестнадцатеричное число будет выведено с префиксом 0x. Если # будет непосредственно предшествовать специфика-
17
тору преобразования o, число будет выведено с ведущим нулем. К любым другим спецификаторам преобразования модификатор # применять нельзя.
Функция scanf(управляющая_строка) выполняет ввод с клавиату­ры и возвращает количество тех элементов данных, которым было успеш­но присвоено значение, либо EOF в случае ошибки.
Управляющая строка состоит из символов трех видов: спецификаторов преобразования, разделителей
и символов, не являющихся разделителями.
Каждый спецификатор формата ввода начинается со знака %, причем спецификаторы формата ввода сообщают функции scanf() тип считывае­мых данных. Перечень этих кодов приведен в табл. 4.
Таблица 4
Спецификаторы преобразования для функции scanf()
Код Значение
%a Читает значение с плавающей точкой %c Читает одиночный символ %d Читает десятичное целое число
%i
%e Читает число с плавающей точкой %f Читает число с плавающей точкой %g Читает число с плавающей точкой %о Читает восьмеричное число %s Читает строку %x Читает шестнадцатеричное число %p Читает указатель %n Принимает целое значение, равное количеству уже считанных символов %u Читает десятичное целое число без знака %[] Читает набор сканируемых символов %% Читает знак процента
Читает целое число как в десятичном, так и восьмеричном или шестнадцатеричном формате
Спецификаторам преобразования в порядке слева направо ставятся в соответствие элементы, представляющие собой адреса объектов, куда необходимо считать информацию. То есть если необходимо считать дан­ные в переменную а, то следует указать, не ее имя, а ее адрес, т.е. &a.
Например, следующая программа читает десятичное, восьмеричное и шестнадцатеричное число и выводит их
int a, b,c;
scanf("%d%o%x", &a, &b, &c);
printf("%d %d %d", a,b,c);
на экран в десятичном виде:
При чтении одиночного символа символы разделителей читаются так же, как и любой другой символ, хотя при чтении данных других типов раз­делители интерпретируются как разделители полей. Например, при вводе с клавиатуры "x y" фрагмент кода
scanf("%c%c%c", &a, &b, &c);
помещает символ x в a, пробел – в b, а символ y – в c.
18
Для чтения из входного потока строки можно использовать функцию
scanf() со спецификатором преобразования %s. Использование специфика-
тора преобразования %s заставляет scanf() читать символы до тех пор, пока не встретится какой-либо разделитель. Читаемые символы помещаются в символьный массив, на который указывает соответствующий аргумент, а после введенных символов еще добавляется символ конца строки ('0'). Что касается scanf(),
то таким разделителем может быть пробел, раздели­тель строк, табуляция, вертикальная табуляция или подача страницы. В от­личие от gets(), которая читает строку, пока не будет нажата клавиша <ENTER>, scanf() читает строку до тех пор, пока не встретится первый разделитель. Это означает, что scanf() нельзя использовать для чтения строки "Hello, World", потому что после пробела процесс
чтения прекра-
тится. Пример ввода строки:
char str[80]; printf("Введите строку: "); scanf("%s", str); printf("Вот Ваша строка: %s", str);
Если введена строка "Hello, World", то на экран будет выведено "Hel-
lo,". Обратите внимание, что перед str не стоит операция взятия адреса &,
так как имя массива является адресом его первого элемента.
Ввод-вывод массив и символьных массивов это различные процеду-
ры. Например, если дан массив
int str[]={1,2,3};
то запись
printf("%i", str);
приведет не к его выводу, а к выводу на экран адреса массива, пре-
образованного к целому числу,
а запись
scanf("%i", str);
приведет к чтению только первого элемента массива. Чтобы ввести, а затем вывести элементы данного массива, необхо-
димо использовать запись
scanf("%i%i%i", &str[0],&str[1],&str[2]); printf("Элементы массива: %i %i %i", str[0],str[1],str[2]);
Разделитель в управляющей строке дает scanf() указание пропустить в потоке ввода один или несколько начальных разделителей. Разделителя­ми являются пробелы, табуляции, вертикальные табуляции, подачи стра­ниц и разделители строк. В сущности, один разделитель в управляющей строке заставляет scanf() читать, но не сохранять любое количество (в том числе и нулевое) разделителей, которые находятся перед
первым симво-
лом, не являющимся разделителем.
Если в управляющей строке находится символ, не являющийся раз­делителем, то функция scanf() прочитает символ из входного потока, про-
19
верит, совпадает ли прочитанный символ с указанным в управляющей строке, и в случае совпадения пропустит прочитанный символ. Например, "%d,%d" заставляет scanf() прочитать целое значение, прочитать запятую и пропустить ее (если это была запятая!), а затем прочитать следующее це­лое значение. Если же указанный символ во входном потоке не будет найден, то scanf() завершится.
Как и printf(), функция scanf() дает возможность модифицировать не­которое число своих спецификаторов формата. В спецификаторах формата моно указать модификатор максимальной длины поля. Это целое число, расположенное между % и спецификатором формата; оно ограничивает число символов, считываемых из этого поля. Например, чтобы считывать в переменную str не более 20 символов, пишите
scanf("%20s", str);
Если поток ввода содержит больше 20 символов, то при следующем вызове функций ввода считывание начнется после того места, где оно за­кончилось при предыдущем вызове. Например, если вы в ответ на вызов
scanf() из этого примера введете
ABCDEFGHIJKLMNOPRSTUVWXYZ
то в str из-за спецификатора максимальной ширины поля будет по­мещено только 20 символов, то есть
символы вплоть до Т. Это значит, что оставшиеся символы UVWXYZ пока еще не прочитаны. При следующем вызове scanf(), например, при выполнении оператора
scanf("%s", str);
в str будут помешены буквы UVWXYZ. Ввод из поля может завершить­ся и до того, как будет достигнута максимальная длина поля – если встретится разделитель. В таком случае scanf() переходит к следующему полю.
Чтобы прочитать длинное целое, перед спецификатором формата поместите l (эль). А для чтения короткого целого значения перед специфи­катором формата следует поместить n. Эти
модификаторы можно исполь-
зовать со следующими кодами форматов: d, i, o, u, x и n.
По умолчанию спецификаторы f, e и g дают scanf() указание присва­ивать данные переменной типа float. Если перед одним из этих специфика­торов будет помещен l (эль), то scanf() будет присваивать данные перемен­ной типа double. Использование L дает scanf() указание, чтобы переменная, принимающая данные, имела тип long double.
Функция scanf() может прочитать поле,
но не присваивать прочитан­ное значение никакой переменной; для этого надо перед литерой­спецификатором формата поля поставить звездочку, *. Например, когда выполняется оператор
scanf("%d%*c%d", &x, &y);
можно ввести пару координат 10,10. Запятая будет прочитана пра­вильно, но ничему не будет присвоена. Подавление присвоения особенно полезно тогда, когда нужно обработать только часть того, что вводится.
20
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]