Прекращает выполнение ближайшего вложенного внешнего оператора switch, while, do или for. Управление передается оператору, следующему за заканчиваемым. Одно из назначений этого оператора -закончить выполнение цикла при присваивании некоторой переменной определенного значения.
Пример
for (i = 0, i < n; i++) if((a[i] =b[i])==0) break,
Примеры
extern int Global_var;
extern char *Name;
extern int func();
Можно опускать длину внешнего одномерного массива.
Пример
extern float Num_array [ ];
Поскольку все функции определены на внешнем уровне, то для описания функции внутри блока прилагательное extern избыточно и часто опускается.
Пример
int Global_flag;
Определяются на том же уровне, что и функции, т. е. не локальны ни в каком блоке. Постоянные. Инициализируются нулем, если явно не задано другое начальное значение. Областью действия является вся программа. Должны быть описаны во всех файлах программы, в которых к ним есть обращения. 3 амечание. Некоторые компиляторы требуют, чтобы глобальные переменные UHggonpenei^ лены только в одном файле и описаны как внешние вдругахфай-лах, где они используются (см. с. 51). Должны быть описаны в файле до первого использования.
Статические переменные
Пример
static mt File _ flag;
Постоянные. Областью действия является файл, в котором данная переменная определена. Должны быть описаны до первого использования в файле.
Замечание 2 Все описания в блоке должны предшествовать первому оператору Автоматические переменные Пример
mt x, /* х - это автоматическая переменная */ }
Автоматическая переменная является временной, так как ее значение теряется при выходе из блока. Областью определения является блок, в котором эта переменная определена. Переменные, определенные в блоке, имеют приоритет перед переменными, определенными в охватывающих блоках.
Регистровые переменные
Пример
{
register mt у;
}"
Регистровые переменные являются временными, их значения сохраняются в регистрах, если последние доступны. Доступ к регистровым переменным более быстрый. В регистрах можно сохранять любые переменные, если размер занимаемой ими памяти не превышает разрядности регистра. Если компилятор не может сохранить переменные в регистрах, он трактует их как автоматические. Областью действия является блок. Операция получения адреса & не применима к регистровым переменным.
Формальные параметры
Примеры
mt func(x), int func(x) int x; register int x;
Формальные параметры являются временными, так как получают значения фактических параметров, передаваемых функции. Областью действия является блок функции. Формальные параметры должны отличаться по именам от внешних переменных и локальных переменных, определенных внутри функции. В блоке функции формальным параметрам могут быть присвоены некоторые значения.
Статические переменные
Пример
{ static int flag }
Статические переменные являются постоянными, так как их значения не теряются при выходе из функции. Любые переменные в блоке, кроме формальных параметров функции, могут быть определены как статические. Областью действия является блок.
char с,
int х;
Основными типами являются:
char - символ (один байт) ;
int - целое (обычно одно слово);
unsigned - неотрицательное целое (такого же размера, как целое);
short - короткое целое (слово или полуслово);
long - длинное целое (слово или двойное слово);
float - число с плавающей точкой (ординарной точности);
double - число с плавающей точкой (двойной точности);
void - отсутствие значения (используется для нейтрализации
значения, возвращаемого функцией). Символы (char) в зависимости от компилятора могут быть со знаком или без знака. Рассматриваемые как целые, символы со знаком имеют значения от -127 до 128, а символы без знака - от 0 до 256. Некоторые реализации допускают явный тип unsigned char. Данные целого типа int могут иметь такой же диапазон, как данные типа long иди short. Описание типа unsigned эквивалентно описанию типа unsigned int. Описание unsigned может сочетаться с описанием типа char, short или long, формируя описания типов unsigned char, unsigned short, unsigned long. Описания типов short и long эквивалентны описаниям типов short int и long mt. Диапазон данных типа long обычно в два раза больше диапазона данных типа short
opposite = mask,
” Использование: iel ” ie2 Двоичное представление iel сдвигается вправо на ie2 разрядов. Сдвиг вправо может быть арифметическим (т. е. освобождающиеся слева разряды заполняются значением знакового разряда) или логическим в зависимости от реализации, однако гарантируется, что сдвиг вправо целых чисел без знака будет логическим и освобождающиеся слева разряды будут заполняться нулями. Пример: х= х” 3;
“ Использование: iel “ ie2 Двоичное представление iel сдвигается влево на ie2 разрядов; освобождающиеся справа разряды заполняются нулями. Пример: fourx= x“ 2;
& Использование: iel & ie2 Побитовая операция И двоичных представлений iel и ie2. Значение выражения содержит 1 во всех разрядах, в которых и iel и ie2 содержат 1, и 0 во всех остальных разрядах. Пример: flag = ((х & mask) != 0);
I Использование: iel | ie2 Побитовая операция ИЛИ двоичных представлений iel и ie2. Значение выражения содержит 1 во всех разрядах, в которых iel или ie2 содержит 1, и 0 во всех остальных разрядах. Пример: attrsum= attrl I attr2:
*> Использование: iel* ie2 Побитовая операция исключающее ИЛИ двоичных представлений iel и ie2. Значение выражения содержит 1 в тех разрядах, в которых iel и ie2 имеют разные двоичные значения, и 0 во всех остальных разрядах. Пример:
diifbits= x'y;
Определение int имя_макроса (с)
int с,
toascu - преобразование целого в символ кода ASCII tolower - преобразование буквы в нижний регистр toupper - преобразование буквы в верхний регистр _tolower - такая же, как tolower, но более быстрая и ограниченная
функция. _toupper - такая же, как toupper, но более быстрая и ограниченная функция
Определение long strtol (sir, ptr, base) char *str, **ptr, int base,
atol — преобразование строки в длинное целое число (специальный
вариант функции strtol())
Определение: long atol (str) char *str,
atoi — преобразование строки в целое.
Преобразование в тип int результата, возвращаемого функцией atol()
Определение int atoi (str)
char *str,
atof — преобразование строки в число двойной точности с плавающей точкой
Определение double atof (str) char *str,
strtod — преобразование строки в число двойной точности с плавающей точкой
Определение, double strtod (str, ptr) char *str, *ptr,
int func();
Функция, не возвращающая значения, должна описываться как имеющая тип void. Если тип функции явно не задан, считается, что она имеет тип int. Областью действия описания на внешнем уровне является остаток файла; внутри блока областью действия является данный блок. Обычно внешние описания располагаются в начале файла. Некоторые компиляторы допускают описание переменных на внешнем уровне без прилагательного extern. Многократные описания внешних переменных компоновщик сводит к одному определению.
Если в качестве первого символа в строке программы используется символ #, то эта строка является командной строкой препроцессора (макропроцессора). Командная строка препроцессора заканчивается символом перевода на новую строку. Если непосредственно перед концом строки поставить символ обратной косой (\), то командная строка будет продолжена на следующую строку программы.
#include <ctype.h>
Определение: int имя_макроса (с)
int с
isalpha Символ с — буква
isupper Символ с - прописная буква (в верхнем регистре)
islower Символ с - строчная буква (в нижнем регистре)
isdigit Символ с - цифра (0 - 9).
isxdigit Символ с - шестнадцатеричная цифра (0 - 9), прописная (А - F) иди строчная (а - f) буква
isalnum Символ с — буква или цифра
isspace Символ с - символ пробела, табуляции, перевода строки, новой строки, вертикальной табуляции или перевода фор мата
ispunct Символ с - символ пунктуации, т е не управляющий сим вол, не буква, не цифра и не пробел
isprint Символ с - печатный, т е имеющий значение (в коде ASCII) от 040 (пробел) до 0176 (тильда)
isgraph Символ с - графический, т е печатный, за исключением пробела
iscntrl Символ с - управляющий (0 - 037) или символ удаления (0177)
isascii Символ с — символ кода ASCII, т е его значение лежит в диапазоне от 0 до 0200
Определение: char *malloc (size) unsigned size;
calloc - выделение памяти и обнуление ее.
Определение: char *calloc (nelem, elsize) unsigned nelem, elsize;
realloc — изменение размера ранее выделенной памяти.
Определение: char *realloc (ptr, size) char *ptr;
unsigned size;
free - освобождение ранее выделенной памяти.
Определение: void free (ptr) char *ptr;
Примеры:
'А' 'а' 'Т '$' Специальные (управляющие) символьные константы
Новая строка (перевод строки) HL (LF) '\п'
Горизонтальная табуляция НТ '\t'
Вертикальная табуляция VT '\v'
Возврат на шаг BS '\Ь'
Возврат каретки CR '\г'
Перевод формата FF '\f
Обратная косая \ '\\'
Апостроф ' '\"
Кавычки " '\" '
Нулевой символ (пусто) NUL '\0.'
Кроме этого любой символ может быть представлен последовательностью трех восьмеричных цифр: '\ddd'. Замечание. Символьные константы считаются данными типа int.
Пример
{х=1; у=2; z=3;}
feof - проверить состояние конца файла в потоке. Определение: int feof (stream) FILE *stream,
ferror — проверить состояние ошибки в потоке. Определение: int terror (stream) FILE *stream;
fileno - связать дескриптор файла, открытого функцией open существующим потоком. Определение: int fileno (stream) FILE * stream;
L признаки J преобразования
Символ * обозначает пропуск при вводе поля, определенного данной спецификацией; вводимое значение не присваивается никакой переменной.
Ширина определяет максимальное число символов, вводимых по данной спецификации.
Буква 1 определяет тип вводимых данных как long, буква h - как short. По умолчанию принимается тип int. Символы преобразования
d - десятичное целое со знаком;
u — десятичное целое без знака;
о — восьмеричное целое без знака;
х - шестнадцатеричное целое без знака.
Буква 1 определяет тип вводимых данных как double, по умолчанию принимается тип float. Символы преобразования f, e, g являются синонимами.
Образец (сканируемое множество) определяет множество символов, из которых может состоять вводимая строка, и задается строкой символов, заключенной в квадратные скобки.
Примеры
[abed]
[А321]
Непрерывный (в коде ASCII) диапазон символов образца описывается первым и последним символами диапазона.
Примеры
[а-z]
[А - FO - 9]
Если на первом месте в образце стоит символ ", то вводиться будут все символы из входного потока, кроме перечисленных в образце, т. е. допустимое по этой спецификации множество символов будет дополнительным к описанному.
Пример
[О-9]
По спецификации преобразования, заданной образцом, вводится строка символов, включая завершающий ее нулевой символ. Ведущие пустые символы не пропускаются.
Ширина определяет число символов, которые должны быть прочитаны из входного потока и присвоены массиву символов. Если ширина опущена, то вводится один символ. По данной спецификации можно вводить пустые символы.
Ширина описывает максимальную длину вводимой строки. Строки во входном потоке должны разделяться пустыми символами;
ведущие пустые символы игнорируются.
Символ # определяет вывод начального нуля в восьмеричном формате или вывод начальных Ох или ОХ в шестнадцатеричном формате. Символ 1 необходим для данных типа long. Символы преобразования
u — десятичное без знака;
о - восьмеричное без знака;
х — шестнадцатеричное без знака;
Х - шестнадцатеричное без знака с прописными буквами А - F.
Примеры (для 32-разрядных чисел)
%u
777626577
%о 5626321721
%#о 05626321721
%х 2e59a3dl
%#Х OX2E59A3D1
Для отрицательных чисел автоматически выводится знак - (минус). Для положительных чисел знак + (плюс) выводится только в том случае, если задан признак +; если в спецификации задан пробел ^>, то в позиции знака выводится пробел. Символы преобразования
l — необходим для данных типа long';
d - определяет вывод данных типа int в десятичном формате
со знаком.
Примеры
%d 43
%+d +43
%d
[#] [ширина] [.точность] 1 Е
Для отрицательных чисел автоматически выводится знак - (минус). Для положительных чисел выводится знак + (плюс), если задан признак +; если в спецификации задан пробел ^, то в позиции знака выводится пробел.
Завершающие нули не выводятся, если в спецификацию не включен признак #. Этот признак также обусловливает вывод десятичной точки даже при нулевой точности.
Точность определяет число цифр после десятичной точки для форматов f, е и Е или число значащих цифр для форматов g и G. Округление "делается отбрасыванием. По умолчанию принимается точность в шесть десятичных цифр.
Примеры
%с А
%3с WA %-3с AW
Точность определяет число печатаемых символов. Если строка длиннее, чем заданная точность, то остаток строки отбрасывается.
Пример
%10s abcdefghijklrnn
%-10.5s abcde^^
%10.5s )W^abcde
Примеры:
"This is a character string"
"Это строковая константа"
"А" "1234567890" "О" "$"
Строковая константа - это массив символов, заключенный в кавычки; она имеет тип char [ ].
В конце каждой строки компилятор помещает нулевой символ '\0', отмечающий конец данной строки.
Каждая строковая константа, даже если она идентична другой строковой константе, сохраняется в отдельном месте памяти. Если необходимо ввести в строку символ кавычек ("), то перед ним надо поставить символ обратной косой (\). В строку могут быть введены любые специальные символьные константы, перед которыми стоит символ \. Символ \ и следующий за ним символ новой строки игнорируются.
//файл bblsort.h
#define MAXLINES 100
#define LINLSIZE (132+1)
main.c
include <stdio h>
include "bblsort h"
char Lme[MAXLINES]ELINESIZE], /* буфер строк */ С int Revfig , /* признак направления * сортировки */
/*
* сортировка строк текста в лексикографическом порядке
*/
main(argc, argv)
D char **argv, /* аргументы вызова программы */
int argc, /* число аргументов */
{
int rdlinesO;
void bblsortO, wrlines();
int numlines;
G Revflg = (argc > 1 && |argv[l][0] [ == '-');
numlines = rdlinesO;
bblsort(numlmes);
wrlines(numlines),
/* запись строк со стандартного выхода*/
Н static int rdlinesO
chai^ *fgets(), / register int l;
/ foi(i=0,i< MAXLINES; i++)
if (fgets(Lme[i], LINESIZE, stdin)
/ == ] (char *)NULL ) break;
return (i);
}
/* запись строк на стандартный выход*/
Структура программы 57
К static void wrhnes(n) L register mt n; /* число строк */
{
register int l,
for (i = 0; i < n; i++) fputs(Lme [i], stdout);
bblsort.c
# include "bblsort.h"
N extern char Line [] [LINESIZE]; [
/* bubble sort */
void bblsort(n) register int n; /* число строк */
int lexcmp();
void swap();
regicterint i,j;
for (i = 1; i <= n - 1; i++) for(J=n- 1;j>= i;J—) if (lexcmp(j - 1, J)) swapO - l.j);
/* лексикографическое сравнение двух строк */
static int lexcmp(i,J)
register int i, j; /* элементы массива строк */ {
strcmp();
extern int Revflg;
register int Ic;
Ic = strcmp(Line [i], Line [j]);
return ((Ic < 0 && Revflg)
(Ic > 0 && '.Revflg));
/* обмен строк */
static void swap(iJ) register int i, j; /* элементы массива строк */
Указатель на основной тип
Пример
char *p,
Переменная р является указателем на символ, т. е. этой переменной должен присваиваться адрес символа. Указатель на указатель
Пример
char **t,
Переменная t - указатель на указатель символа. Одномерный массив
Пример
int a [50];
Переменная а - массив из 50 целых чисел. Двухмерный массив
Пример
char m[7][50];
Переменная m - массив из семи массивов, каждый из которых
состоит из 50 символов. Массив из семи указателей
Пример
char *G[7];
Массив G состоит из указателей на символы. Указатель на функцию
Пример
int (*f)();
f - указатель на функцию, возвращающую целое значение.
struct имя _структуры {
описания_элементов
Пример
struct dinner {
char * place,
float cost,
struct dinner *next, };
Структурная переменная описывается с помощью структурного типа.
Примеры
struct dinner week_days [7], /* массив структур */
struct dinner best_one, /* одна структурная переменная */
struct dinner *p; /* указатель на структурную переменную */
struct bfeg {
unsigned int of_fldl 10;
unsigned int bf_fld2 :
Данная структура описывает 10-битовое поле, которое для вычислений преобразуется в значение типа unsigned int, и 6-битовое поле, которое обрабатывается как значение типа unsigned int.
Определение объединенного типа данных аналогично определению структурного типа данных
union имя объединения { описания_элементов },
Пример
#if АВС + 3
Истина, если конвтантное выражение АВС + 3 не равно нулю #fdef идентификатор
Пример
#ifdef АВС
Истина, если идентификатор АВС определен ранее командой #define #ifndef идентификатор
Пример
#ifndef АВС
Истина, если идентификатор АВС не определен в настоящий момент #else
#endif
Если предшествующие проверки #if, #ifdef или #ifndef дают значение Истина, то строки от #else до #endif игнорируются при компиляции
Если эти проверки дают значение Ложь, то строки 01 проверки до #else (а при отсутствии #else — до #endif) игнорируются Команда #endif обозначает конец условной компиляции
Пример
#ifdef DEBUG
iprmtf (stderr, "location x = %d\ n", x), #endif
Если выражение истинно, то выполняется оператор. Если выражение ложно, то ничего не делается.
Пример
if (а == х) temp = 3;
temp = 5,
if (выражение)
оператор} else
оператор2
Если выражение истинно, то выполняется оператор и управление передается на оператор, следующий за оператором (т. е. оператор2 не выполняется). Если выражение ложно, то выполняется оператор2.
Часть else оператора может опускаться. Поэтому во вложенных операторах if с пропущенной частью else может возникнуть неоднозначность. В этом случае else связывается с ближайшим предыдущим оператором if в том же блоке, не имеющим части else
Примеры
Часть else относится ко второму оператору if:
if (х > 1) if (у==2)
z= 5; else z=6,
Часть else относится к первому оператору if if(x>l){ if (У==2)
z= 5; else z= б,
Вложенные операторы
if (х == 'а') У=1,
else if (x=='b'){
У=2; z=3; у else if (x == 'c')
У =4; else
printf("ERROR"),
Если использовать верификатор lint на всех этапах разработки, то программный продукт будет гораздо легче переносить на любую версию ОС UNIX. Если вам потребуется переписать старую программу для повышения мобильности, то верификатор lint поможет вам выявить все сомнительные места.
Верификатор lint - это хорошее сервисное средство для разработки мобильных программ. Однако не надейтесь, что ваша программа является мобильной, если верификатор lint "не имеет к ней никаких претензий", и не полагайтесь на него, если программа написана плохо, так как верификатор может пропустить некоторые немобильные конструкции. Следуйте изложенным в этом разделе рекомендациям, улучшающим стиль программ.
#include (имя _файла'1
Пример
#mclude <riath.h>
Препроцессор заменяет эту строку содержимым файла math.h. Угловые скобки обозначают, что файл math.h будет взят из некоторого стандартного каталога (обычно это /usr/mclude). Текущий каталог не просматривается. #include "имя_файла"
Пример
#mclude "ABC"
Препроцессор заменяет эту строку содержимым файла ABC. Так как имя файла заключено в кавычки, то поиск производится в текущем каталоге (в котором содержится основной файл исходного текста). Если в текущем каталоге данного файла нет, то поиск производится в каталогах, определенных именем пути в опции -1 препроцессора Если и там файла нет, то просматривается стандартный каталог
tmpnam — создать временное имя файла.
Определение: char *tmpnam (s) char *s;
tempnam - создать временное имя файла, используя каталог dir и
префикс файла pfx.
Определение: char *tempnam (dir, pfx) char *dir, *pfx,
mktemp - создать уникальное имя файла по шаблону, записанному
в строке template.
Определение: char *mktemp (template) char *template;
tmpfile - создать временный файл.
Определение: FILE *tmpfile ()
Определение: char *fgets (s, n, stream) char *<;
int n, FILE *stream;
gets — прочитать строку из стандартного файла ввода stdm. Определение: char *gets(s) char *s;
fputs - записать строку в поток stream. Определение: int fputs (s, stream) char *s;
FILE *stream, puts — записать строку в стандартный файл вывода stdout. В конце
строки записывается символ новой строки. Определение: int puts (s) char *s;
Ввод символа
fgetc — прочитать следующий символ из входного потока stream Определение: int fgetc (stream) FILE •stream;
Замечание. Функции getc(), getchar(), ungetc() являются макроопределениями.
getc - прочитать следующий символ из входного потока.
Определение: int getc (stream)
FILE *stream, getchar - прочитай, следующий символ из стандартного файла ввода.
Определение: int getchar ()
ungetc - вернуть символ во входной поток. Определение: int ungetc (с, stream) int с, FILE * stream;
#include <stdio.h>
system - выполнить команду языка shell, описанную как строка string.
Определение: int system (string) char * string
FILE * stream;
Замечание. Функции putc() и putchar() являются макроопределениями.
putc - записать символ в поток. Определение: int putc (с, stream) int с, FILE *stream,
putchar - записать символ в стандартный файл вьшода. Определение: int putchar (с) int с;
имя_функцш (е1, е2,. .., eN)
(указатель _на_функцию) (е1, е2,..., eN) Указатель _на_функцию - это переменная, содержащая адрес функции. Адрес функции может быть присвоен указателю оператором
указатель_на_функцию = имя _функции;
Аргументы (фактические параметры) передаются по значению, т. е. каждое выражение el, . . . , eN вычисляется и значение передается функции, например, загрузкой в стек. Порядок вычисления выражений и порядок загрузки значений в стек не гарантируются. Во время выполнения не производится проверка числа или типа аргументов, переданных функции. Такую проверку можно произвести с помощью программы lint до компиляции (см. с. 78). Вызов функции - это выражение, значением которого является значение, возвращаемое функцией. Описанный тип функции должен соответствовать типу возвращаемого значения. Например, если функция linfunc возвращает значение типа double, то эта функция должна быть описана до вызова:
extern double ' linfunc();
Замечание. Такое описание не определяет функцию, а только описывает тип возвращаемого значения; оно не нужно, если функция определена в том же файле до ее вызова (см. с. 42).
Примеры
Правильно: extern double linfuncO;
float у;
у = linfunc (3.05, 4.0, le-3), Значение функции перед присваиванием переменной у преобразуется из типа double в тип float.
Неправильно: float х;
float у;
х=3.05;
у = linfunc (х, 4, le-3);
Тип аргументов не соответствует типу параметров, описанных в определении функции, а именно: константа 4 имеет тип int, а не double. В результате аргументы, загруженные в стек, имеют неправильные тип и формат, поэтому значения, выбираемые из стека, бессмысленны и значение, возвращаемое функцией, не определено. Кроме того, если тип функции не описан, то считается, что возвращаемое значение имеет тип int. Поэтому, даже если функция linfunc возвращает правильное значение типа double, выражение, представляющее вызов функции, получит бессмысленное значение типа int (например, старшая половина значения double).
Пример
#define ABC 100
Заменяет каждое вхождение идентификатора ABC а тексте программы на 100.
#undef идентификатор
Пример
#undef ABC Отменяет предыдущее определение для идентификатора ABC.
Размер данных типа mt зависит от размера машинного слова, различающегося у разных ЭВМ. Если вы не уверены в результате операций над целыми числами, используйте тип long, чтобы избежать проблемы переполнения.
Не гарантируется, что размер данных типа int совпадает с размером машинного слова. В языке Си определяется только, что размер данных типа short меньше или равен размеру данных типа
int. который, в свою очередь, меньше или равен размеру данных типа long. Размер слова может сказаться на обработке двоичных масок. Пример
#define MASK 0177770 /* неправильно*/
mt х,
х &= MASK;
В этом примере три правых бита целого х будут обнуляться только в том случае, если данные типа mt занимают 16 бит. Но если размер данных типа int больше 16 бит, то кроме этого будут обнуляться левые биты данного х. Чтобы избежать таких проблем, используйте следующее макроопределение:
#define MASK (~07) /* правильно */ int х;
х &=- MASK,
Этот пример корректен для всех ЭВМ независимо от размера
данных типа int
Тщательно проверяйте операции сдвига.
Максимальное число бит, которые могут быть сдвинуты вправо или влево, различно на разных ЭВМ. Если заданный в операции сдвиг превысит допустимый максимум, то результаты операции будут непредсказуемы.
Перед сдвигом преобразуйте целые значения к типу unsigned. На некоторых ЭВМ сдвиг выполняется логически, т. е. освобождающиеся разряды обнуляются. На других сдвиг производится арифметически, и освобождающиеся разряды заполняются значением знакового разряда. Однако в языке Си гарантируется, что значения типа unsigned сдвигаются логически.
Используйте поименованные константы.
Использование в программе числовых констант, особенно когда смысл их неочевиден, является плохим стилем программирования. Числовые константы лучше определять в программе символическими именами, связанными с числовыми константами командой препроцессора #defme. Такие определения легко находить и модифицировать, если они размещены в некотором стандартном месте. Обычно это начало программы или файл заголовка.