Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЯЗЫК СИ_РУКОВОДСТВО ПРОГРАММИСТА.doc
Скачиваний:
12
Добавлен:
18.08.2019
Размер:
438.27 Кб
Скачать

1.4. Работа со строками и символами

Во время выполнения программы, написанной на языке "СИ", строка символов представляется последовательностью байт, заканчивающейся нулевым байтом. принято нулевой байт записывать не как 0, а как '\0' или kak "EOS" (определен как 0 в файле "stdio.h"). Строка использутся, как правило, при помощи указателя на ее начало и в дальнейшем выражение "строка str" будет означать "строка, на начало которой указывает str", причем подразумевается, что "str" имеет тип "char *".

char *str;

strlen(str);

возвращает длину строки str в байтах. Конечний нулевой байт не

считается, так что строка "" будет иметь длину 0.

char *in; /* исходная строка */

char *out; /* указатель на буфер */

char *

strcpy(out, in);

char *

cpystr(out, in);

копируют строку in в буфер, на который указывает out.

strcpy() возвращает out.

cpystr() возвращает указатель на конец строки, записанной в out. Это позволяет использовать функцию cpystr() следующим образом:

char *ptr;

char bufferbufsiz;

extern char *cpystr();

ptr = cpystr(buffer, text);

ptr = cpystr(ptr, more_text);

В приведенном примере первым вызовом cpystr() строка text копируется в buffer, после чего вторым вызовом функции cpystr() к этой строке добавляется (приписывается) строка more_text.

char *out; /* вых. буфер */

char *in; /* вх. строка */

int count; /* число байт */

char *

strncpy(out, in, count);

копирует строку in в буфер out. В out записывается ровно count байт - если строка in короче, то out дополняется нулями, если длиннее, то остаток отбрасывается, причем в последнем случае out не завершается нулем. Возвращает out.

char *in;

char *out;

char *

strcat(out, in);

присоединяет ("приписывает") строку in к концу строки, уже находящейся в буфере out. Возвращает out.

char *out;

char *in;

int count;

char *

strncat(out, in, count);

присоединяет ("приписывает") строку in к концу строки, уже находящейся в буфере out. Если строка in содержит более count символов, то остаток строки отбрасывается. В count не входит нулевой байт, которым в любом случае завершается строка out. Возвращает out.

char *out; /* указатель на буфер */

char *in0; /* первая вх. строка */

char *in1; /* вторая --- // --- */

.......................................

char *

concat(out, in0, in1, ...., NULL);

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

char *a, *b; /* stroki */

strcmp(a, b);

сравнение двух строк возвращает результат:

-1 a < b

0 a == b

+1 a > b

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

char *a, *b;

int count; /* число символов */

strncmp(a, b, count);

сравнение строк, причем рассматриваются только первые count символов (если строки длиннее count). Возвращает результат сравнения:

-1 a < b

0 a == b

+1 a > b

О смысле сравнения см. strcmp().

char *a, *b;

streq(a, b);

проверяет строки на совпадение. Возвращает 1, если строки совпадают, и 0, если нет.

char *strn;

char sim; /* символ для поиска */

char *

index(strn, sim);

просмотр строки strn до первого появления символа sim. Если символ в строке найден, возвращает указатель на него, иначе возвращает NULL.

char *strn;

char sim;

char *

rindex(strn, sim);

возвращает указатель на место последнего появления символа "sim" в строке "strn", или NULL, если "sim" в "strn" отсутствует.

Существует (в данной библиотеке) два варианта реализации функций тестирования и модификации символов: в виде обычных функций и в виде макросов с аргументами. Второй вариант содержит большее число функций, работает быстрее, однако требует 0.5 Кб памяти (причем независимо от числа используемых функций, если оно, конечно, не равно нулю). Первый вариант работает несколько медленней, однако требует меньше памяти, особенно когда используется всего одна или две функции. Разумно в программах, где тестирование и модификация символов используется "между делом" использовать первый вариант, а в программах, существенно ориентированных на работу с символами (например, в лексических анализаторах) - второй. Необходимо обратить внимание на то, что эти функции рассчитаны на латинский двухрегистровый алфавит, и будут не совсем корректны для русского алфавита. Так, например, символы 'э', 'ш', 'щ', 'ч', 'ю' не будут трактоваться как буквы.

