Главная страница

Курс на Си. Подбельский. Курс программирования на Си. В., Фомин С. С. Курс программирования на языке Си Учебник


Скачать 1.57 Mb.
НазваниеВ., Фомин С. С. Курс программирования на языке Си Учебник
АнкорКурс на Си
Дата18.02.2023
Размер1.57 Mb.
Формат файлаdocx
Имя файлаПодбельский. Курс программирования на Си.docx
ТипУчебник
#943863
страница24 из 42
1   ...   20   21   22   23   24   25   26   27   ...   42

h - указывает, что следующий после h спецификатор d, i, o, x или X применяется к аргументу типа short или unsigned short;

  • l - указывает, что следующий после l спецификатор d, i, o, x или X применяется к аргументу типа long или unsigned long;

  • L - указывает, что следующий после L спецификатор e, E, f, g или G применяется к аргументу типа long double.

    Примеры указания ширины_поля и точности:

    • %d - вывод десятичного целого в поле, достаточном для пред­ставления всех его цифр и знака;

    • %7d - вывод десятичного целого в поле из 7 позиций;

    • %f - вывод вещественного числа с целой и дробной частями (выравнивание по правому краю; количество цифр в дробной части определяется реализацией и обычно равно 6);

    • %7f - вывод вещественного числа в поле из 7 позиций;

    • %.3f - вывод вещественного числа с тремя цифрами после де­сятичной точки;

    • %7.3f - вывод вещественного числа в поле из 7 позиций и тре­мя цифрами после десятичной точки;

    • %.0f - вывод вещественного числа без десятичной точки и без дробной части;

    • %15s - печать в выводимой строке не менее 15 символов;

    • %. 12s - печать строки длиной не более 12 символов («лиш­ние» символы не выводятся);

    • %12.12 - печать всегда в поле из 12 позиций, причем лишние символы не выводятся, используются всегда 12 позиций. Та­ким образом, точное количество выводимых символов можно контролировать, задавая и ширину_поля, и точность (макси­мальное количество символов);

    • %-15s - выравнивание выводимой строки по левому краю;

    • %08f - вывод вещественного числа в поле из 8 позиций. Не занятые значащими цифрами позиции заполняются нулями.

    Функция форматного вывода printf( ) предоставляет множество возможностей по форматированию выводимых данных. Рассмотрим на примере построение столбцов данных и их выравнивание по ле­вому или правому краям заданного поля.

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

    #include int main()

    {

    int i;

    int number[3]={1, 2, 3}; /* Номер товара */

    int code[3]={10, 25670, 120}; /* Код товара */

    /* Наименование товара: */

    char design[3][30]={{"лампа"}, {"стол"}, {"очень большое кресло"}};

    /* Цена: */

    float price[3]={1152.70, 2400.00, 4824.00};

    for (i=0; i<=2; i++)

    printf("%-3d %5d %-20s %8.2f\n",

    number[i], code[i], design[i], price[i]);

    return 0;

    }

    Результат выполнения программы:

    1

    10

    лампа

    1152.70

    2

    25670

    стол

    2400.00

    3

    120

    очень большое кресло

    4824.00

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

    1. переменная number[i] типа int выводится в поле шириной 3 символа и прижимается к левому краю (%-3d);

    2. переменная code[i] типа int выводится в поле шириной 5 сим­волов и прижимается (по умолчанию) к правому краю (%5d);

    3. строка из массива design[i] выводится в поле шириной 20 сим­волов и прижимается к левому краю (%-20s). Если в данной спецификации преобразования будет указано меньшее, чем 20, количество позиций, то самая длинная строка будет все равно выведена, однако последний столбец не будет выровнен;

    4. переменная price[i] типа float выводится в поле шириной 8 символов, причем после десятичной точки выводятся 2 сим­вола, и выводимое значение прижимается к правому краю.

    Между полями, определенными спецификациями преобразова­ний, выводится столько пробелов, сколько их явно задано в формат­ной строке между спецификациями преобразования. Таким образом, добавляя пробелы между спецификациями преобразования, можно производить форматирование всей выводимой таблицы.

    Напомним, что любые символы, которые появляются в формат­ной строке и не входят в спецификации преобразования, копируют­ся в выходной поток. Этим обстоятельством можно воспользоваться для вывода явных разделителей между столбцами таблицы. Напри­мер, для этой цели можно использовать символ '*' или '|'. В послед­нем случае форматная строка в функции printf( ) будет выглядеть так: «%-3d | %5d | %-20s | %8.2f\n», и результат работы программы будет таким:

    1 | 10 | лампа | 1152.70

    2 | 25670 | стол | 2400.00

    3 | 120 | очень большое кресло | 4824.00

    Форматный ввод из входного потока. Форматный ввод из вход­ного потока осуществляется функцией scanf( ). Прототип функции scanf( ) имеет вид:

    int scanf(const char * format, . . . );

    При обращении к функции scanf( ) возможны две формы задания первого параметра:

    int scanf ( форматная_строка, список_аргументов );

    int scanf ( указатель_на_форматную_строку, список_аргументов);

    Функция scanf( ) читает последовательности кодов символов (байты) из входного потока и интерпретирует их в соответствии с форматной_строкой как целые числа, вещественные числа, оди­ночные символы, строки. В первом варианте вызова функции фор­матная строка размещается непосредственно в списке аргументов. Во втором варианте вызова предполагается, что первый аргумент - это указатель типа char *, адресующий собственно форматную стро­ку. Форматная строка в этом случае должна быть определена в про­грамме как обычная строковая константа или переменная.

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

    Если аргументов недостаточно для данной форматной строки, то результат зависит от реализации (от операционной системы и от си­стемы программирования). Если аргументов больше, чем требуется в форматной строке, «лишние» аргументы игнорируются.

    Последовательность кодов символов, которую функция scanf( ) читает из входного потока, как правило, состоит из полей (строк), разделенных символами промежутка или обобщенными пробель­ными символами. Поля просматриваются и вводятся функцией scanf( ) посимвольно. Чтение поля прекращается, если встретился пробельный символ или в спецификации преобразования точно ука­зано количество читаемых символов (см. ниже).

    Функция scanf( ) завершает работу, если исчерпана форматная строка. При успешном завершении scanf( ) возвращает количество прочитанных полей (точнее, количество объектов, получивших зна­чения при вводе). Значение EOF возвращается при возникновении ситуации «конец файла»; значение -1 - при возникновении ошибки преобразования данных.

    Форматная строка ограничена двойными кавычками и может включать:

    • пробельные символы, отслеживающие разделение входного потока на поля. Пробельный символ указывает на то, что из входного потока надо считывать, но не сохранять все после­довательные пробельные символы вплоть до появления не­пробельного символа. Один пробельный символ в форматной строке соответствует любому количеству последовательных пробельных символов во входном потоке;

    • обычные символы, отличные от пробельных и символа '%'. Обработка обычного символа из форматной строки сводится к чтению очередного символа из входного потока. Если прочи­танный символ отличается от обрабатываемого символа фор­матной строки, функция завершается с ошибкой. Несовпав­ший символ и следующие за ним входные символы остаются непрочитанными;

    • спецификации преобразования.

    Спецификация преобразования имеет следующую форму:

    % * ширина_поля модификатор спецификатор

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

    Необязательные элементы спецификации преобразования имеют следующий смысл:

    • * - звездочка, следующая за символом процента, запрещает запись значения, прочитанного из входного потока по адресу, задаваемому аргументом. Последовательность кодов из вход­ного потока прочитывается функцией scanf(), но не преобра­зуется и не записывается в переменную, определенную оче­редным аргументом.

    • Ширина_поля - положительное десятичное целое, опреде­ляющее максимальное число символов, которое может быть прочитано из входного потока. Фактически может быть про­читано меньше символов, если встретится пробельный символ или символ, который не может быть преобразован по заданной спецификации.

    • Модификатор - позволяет задать длину переменной, в кото­рую предполагается поместить вводимое значение. Модифика­тор может принимать следующие значения:

    • L - означает, что соответствующий спецификации преоб­разования аргумент должен указывать на объект типа long double;

    • l - означает, что аргумент должен быть указателем на пере­менную типа long, unsigned long или double;

    • h - означает, что аргумент должен быть указателем на тип short.

    Спецификация преобразования имеет следующую форму:

    % * ширина_поля модификатор спецификатор

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

    Необязательные элементы спецификации преобразования имеют следующий смысл:

    • * - звездочка, следующая за символом процента, запрещает запись значения, прочитанного из входного потока по адресу, задаваемому аргументом. Последовательность кодов из вход­ного потока прочитывается функцией scanf(), но не преобра­зуется и не записывается в переменную, определенную оче­редным аргументом.

    • Ширина_поля - положительное десятичное целое, опреде­ляющее максимальное число символов, которое может быть прочитано из входного потока. Фактически может быть про­читано меньше символов, если встретится пробельный символ или символ, который не может быть преобразован по заданной спецификации.

    • Модификатор - позволяет задать длину переменной, в кото­рую предполагается поместить вводимое значение. Модифика­тор может принимать следующие значения:

    • L - означает, что соответствующий спецификации преоб­разования аргумент должен указывать на объект типа long double;

    • l - означает, что аргумент должен быть указателем на пере­менную типа long, unsigned long или double;

    • h - означает, что аргумент должен быть указателем на тип short.

    Таблица 7.2. Спецификаторы форматной строки для функции форматного ввода

    Спе- цифи- катор

    Ожидаемый тип вводимых данных

    Тип аргумента

    d

    Десятичное целое

    int *

    o

    Восьмеричное целое

    int *

    х

    Шестнадцатеричное целое

    int *

    i

    Десятичное, восьмеричное или шестнадцатерич­ное целое

    int *

    u

    Десятичное целое без знака

    unsigned int *

    e, f, g

    Вещественное значение вида:

    [+|-]dddd [E|e[+|-]dd],

    состоящее из необязательного знака (+ или -), последовательности из одной или более десятич­ных цифр, возможно, содержащих десятичную точ­ку, и необязательного порядка (признак «е» или «Е», за которым следует целое значение, возможно, со знаком)

    float *

    le, lf lg

    Для ввода значений переменных типа double ис­пользуются спецификаторы «%le», «%lf», «%lg»

    double *

    Le, Lf, Lg

    Для ввода значений переменных типа long double используются спецификаторы «%Le», «%Lf», «%Lg»

    long double *

    с

    Очередной читаемый символ должен всегда вос­приниматься как значимый символ. Пропуск на­чальных пробельных символов в этом случае по­давляется. (Для ввода ближайшего, отличного от пробельного, символа необходимо использовать спецификацию «%1s».)

    char *

    s

    Строка символов, ограниченная справа и слева пробельными символами. Для чтения строк, не ограниченных пробельными символами, вместо спецификатора s следует использовать набор сим­волов в квадратных скобках. Символы из входного потока читаются до первого символа, отличного от символов в квадратных скобках. Если же первым символом в квадратных скобках задан символ '", то символы из входного потока читаются до первого символа из квадратных скобок

    Указатель char * на массив симво­лов, достаточный для размещения входной строки, и терминально­го символа ('\0'), который добав­ляется автомати­чески

    Контроль заключается в том, что во входном потоке должна при­сутствовать именно строка «code:» (без кавычек). Строка строка1 используется для комментирования вводимых данных, может иметь произвольную длину и пропускается при вводе. Отметим, что стро- ка1 и строка2 не должны содержать внутри себя пробелов. Текст программы приводится ниже:

    #include

    int main()

    {

    int i;

    int ret; /* Код возврата функции scanf() */

    char c, s[80];

    ret=scanf("code: %d %*s %c %s", &i, &c, s);

    printf("\n i=%d c=%c s=%s", i, c, s);

    printf("\n \t ret = %d\n", ret);

    return 0;

    }

    Рассмотрим форматную строку функции scanf( ):

    "code: %d %*s %c %s"

    Строка «code:» присутствует во входном потоке для контроля вво­димых данных и поэтому указана в форматной строке. Специфика­ции преобразования задают следующие действия:

    • %d - ввод десятичного целого;

    • %*s - пропуск строки (строка1 в приведенной выше форме ввода);

    • %с - ввод одиночного символа;

    • %s - ввод строки.

    Приведем результаты работы программы для трех различных на­боров входных данных.

    1. Последовательность символов исходных данных:

    code: 5 поле2 D asd

    Результат выполнения программы:

    i=5 c=D s=asd

    ret=3

    Значением переменной ret является код возврата функции scanf( ). Число 3 говорит о том, что функция scanf( ) ввела данные без ошибки и было обработано 3 входных поля (строки «code:» и «поле2» пропускаются при вводе).

    1. Последовательность символов исходных данных:

    code: 5 D asd

    Результат выполнения программы:

    i=5 c=a s=sd ret=3

    Обратите внимание на то, что во входных данных пропущена строка перед символом D, использующаяся как комментарий. В результате символ D из входного потока был (в соответствии с форматной строкой) пропущен, а из строки «asd» в соответ­ствии с требованием спецификации преобразования %c был введен символ 'a' в переменную с. Остаток строки «asd» (sd) был введен в массив символов s. Код возврата (ret=3) функции scanf( ) говорит о том, что функция завершила свою работу без ошибок и обработала 3 поля.

    1. Последовательность символов исходных данных:

    cod: 5 поле2 D asd

    Результат выполнения программы:

    i=40 c= s= )

    ret=0

    Вместо предусмотренной в форматной строке последовательно­сти символов в данных входного потока допущена ошибка (набрано слово cod: вместо code:). Функция scanf( ) завершается аварийно (код возврата равен 0). Функция printf( ) в качестве результата на­печатала случайные значения переменных i, c и s.

    Необходимо иметь в виду, что функция scanf( ), обнаружив ка­кую-либо ошибку при преобразовании данных входного потока, за­вершает свою работу, а необработанные данные остаются во входном потоке. Если функция scanf( ) применяется для организации диа­лога с пользователем, то, будучи активирована повторно, она дочи­тает из входного потока «остатки» предыдущей порции данных, а не начнет анализ новой порции, введенной пользователем.

    Предположим, что программа запрашивает у пользователя номер дома, в котором он живет. Программа обрабатывает код возврата функции scanf( ) в предположении, что во входных данных при­сутствует одно поле.

    #include int main()

    {

    int number;

    printf("Beegume номер дома: ");

    while (scanf("%d", &number) != 1)

    printfC’OuudKa. Введите номер дома: ");

    printf("HoMep вашего дома %d\n", number); return 0;

    }

    При правильном вводе данных (введено целое десятичное число) результат будет следующий:

    Введите номер дома: 25

    Номер вашего дома 25

    Предположим, что пользователь ошибся и ввел, например, сле­дующую последовательность символов «@%». (Эти символы будут введены, если нажаты клавиши '2' и '5', но на верхнем регистре, то есть одновременно была нажата клавиша .) В этом случае получится следующий результат:

    Введите номер дома: @%

    Ошибка. Введите номер дома:

    Ошибка. Введите номер дома:

    Ошибочный символ @ прерывает работу функции scanf( ), но сам остается во входном потоке, и вновь делается попытка его преобра­зования при повторном вызове функции в теле цикла while. Однако эта и последующие попытки ввода оказываются безуспешными, и программа переходит к выполнению бесконечного цикла. Необхо­димо до предоставления пользователю новой попытки ввода номера дома убрать ненужные символы из входного потока. Это предусмот­рено в следующем варианте той же программы:

    #include

    int main()

    {

    int number;

    printf("Beegume номер дома: ");

    while (scanf("%d", &number) != 1)

    {

    /* Ошибка. Очистить входной поток: */

    while (getchar() != '\n')

    printf("Ошибка. Введите номер дома: ");

    }

    printf("Номер вашего дома %d\n", number);

    return 0;

    }

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

    Введите номер дома: @%

    Ошибка. Введите номер дома: 25

    Номер вашего дома 25

        1. Работа с файлами на диске

    Так же как это делается при работе со стандартными потоками ввода-вывода stdin и stdout, можно осуществлять работу с файлами на диске. Для этой цели в библиотеку языка Си включены следую­щие функции:


  • написать администратору сайта