Первый вариант, настоящие функции: char c;

isupper(c); /* буква верхнего регистра */

islower(c); /* буква нижнего регистра */

isalpha(c); /* буква */

isdigit(c); /* цифра */

toupper(c); /* преобразование к верхнему регистру */

tolower(c); /* преобразование к нижнему регистру */

Возвращают ненулевое значение, если символ, являющийся входным аргументом, принадлежит соответствующему классу (класс указан в комментарии к обращению), и 0 в противном случае. Классы, используемые при определении функций,следующие: буквы верхнего регистра -латинские большие буквы, A-Z,коды символов 0101-0132. буквы нижнего регистра - латинские малые (или, для некоторых терминалов, русские большие), коды символов 0141-0172. Буквы - буквы на верхнем или на нижнем регистре. Цифры - цифры 0-9, коды 060-071. функции преобразования (tolower() и toupper()) возвращают преобразованный код символа. Преобразования выполняются только для букв (латинских).

Второй вариант, макросы:

Обращение к функциям:

#include <ctype.h> /* файл макроопределений */

isupper(c) /* буква верхнего регистра */

islower(c) /* буква нижнего регистра */

isalpha(c) /* буква */

isdigit(c) /* цифра */

isalnum(c) /* буква или цифра */

isxdigit(c) /* шестнадцатеричная цифра */

isspace(c) /* разделитель */

ispunct(c) /* символ пунктуации */

isgraph(c) /* видимый символ */

isprint(c) /* печатный символ */

iscntrl(c) /* управляющий символ */

isascii(c) /* 7-битный символ ASCII */

_toupper(c) /* преобразование к верхнему регистру */

_tolower(c) /* преовразование к нижнему регистру */

toascii(c) /* преобразование к 7-битному коду ASCII */

Макросы isxxxxx() возвращают ненулевое значение, если символ, являющийся входным аргументом, принадлежит соответствующему классу (класс указан в комментарии к обращению), и 0 в противном случае. Классы, дополнительно используемые при определении функций, следующие: шестнадцатеричные цифры - цифры и буквы a-f на любом регистре. разделители - символы '\t' ('\011'), '\n' ('\012'), ('\013'), '\f' ('\014'), '\r' ('\015'), "пробел" ('\040'). Символы пунктуации - разнообразные символы (все печатные небуквы и нецифры) с кодами 041-057, 072-0100, 0133-0140, 0173-0176. Видимые символы - все буквы, цифры и символы пунктуации. Печатные символы - видимые символы и пробел. управляющие символы - все неупомянутые символы с кодами 0-010, 016-037 и 0177. 7-битные символы ASCII - все символы, код которых (без учета знака) не больше 0177. Макросы преобразования _tolower() и _toupper() возвращают преобразованный код символа. преобразования выполняются только для букв, причем эти макросы не должны использоваться с аргументами, имеющими побочный эффект, например вида

_toupper(*ptr++);

В таких случаях применяйте функции "toupper()" и "tolower()". Макрос toascii() возвращает аргумент, преобразованный в 7-битный символ ASCII (см. выше) и может использоваться без ограничений.

int val;

abs(val);

возвращает абсолютное значение своего аргумента.

int start; /* стартовое состояние */

srand(start); /* запуск генератора случайных чисел */

rand(); /* возвращает случайное число */

При последовательных вызовах возвращает целые положительные числа в диапазоне от 0 до 2**15, входящие в псевдослучайную последовательность длиной 2**32. Распределение равномерное. Функция srand() может быть вызвана в любой момент для инициализации и реинициализации генератора, т.е. определения некоторой точки в псевдослучайной последовательности. отсутствие вызова srand() до первого использования rand() равносильно вызову srand(1).

char *buffer; /* указатель на строчку из 2-х байт */ swabb(buffer);

возвращает целое, полученное из переставленных байтов buffer0 и buffer1. buffer может не быть выровнен по границе слова.

int value;

swabi(value);

возвращает целое, полученное из value перестановкой байт (инструкцией "swab").

char *base; /* начало массива элементов */

int nel; /* число элементов */

int width; /* длина элемента в байтах */

int (*compar)( ); /* функция сравнения */

qsort(base, nel, width, compar); /* сортировка */

реализует алгоритм быстрой сортировки. аргументы: "base" - указатель на начало массива элементов, подлежащих сортировке, "nel" - число элементов, "width" - длина элемента в байтах, "compar" - указатель на функцию сравнения. Функция сравнения будет вызываться с двумя аргументами - указателями на сравниваемые элементы. Функция сравнения должна возвращать целое меньше, равное или больше нуля в зависимости от того, меньше, равен или больше первый элемент чем второй соответственно.

int count; /* число символов ASCII */

int *output; /* указатель на буфер для вывода */

char *input; /* указатель на входную строку */

ascr50(count, input, output);

преобразовывает "count" символов ASCII из строки "input" в код RADIX-50, и записывает полученное в "output" (на каждые 3 входных байта получается одно слово на выходе). Если "count" не кратно трем, или если строка короче "count", строка дополняется пробелами.

char *buff; /* выходной буфер */

int *r5vec; /* входной массив слов в RAD50 */

int r5cnt; /* число слов R50 для преобразования */

r50toa(buff, r5vec, count);

преобразует "count" слов из массива, на который указывает "r5vec" в строку символов ASCII, которая помещается в массив "buff" (по 3 выходных символа на каждое входное слово). Строка в "buff" не завершается нулем, все символы будут на верхнем регистре. "Зарезервированный" символ кода RADIX-50 (035) будет представлен символом '/'.

int count; /* число аргументов */

extern int routine(); /* имя функции */

return_value = call(routine, count, &arg1, ... &argn); позволяет вызывать функции с интерфейсом языка FORTRAN-IV, например функции из системной обьектной библиотеки, из программ на языке "СИ". Функция call(), кроме того, сохраняет регистры R2-R5. "routine" - имя подпрограммы (или функции) с интерфейсом языка FORTRAN-IV, "count" - число аргументов, передаваемых функции "routine", "arg1" - "argn" - эти аргументы (отметим, что передаются адреса аргументов, поэтому среди аргументов не должно быть регистровых переменных, к которым неприменима операция '&'). **********Необходимо заметить, что вызов функций, действительно написанных на ФОРТРАНе, приведет к интерференции исполняющих систем и достаточно сложным проблемам, которые станут практически неразрешимыми, если в этих функциях производится ввод/вывод средствами языка FORTRAN-IV. Возвращение чисел с плавающей точкой непредусмотрено.

long *tloc;

long

time(0);

long

time(tloc);

эмулирует системный вызов time ОС UNIX. Возвращает длинное целое,

содержащее число секунд, прошедших с 00:00 (полночи) 1 января 1970

г. Если аргумент "tloc" отличен от нуля, то то же значение

копируется по адресу "tloc". В ОС UNIX time() возвращает GMT, а не

локальное время, здесь же - локальное системное время. Алгоритм

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

1970 <= год < 2100.

#include <time.h>

long *clock; /* указатель на время,

полученное вызовом time() */

struct tm *

localtime(clock);

заполняет структуру tm, описанную в файле "time.h", в соответствии с

системным временем в формате ОС UNIX, полученным, например, вызовом

time(), и возвращает указатель на эту структуру. Возвращаемое

функцией значение указывает на статические данные, которые будут

перезаписываться при каждом вызове функции.

#include <setjmp.h>

jmpbuf env;

int val;

int setjmp(env);

int longjmp(env,val); /* выполнение нелокального goto */ используются, в основном, для обработки ошибок и событий, возникающих

в глубоко вложенных функциях. При этом неудобно возвращать по

цепочке функций некое "особое" значение, существенно удобнее иметь

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

где-то у начала цепочки вызовов. Возможность такого перехода и

предоставляют функции setjmp() и longjmp(). setjmp(env) запоминает в

статическом буфере "env" информацию о текущей точке программы и

возвращает 0. Функция longjmp(env, val), вызванная после вызова

setjmp(env), вызванная возможно в другой, глубоко вложенной функции,

востанавливает информацию о состоянии, запомненной setjmp(). При этом

выполнение программы продолжается (как-бы) с возврата из функции

setjmp(), но возвращаемое значение равно "val", установленой при

вызове longjmp() и не равно 0. (Если val == 0, то возвращается 1).

Как правило, эти функции используются так: if(i = setjmp(env))

/* действия, выполняемые при longjmp() */

else

/* действия, выполняемые после начальной

установки точки возврата вызовом setjmp().

как правило действия, приводящие к

вызову цепочки вложенных функций, в которых

используется longjmp(). */

.....................

longjmp(env, 1); /* во вложенной функции */ .....................

при возвращении по longjmp() глобальные и статические переменные

сохраняют значения, которые они имели непосредственно перед вызовом

longjmp(), регистровые переменные имеют значения, которые они имели

перед вызовом setjmp(), а автоматические (локальные) переменные -

значения, которые они имели перед вызовом из данной функции функции,

породившей цепочку вызовов, на которой был выполнен longjmp().

Необходимо отметить, что вызов longjmp(env, val) с env, не установленным setjmp(env) приведет к непредсказуемым результатам. То же произойдет, если функция, выполнившая в последний раз setjmp(env) в момент вызова longjmp(env, val) не активна, т.е. не находится выше в цепочке функций, вызвавших выполняющую longjmp() функцию.

exit();

int stat; /* статус завершения */

exits(stat);

extern int $$exst;/* фактический статус завершения для exit() */ осуществляют выход из программы на "СИ". При этом выполняются следующие действия в указанном порядке: вызывается функция "wrapup()" (возможно написанная пользователем, см ниже). Выводится (если необходимо) статистика выполнения ("профиль") программы (см. "средства отладки". "$$prof"). Закрываются все файлы. Выполняется фактический выход в монитор ОС (.EXIT). Вызывая exits() с аргументом, программа может передать статус завершения операционной системе. Возможные значения аргумента такие:

1 - success (нормально)

2 - warning (замечание)

4 - error (ошибка)

8 - severe error (грубая ошибка)

вызов exit() эквивалентен exits(1). Заметим также, что программа

может занести статус завершения непосредственно в глобальную

переменную $$exst и выйти по exit():

extern int $$exst;

...

$$exst = 4;

exit();

если функция main() завершается,это равносильно выполнению в конце

нее exit().

wrapup();

(библиотечный ее вариант не делает ничего) вызывается при завершении

программы - выполнении функции exit(), вызванной явно или неявно

(например, через error() или при завершении функции main()). Смысл в

том, что пользователь может написать собственную функцию,которая

заменит библиотечный вариант, и которая может выполнять некоторые

действия при завершении программы на "СИ" вызывается только один

раз, т.е. если функция wrapup() сама выполнит exit(), то нового

вызова wrapup() не будет.

int mytr4(); /* функция обраб. trap to 4 */

int mytr10(); /* функция обраб. trap to 10 */

$set4 (mytr4); /* перехват trap to 4 */

$set4 (0); /* возвращение стандартной реакции */

$set10(mytr10); /* перехват trap to 10 */

$set10(0); /* возвращение стандартной реакции */

служат для перехвата и собственной обработки прерываний по векторам 4

(недопустимый адрес и др.) и 10 (недопустимая инструкция). После

выполнения "$set4(mytr4)" при прерывании по вектору 4 будет

вызываться функция "mytr4()", написанная пользователем. Функция

"mytr4()" должна быть написана на "СИ" (в смысле "сохранять регистры

R2-R5") и может обращаться к четырем аргументам типа int. Например, при описании

mytr4(r0, r1, pc, psw)

int r0, r1, pc, psw;

............

r0 - значение регистра R0 при прерывании,

r1 - значение регистра R1 при прерывании,

pc - счетчик команд после прерывания,

psw - слово состояния процессора.

Если функция mytr4() изменит эти аргументы, то при возврате из прерывания будут использованы новые значения.

Если функция mytr4() возвратит 1, то выполнение программы будет продолжено (обратите внимание - если прерывание произошло на многословной инструкции, то иногда необходимо скорректировать PC для нормального продолжения работы).

Если mytr4() возвратит 0, то будет выполнена стандартная реакция на прерывание. Для возвращения стандартной реакции системы необходимо вызвать функцию с нулевым аргументом. Функция $set10() работает полностью аналогично $set4(), только для прерывания по вектору 10. Использование других способов перехвата прерываний может нарущить работу эмуляторов EIS и FPU.

char *fmt; /* формат сообщения */

error(fmt, arg1, ... , argn);

завершает программу, выполняя следующие действия в указанном порядке:

выводит сообщение об ошибке, заданное форматом "fmt" и аргументами

"arg1 ... argn" (см. описание функции printf()) в stderr.

-если используются средства отладки, в stderr выводится путь вызова (см. calltr());

-выполняется выход из программы вызовом exit(), причем статус завершения (см. exit()) устанавливается в "error".

char *fmt; /* формат сообщения */

errmsg(fmt, arg1, ... ,argn);

выводит строку, заданную форматом "fmt" и аргументами в stderr. После

сообщения в stderr выводится '\n'. errmsg() ничего не возвращает.

perror, errtxt - вывести (получить) причину ошибки обращение к

функции:

char *umsg; /* дополнительное сообщение */

perror(umsg); /* вывод сообщения в stderr */

char *

errtxt(); /* получить указатель на сообщение */

При ошибке многие функции, работающие с файлами, а также некоторые функции, работающие с числами с плавающей запятой (double) не только отмечают факт возникновения ошибки, но и возвращают дополнительную информацию о ней. Эта информация возвращается через глобальную переменную "$$ferr" (эта переменная имеет альтернативное имя "errno" для совместимости с ОС UNIX) в виде небольшого положительного целого, причем 0 означает отсутствие ошибки.

0 "NO ERROR"

E_ILF 2 "ILLEGAL FILE NAME"

E_NOR 4 "NO ROOM FOR USER ON DEVICE"

E_FNF 5 "FILE NOT FOUND"

E_NOD 6 "NO A VALID DEVICE"

E_ILU 7 "I/O CHANNEL IN USE"

E_NOO 9 "I/O CHANNEL NOT OPEN"

E_EOF 11 "END OF FILE ON DEVICE"

E_FAT 12 "FATAL SYSTEM I/O FAILURE"

E_ERR 13 "USER DATA ERROR ON DEVICE"

E_FND 15 "FILE ALREADY FOUND (PROTECTED)"

E_NOC 17 "NO FREE I/O CHANNELS"

E_NSP 32 "NO MEMORY SPACE LEFT"

E_DOM 33 "ILLEGAL ARGUMENT"

E_RAN 34 "FLOATING OVERFLOW/UNDERFLOW"

----- ?? "UNINDENTIFY ERROR"

Коды ошибок можно анализировать непосредственно, в файле "ERRNO.H" содержатся мнемоники для них, однако при помощи данных функций можно получить сообщения в текстовом виде. Функция errtxt() возвращает указатель на строку, содержащую сообщение об ошибке, код которой записан в $$ferr. Функция perror() выводит в stderr строку, заданную аргументом, двоеточие, пробел, сообщение об ошибке и '\N', т.е., фактически выполняет fprintf(stderr, "%s: %s\n", umsg, errtxt()); функция perror() ничего не возвращает.