Professional Documents
Culture Documents
Programski Jazik C (II Izdanie) (Brajan V. Kernigan & Denis M. Richi) PDF
Programski Jazik C (II Izdanie) (Brajan V. Kernigan & Denis M. Richi) PDF
Programski Jazik C (II Izdanie) (Brajan V. Kernigan & Denis M. Richi) PDF
II 16945
db142
ПРОГРАМСКИ
ЈАЗИК
Брајан В. Керниган
Денис М. Ричи
'-' tamina
Ш (о. dp . G5,2.JSро11о Ѕ . /; 1(>9'-tS-- 8d1v 42.
cwr зз z. .;l~н. ..-
Програмски јазик
е
Второ издание
Програмски јазик
е
Второ издание
Authorized translation from the English language edition, entitled С PROGRAMMING LANGUAGE,
2nd Edition, 0131 103628 by KERNIGHAN, BRIAN W.; RIТCHIE, DENNIS, published by Pearson
Education, lnc, publishing аѕ Prentice Hall, Copyright © 1988, 1978 by Bell Telephone Laboratories,
lncorporated, by Prentice Hall, lnc., Upper Saddle River, NJ 07458
All the rights reserved. No part of this book may be reproduced or transmitted in any form or by
any means, electronic and mechanical, including photocopying, recording or by any information
storage retrieval system, without permission from Pearson Education, lnc. MACEDONIAN language
edition published by ARS LAMINA DOO, Copyright ©2009
Овластен превод од изданието на Англиски јазик под насл ов Програмски Јазик С, второ
издание, 0131103628 од Керниган, Брајан В.; Ричи , Денис; издадено од Pearson Education,
lnc., објавено како Prentice Hall, авторски права ©1988, 1978 од Bell Telephone Laboratories,
lncorporated, од Prentice Hall, lnc., Upper Saddle River, NJ 07458
Сите права се заджани. Ниту еден дел од оваа книга не смее да биде препечатуван или
пренесуван во било каква форма или со било как ви средства, електронски или механички,
вклучувајќи и фотокопирање, документирање или да биде сочуван во систем за повторно
пронаоѓање без писмена согласн ос т од издавачот.
Преведувач :
Стојан Котев
Стручен соработник :
м-р Миле Јова нов
004.432. 2с
КЕРНИГАН, Брајан В.
Програм ск и јазик С 1 Брајан В. Керниган, Денис М. Ричи. - Скопје
: Арс Ламина , 2009. - XIV, 350 стр. : илустр. ; 2б см
ISBN 978-б08-4535-48-5
1. Ств. н асл. на на спор. н асл. стр. 2. Ричи , Денис М. [avtor]. -
1. Kerпighan, Brian W. види Керниган, Брајан В .
.,..,...- · а~ Компјутерско програмирање - С (програмс ки јазик)
/ .. COB~SS.MK-ID 80939530
ФА "''<' 0::1 Zl\ [ '. >~"Tf'Q T( X ,..o,p А И
v -- t.o~ ·.• ..' ."-.:""" - ::.>..l('l :·or w-oи
.... " ':"Ј Г 1 L
БИБЛИОТЕК А
Предrовор xi
Предrовор кон првото и3дание xii
Вовед 1
v
Vl Програмски јазик С Содрж ина
А 13 Граматика 282
Индекс 321
Предговор
Xl
xii Предговор
ите во зборови и обратно. Како и претходно и овде сите примери беа тестирани
директно од текстот, т.е. во форма препознатлива за компјутерите.
Додатокот А, упатството за работа, не го претставува стандардот, туку е наш
обид да се прикаже неговата сушти на во пократок облик. Предвиден е да биде
лесно разбирлив од страна на програмерите, но не и да се користи како дефи
ниција од страна на креаторите на компајлери - таа улога недвосми слена му
припаѓа на самиот ста ндард. Додатокот Б претставува преглед н а можностите
на стандардната библиотека. Ова , исто така, е наменето за пов икување од стра
на н а програмерите, а не имплементирачите. Додатокот В нуди краток преглед
на измените во однос на оригиналното издание.
Брајан В. Керниган
Денис М . Ричи
Предrовор кон првото издание
X lll
xiv Предговор кон првото издание
Брајан В . Керниган
Денис М . Ричи
Вовед
компајлирање.
С е јазик од релативно "ниско ниво". Ваквата карактеризација не претставу
ва недостаток, туку означува дека С работи со истите видови на објекти со кои
работат и самите компјутери, а тоа се знаците, броевите и адресите. Наведените
објекти може да се комбинираат и преместуваат со помош на аритметички и
логички оператори имплементирани од постојни машини.
С не нуди операции кои работат директно со сложени објекти како што се
стринговите (низи од знаци) , множествата, листите или низите . Не постојат опе
рации кои обработуваат цела низа или стринг, иако структурите може да бидат
копирани како целина. С не дефинира ниту една друга можност за алоцирање
на мемориски простор освен статичката дефиниција и дисциплината на скла
дот (анг. stack), која е овозможена со локалните променливи од функциите; нема
хип (анг. heap) ниту собирање на ѓубре (анг. garbage collection). На крај, самиот С
не нуди влезно/ излезни можности; во него не постојат READ или WRITE искази,
ниту вградени методи за пристап до датотеките. Сите овие механизми од пови
соко ниво мора да бидат обезбедени од функции кои се повикуваат експлицит
но. Речиси сите имплементации н аС имаат релативно стандардна колекција од
такви функции.
Слично, С нуди само директен, единичен контролен тек: тестови, циклуси ,
групирање и потпрограми , но не и мултипрограмирање, паралелни операции,
кон јазикот.
Програмски јазик С 3
1.1 Почеток
Да се испишат зборовите
5
6 Краток вовед во јазикот С Глава 1
hello, world
#include <stdio.h>
main()
{
printf("hello, world\n");
се hello.c
Ако никаде не сте направиле грешка, во смисла да сте пропуштиле знак или
сте напишале некоја буква погрешно, компајлирањето ќе биде тив ко изведено
и ќе се создаде извршна датотека имен у вана а. out. Ако ја подигнете а . out со
отчукување на командата
a.out
ќе се испечати
hello, world
#include<stdiooh>
main ()
дефинира функцuја наречена
main која нема аргументи
Првата програма во С
те нешто како
#inelude <stdio.h>
main()
{
printf( "Hello ," ) ;
printf( " world" ) ;
printf( " \n " );
о -17
20 -6
40 4
60 15
80 26
100 37
120 48
140 60
160 71
180 82
200 93
220 104
240 115
260 126
280 137
300 148
#include <stdio.h>
/* nечатеае на Фарнхајт-Целзиус табела
за fahr =О , 20 , . .. , 300 */
main ()
{
int fahr , celsius ;
int lower, upper, step;
fahr = lower;
while (fahr <= upper) {
celsius = 5 * (fahr-32) 1 9 ;
printf("%d\t%d\n", fahr, celsius);
fahr = fahr + step ;
Д~ете линии
lower = О;
upper = 300;
step = 20;
while (i < ј)
i = 2 * i ;
celsius =5 * (fahr-32) 1 9 ;
о -17
20 -6
40 4
60 15
во 26
100 37
Иinclude <stdio.h>
fahr lower;
while (fahr <= upper) {
celsius = (5.0/9.0) * (fahr-32.0);
printf( "%3.0f %6.lf\n", fahr , celsius) ;
fahr = fahr + step ;
fahr = lower ;
и условот
о - 17 . 8
20 -б . 7
40 4.4
#include <stdio.h>
/* print Fahrenheit-Celsius table */
main ()
1.3 Исказот for 15
int fahr ;
fahr =О
се извршува само еднаш, пред да се влезе во телото на циклусот . Вториот дел
е условот кој го контролира циклусот :
fahr = fahr + 20
Понатаму , секоја појава н а име (не во наводници и не како дел од друго име)
ќе биде заменета со соодветната, текст з а замена. Име има ист облик како
и имињата на променливите: секвенца од букви или цифри што започнува со
буква. Текстот за замена може да биде каква било низа од знаци; не е огра
ничен само на броеви .
tinclude <stdio.h>
грамата .
е = getchar () ;
променливата е ја содржи вредноста на последниот влезен знак. Знаците во
општ случај доаѓаат од тастатура; влез од датотеки е обработен во Глава 7 .
Функцијата putchar печати еден знак при секое нејзин о повикување :
putchar(c) ;
прочитај знак
while (знакот не е знак за крај на датотека)
испрати го на излез штотуку прочитаниот знак
прочитај знак
18 Краток вовед во јазикот е Глава 1
#inelude <stdio.h>
е =
getehar () ;
while (е != EOF)
putehar(e);
е = getehar () ;
е = getchar ()
е израз и има некоја вредност. Тоа е вредноста на левата страна после доделу
вањето. Ова значи дека доделувањето може да се појави како дел од по голем из
раз. Ако доделувањето на еден знак е се стави внатре во условниот дел на еден
while циклус, програмата за копирање може да се напише на следниов начин:
1.5 Влез и излез на знаци 19
#inelude <stdio.h>
Циклусот while зема еден знак, го доделува на е и потоа проверува дали зна
кот е знак за крај на датотеката. Ако не е, се извршува телото наwhile циклу
сот, кој го печати знакот. Потоа
while се повторува. Кога конечно ќе се стигне
до крајот на влезот, завршува while циклусот , а со тоа и програмата main .
Оваа верзија се концентрира на влезот- сега има само едно повикување до
qetehar - а програмата е пократка . Резултантната програма е покомпактна
и, кога еднаш ќе навикнете на ваков облик на пишување на кодот, истиот ќе
ви биде полесен за читање. Со овој стил на пишување ќе се среќавате често.
(Сепак, во пишувањето на ваков начин може да се претера , што во чести си
туации доведува до замрсен код, нешто што ние ќе се обидеме да го избегнеме
овде.)
е = qetehar() != EOF
е еквивалентен н а
е = (qetehar() != EOF)
#include <stdio.h>
/* броеае знаци на влез ; 1-ва верзија */
main()
{
long nc ;
nc = О;
while (getchar() != EOF)
++nc ;
printf( "%ld\n", nc) ;
Наредбата
++nc ;
н е запознава со нов оператор, ++ , кој означува инкрементирање (зголемување
за еден). Наместо него можете да напишете nc = nc + 1, но ++nc е поконцизно ,
а честопати и поефикасно. Постои и соодветен -- оператор за декрементирање
{ намалување за еден). Операторите ++ и -- можат да се сретнат во префиксна
(++nc) и постфиксна форма (nc++) ; овие две форми во изразите резултираат
со различни вредности, како што ќе биде покажано во Глава 2, но и ++nc и nc++
го инкрементираат nc. Во моментов ќе се задржиме на префиксната форма.
Програмата за броење, наместо воint , го акумулира својот резултат во long
променлива . long целите броеви се со големина од најмалку 32 бита. Иако на
некои машини, int и long се со иста големина , на други int е со големи на од 16
битови , со максимална вредност од 327 67 , што овозможува релативно мал влез
да направи пречекорување кај бројач од тип int. Конверзната спецификација
%1d му сугерира на printf дека соодветниот а ргумент е цел број од тип long.
Можно е да се оперира дури и со поголеми броеви ако се користи double
(float со двојна прецизност) . Исто така, наместо while ќе користиме for ци
клус, со цел, да илустрираме алтернативен начин на пиш у вање на циклус.
#include <stdio.h>
Ако нема што да се работи, тогаш и не се работи, дури и ако тоа подразбира
да не се помине низ телото на циклусот. Програм ите треба интелигентно да
ги разрешуваат случаите каде податочниот влез има должина н ула. Ци клусите
while и for обезбедуваат добра работа на програмите и при тие граничн и ус
лови.
jinelude <stdio.h>
nl =О;
while ((е= getchar()) != EOF)
if (е = '\n')
++nl;
printf( "%d\n", nl);
множество знаци.
Излезните секве нци кај стр и нговите конс тант и, исто така, се легални и кај
з наковните константи, па '\n' оз н ачува вред ност за знак за нова линија, кој е
10 во ASCII. Треба да се забележи дека '\n ' претставува еден знак и во изра
зите се третира како целобројна вредност; од друга страна, "\n" претставува
стринг константа која содржи само еден знак. Прашањето за разликите помеѓу
стри нговите и знаците ќе биде дискутирано понатаму во Глава 2 .
#inelude <stdio.h>
state=OUT;
nl = nw = ne = О ;
while ( (е= getehar () ) ! = EOF) {
++n.C;
if (е= '\n')
++nl ;
if (е=='' 11 е= '\n' 11 e=::' \t' )
state =ОUТ;
else if (state=OUТ)
state = IN ;
++nw ;
nl = nw = ne = О ;
се интерпретира како "ако е е бланко или е е знак за нов ред или е е таб " .
(Потсетете се дека \t е видлива претстава на знакот таб . ) Постои и соодве
тен оператор && за л оги чко И ; неговиот приоритет е поголем од (веднаш пред)
приоритетот на 11 • Изразите поврзани со && и 11 се пресметуваат од лево кон
десно и се гарантира дека пресметката ќе застане во моментот кога вистини
тоста или неви стинитоста на изразот ќе станат познати. Ако е е бланко-знак ,
тогаш нема потреба да се тестира дали е знак за нова линија или таб , така што
тие проверки не се прават. Овде тоа и не изгледа важно , но е значајно во по
комплексни ситуации, како што ќе видиме набргу.
Примеров , исто така, го прикажува else, кој специфицира алтернативна ак
ција доколку е невистинит условот од if . Општиот облик е
if (израз)
наредба 1
else
наредба 2
Вежба 1-12 . Напишете програма која го печати нејзиниот влез, еден збор по ли
нија о
1.6 Низи
nwhite = nother = О;
for (i = О; i < 10 ; ++i)
ndigit[i] = О;
Декларацијата
intndigit[10];
определува дали знакот е е цифра. Ако е цифра, бројната вредност на таа цифра е
е- '0'
Ова функционира само ако '0', '1', ... , '9' имаат последователни растеч
ки вредности. За среќа, тој услов го исполнуваат сите знаковни множества .
По дефиниција, знаците се само мали цели броеви, па во аритметичките
изрази, ehar променливите се идентични со int променливите. Ова е при
родно и погодно; на пример изразот е- 'О' е целоброен израз со вредност
помеѓу о и 9, што за виси од вредноста на е, а со тоа е и погоден како индекс
на низата ndigit.
Одлуката за тоа дали еден знак е цифра, невидлив знак, или нешто друго се
изведува преку секвенцата
++ndigit[e-'0 ' ] ;
elseif (е=' ' 11 е== '\n' 11 е== '\t')
++nwhite;
else
++nother;
етруктурата
if (услов )
1
наредба 1
else if (услов )
2
наредба 2
else
наредба.
else if (услов)
наредба
1.7 Функции
#include <stdio.h>
p=l;
for (i=l ; i<=n; ++i)
р=р *base;
returnp;
искази (наредби)
Секој повик кон power предава два аргумента, при што секојпат функцијата
враќа цел број кој треба да се форматира и печати. За еден израз, power (2 , i)
претставува цел број, на ист начин како што се константата 2 и променливата
i. (Не сите функции даваат целоброен резултат ; ќе го продискутираме тоа во
Гл ава 4.)
Првата линија од самата power
return израз;
Декларацијата
intpower(intbase, intn);
30 Краток во вед во јаз и кот е Глава 1
пред самиот main 1 означува дека power е функција која очекува два
int аргу
мента и која враќа int. Оваа декларација 1 наречена
npomomun на функција
та 1 мора да се совпаѓа со дефиницијата и употребите на power. Погрешно е
доколку дефиницијата на функцијата или некој нејзи н повик не се совпаѓаат со
нејзиниот прототип .
Имињата на параметрите не мора да се совпаѓаат. Навистина 1 за еде н
функциски прототип имињата на параметрите се опционал ни 1 па кај прототи
пот можевме да напиш еме и:
int base 1 n ;
int i , р;
р = 1;
for (i = 1 ; i <= n ; ++i)
р = р * base ;
return р ;
земаат за тип int. (Телото на функцијата е исто како и во претходн иот случај)
Декларирањето на power на почетокот од програмата ќе изгледаше вака:
int power () ;
int р;
for (р = 1; n > О ; --n)
р =р * base;
return р;
#include <stdio.h>
#define МAXLINE 1000 /* махсимапна должина на влезот */
max = О ;
while ((len = getline(line, МAXLINE)) >О)
if (len > max) {
max = len ;
copy(longest , line);
int е, i;
for (i=O ; i < lim-1 && (c=getchar())!=EOF && c!=' \n'; ++i)
s[i] = е;
if (е= '\n' )
s[i] =е ;
++i ;
i = О;
while ( (to [i] from[i]) != ' \ 0')
++i ;
34 Краток вовед во јазикот е Глава 1
getline поставува знак '\ 0' (пи/lзнак , чија вредност е нула) на крајот од
стрингот што истата го креира, со што оз начува негов крај. Оваа конвенција се
користи и во е ; кога стринг константа како што е
"hello\n"
#include <stdio.h>
int getline(void);
void copy(void);
max = О ;
while ((len = getline()) >О)
if (len > max) {
max = len ;
сору () ;
int е , i ;
extern ehar line[] ;
if (е - '\n' ) {
line[i] = е;
++i;
line[i] = '\0';
return i;
i = О;
while ((longest[i] line [ i] ) ! = '\ О ' )
++i ;
функции.
Доколку nрограмата се состои од nовеќе изворни датотеки , nроменлива де
финирана во "датотекаl ", а се користи во "датотека2", и "датотекаЗ ",
38 Краток вовед во јазикот С Глава 1
Вежба 1-210 Напишете програма entab која заменува стрин гови од бла н ко
знаци со минимален број табови и бла нко-з наци кои заземаат еднаков прос
тор о Користете исти табулатори како и за detab о Доколку и та булатор и бла н ко
биле доволни да се достигне следниот таб-завршеток , на кој знак треба да му
се даде предност?
Вежба 1-22 о Напишете програма која ги " прекршува " долгите линии ко и до
аѓаат на влез, на две или повеќе по кратки линии после последн иот знак кој
не е бланко, а кој се јавува пред n-тата влез н а колона о Уверете се дека ваша
та програма интелигентно ги обработува долгите линии и во случај кога нема
бланко-знаци и табулатори пред специфицираната колона о
41
42 Типови, оператори и изрази Гла ва 2
char еден бајт, може да чува еден знак од локалното множество на знаци
int цел број , обична ја рефлектира природната големината на целите
броеви на локалната машина
float број со подвижна точка со единична прецизност
double број со подвижна точка со двојна прецизност
""'
Зборот int може да се испушти во декларациите од овој тип , што и обична се
прави.
помеѓу О и 255, додека онаа од тип signed char помеѓу -128 и 127 (кај
машини со двоен комплемент) . Дали char вредностите се означени или не
означени зависи од машината, но знаците кои може да се печатат секогаш се
позитивни.
Стандардните заглавја <1imi ts. h> и <float. h> содржат симболички кон
станти за сите овие големини, заедно со другите својства на машината и ком
пајлерот. За нив се зборува во Додатокот Б.
2.3 Константи
'\ооо'
'\xhh '
return)
\t хоризонтален таб \xhh хексадекаден заn и с
\v вертикален таб
Знаковната константа
'\0' го nретставува знакот со вред ност нул а , нултиот
(анг. null) знак. Често, наместо о се nишува
'\0' за да се поте н ци р а неговата
природа во некој израз, но бројната вредност му е само о .
Константен израз е израз кој содржи само константи . Та кв ите и зрази мо
жат да бидат евалуирани за време на комnајлирањето , пред да се стартува
програмата и во согласност со тоа да се користат на секое место каде може да
2.3 Константи 45
или
или
е исто што и
Ова е корисно кога има потреба од пишување на долги стрингови кои се проте
гаат на повеќе редови во кодот .
Технички , една стринг константа претставу ва низа од знаци. Внатрешната
репрезентација на стрингот поседува празен знак '\ о' кој се наоѓа на крајот ,
така што потребната физичка меморија е за еден поголема од бројот на зна
ците кои се напишани помеѓу наводниците. Таа репрезентација означува дека
не постои ограничување за тоа колкава должина може да има еден стринг , но
int i;
while (ѕ [i] != '\0')
++i;
return i;
2.4 Декларации
Сите променливи мора да се декларираат пред нивната употреба, иако од
редени декларации може да се из ведат имплицитно според содржината. Едн а
декларација специфицира тип и содржи л иста од една или повеќе променливи
од тој тип , како во
int lower ;
int upper ;
int step ;
char е;
c har line[1000] ;
х % у
чаите кога има пречекорува ње на горна или долна граница . (анг. overflow и
uпderflow)
Бинарните + и - имаат еднаков приоритет , кој е по низок од приоритетот на
*, 1, и %, кои, пак, се со понизок приоритет од унарните + и -. Аритметичките
оп е ратори се асоцијативни од лево кон десно .
Табелата 2 . 1 на крајот од оваа глава, ги сумира приоритетот и асоцијатив
н оста н а сите оператори во е .
2.6 Релациони и логички оператори 49
Релациони оператори се
for (i=O ; i < 1im-1 && (e=getehar ()) ! = '\n' && е ! = EOF ; ++i)
s[i] =е ;
Пред читањето на нов знак, потребно е да се провери д али има доволно место
за истиот да се смести во низата ѕ, поради што, најпрвин, мора да се провери
условот i < 1im - 1 . Значи, ако проверката е негативна , отпаѓа потребата да
читаме нов знак.
Исто така, би било погрешно , ако е се тестира за EOF , пред да биде повика
на функцијата getehar; поради тоа, повикот за доделување мора да се изведе
пред да се провери содржината на е.
изразите како
(e=getehar()) != '\n'
редување со '\n'.
По дефиниција , бројната вредност на релационен или логички израз е 1 ако
релацијата е вистинита и о кога е невистинита .
Унарниот оператор за негација ! ги претв ора сите ненулти о п ера нди во о , а
нултите во 1. Негацијата често се употребува во конструкции од обликот
50 Типови, оператори и изрази Глава 2
if ( !valid)
како замена за
i f (valid == О)
Тешко е да се рече која од двете форми е подобра. Конструкциите како
!valid се читаат ( " ако не е валидно " ) , но покомплицираните изрази можат
да бидат тешки за разбирање.
int i , n;
n = О;
for (i = О ; s[i] >= '0' && s[i] <= '9 ' ; ++i)
n =
10 * n + (ѕ [i] - '0') ;
return n ;
s[i]- '0'
ја дава бројната вредност на знакот складиран во ѕ [i] , но, само затоа што
вредностите 'о' , '1' , итн. формираат континуирана секвенца во растечки
редослед.
Овој код, единствено, функциони ра за ASCII , бидејќи кај ова множество соод
ветните знаци за голема и мала буква се наоѓаат на фиксно растојание од по
четокот до крајот на азбуката , а помеѓу нив нема никакви други знаци осв ен
букви. Но, тоа не е вистина и за знаковното множество EBCDIC, така што оваа
функција во тој случај е бесмислена .
Стандардното заглавје <ctype. h >, опишан во Додаток Б , дефинира фа
милија на функции кои обезбедуваат тестови и кон верзии, независни од зна
ковното множество. На пример , функцијата tolower е портабилна замена за
функцијата lower која претходн о ја разгледавме. Слично на тоа , проверката
може да се замени со
isdigit(c}
ско време кај машините кај кои аритметиката со двојна прецизност е прилично
скапа .
е16- битен, а long типот 32. Тогаш -lL < lU, бидејќи lU, којшто е unsigned
int, се претвора во signed long. Но -lL > lUL бидејќи -lL се конвертира во
unsigned long, па поради тоа изгледа како голем позитивен број.
Конверзиите можат да се вршат и за време на доделувањата ; вредноста од
десната страна се претвора во типот кој е од левата , т. е. во типот на резулта
тот.
Знак се претвора во цел број , било со знаковна екстензија или без неа ,
како што беше опишано nогоре.
Долгите цели броеви се претвораат во кратки или во знаци со отфрлање на
вишокот високи битови. Така во
inti;
ehar е ;
i =е ;
c=i ;
вредноста на е останува непроменета. Ова е вистина без разлика дали има или
нема инволвирано знаковна екстензија. сепак, промена на редоследот на
доделувањата може да доведе до загуба на информација .
Ако х е float и i е int, тогаш обете, тогаш и х = i и i = х резултираат со
конверзија ; float во int доведува до отфрлање на децималниот дел. При nре
творање на double во floa t, во зависност од имплементацијата , конверз ијата
на вредноста се прави со заокружување или со отсекување .
(име на т и п) израз
sqrt ( (double) n)
54 Типови , оператори и изрази Глава 2
повикот
Вежба 2-3 . Напишете функција htoi (ѕ) , која претвора стри нг од хексадекад
ни цифри (вкл уч ително и опционалните Ох или ОХ) во негов целоброен екви
валент . Дозволени цифри се од О до 9, од а до f, и од А до F.
if (е= '\n')
++nl ;
x=n++ ;
x=++n;
if (е== '\n')
nl++ ;
i f (s[i] !=е) {
ѕ[ј] =s[i] ;
ј++ ;
++i ;
со покомпактниот облик
i = ј = О;
while (s[i] != '\0') /* најди крај на ѕ */
i++ ;
while ((s[i++] = t[j++]) != '\0' ) /* коnирај t */
Вежба 2-4. Напишете алтернативна верзија на squeeze (ѕ1 , ѕ2) која ги от
странува сите знаци од стрингот ѕ1 кои се содржат во ѕ2 .
Вежба 2-5 . Напишете функција any ( ѕ 1, ѕ2) , која ја вра ќа прв ата локација в о
стрингот ѕ1, каде се појавува кој било од знак од ѕ2 , или -1 ако ѕ1 не содржи
знаци од ѕ2 . (Функцијата од стандардната библиотека strpbrk ja извршува и с
тата работа , но враќа покажувач кон ло кацијата . )
& битско И
битско ИЛИ
битско исклучително ИЛИ
<< лево поместување (анг. shift)
>> десно поместување
n =n & 0177
Х= Х 1 SET_ON ;
вање") на други .
Унарниот оператор- враќа единичен комплемент на еден цел број ; т. е. го
трансформ ира секој 1-бит во о-бит и обратно .
х =х & - 077
/
1* getbi ts :
земи n битови од по зи ција р */
uns ignedgetbits (unsignedx , intp , intn)
Израз како
i=i+2
i +=2
е еквивалентно со
х *=у+ 1
оз начува
х=х * (у+ 1)
а не
х=х*у+1
if (х & 01)
b++ ;
returnb ;
Вежба 2-9. Во броен систем со двоен комплемент , х &= (х-1) ја брише нај
десната битска единица во х. Објаснете зошто. Искористете го тој за клучок за
да напишете побрза варијанта на bi tcount.
2011 Условни изрази 61
Наредбите
if(a>b)
z=a;
else
z=b;
z =· (а >b) ? а: b; /* z =max(a, b) */
(n>O) ?f: n
Знак за нова линија се печати после секој десети елемент, како и после n-тиот .
Сите други елементи се проследени со едно бланко . Овој израз можеби изгле
да ком пли цирано, но е многу п окомпактен откол ку еквивалентниот i f/ else.
Друг добар пример би бил
Оператори Приоритет
() []-> . лево ко н десно
== != лево ко н десно
?: десно ко н лево
лево ко н десно
i f ( (х & МАЅК) == 0)
мораат да бидат целосно омеѓени со загради о
С, како и повеќето јазици, не го специфицира редоследот по кој се евал уи
раат операндите на еден оператор о (Исклучок претставуваат операторите && ,
11 , ? : и ' ,' о) На пример, во израз како
x=f() +g();
f може да биде пресметано пред g, и обратно; поради тоа, ако која било од f
и g изврши промена на променлива од која зависат и двете , може да се случи
х да за виси од редоследот на пресметувањето о За решавање на тој проблем
потребно е меѓурезултатите да се чуваат во привремени променливи о
++n ;
printf( "%d%d\n", n, power(2, n));
a[i] = i++;
Прашање е дали индексот ја содржи старата или новата вредност на i о
Компајлерите можат да го интерпретираат ова на различни начини и гене ри ра
ат различни одговори во зависност од интерпретацијата о Стандардот намерно
ги остава ваквите прашања како недефинирани о Дали и кога ќе се појава т до
полнителните влијанија (доделување на вредност на променливи) во рамките
на еден израз е оставено да за виси од компајлерот , бидејќи најдобриот ре
дослед строго зависи од машинската архитектура. (Стандардот специфицира
дека сите дополнителни влијанија кај аргументите се случуваат пред повику
вање на функцијата, но дури и тоа не би помогнало во случај демонстрира н со
функцијата printf, напиша на малку погоре.)
Поуката е дека пишување на код , кој за виси од редоследот на евалуација ,
е лоша програмерска практика за кој било јазик. Нормално, потребно е да се
знае кои нешта треба да се одбегнуваат , но ако немате познавање како тие се
извршуваат на различни машини , не треба да бидете предизви кани да ги ко
ристите предностите на поединечните конфигурации.
Глава 3: Контрола на текот
Изразот од облик х =о или i++ или printf {... ) станува исказ (наредба) кога
ќе биде проследен со точка-запир ка, како во
х=О ;
i++ ;
printf{ ... ) ;
3.2 if-else
65
66 Контрола на текот Глава 3
if(uзpoз)
норедбо
1
else
норедбо 2
if (izraz)
наместо
if (izraz !=О)
if (n>O)
if(a>b)
z =а ;
else
z =b ;
if (n>O) {
if(a>b)
z=a ;
else
z =b ;
if (n>O)
for (i=O ; i<n; i++)
if (ѕ [i] >О) {
printf(" . .. " ) ;
return i;
else / *ПОГРЕШНО*/
printf ( " error --n is negative\n") ;
if (а >b)
z =а ;
else
z=b;
3.3 else- if
Појавата на конструкцијата
if (израз)
наредба
else if (израз)
наредба
else/ff (израз)
наредба
else if (израз)
наредба
else
наредба
else
наредба
low = О;
high = n - 1 ;
while (low <= high) {
mid = (low+high)/2 ;
if (х < v[mid])
high = mid - 1 ;
els~ if (х > v[mid])
low = mid + 1 ;
else /* nозицијата е nронајдена */
return mid ;
3.4switch
swi tch е наредба за повеќенасочни одлуки која проверува дали еден израз
по вредност се поклопува со една од повеќето константни целобројни вред
ности и во согласност со тоа го насочува разгранува њето во сак а ната н а сока.
switch ( израз ) {
саѕе конст- израз : наредби
саѕе кон ст-израз: наредби
defaul t : наредби
Секоја опција (анг. саѕе) е означена со една или повеќе целобројн и константи
и ли константни израз и . Ако вредноста на изразот одго в а ра на не која од саѕе
опциите , тогаш извршувањето на кодот почн ува од таа опција . Сите саѕе из
рази мора да бидат различни. Опцијата означена к а ко defaul t се из в р шув а
кога ниту една од опциите не е задоволена . Употребата на defaul t делот е
опционална ; ако истиот не се напише и ако ниту една од наведените опции
nwhi te = nother = О ;
for (i=O ; i<lO ; i++)
ndigit[i] =О ;
while ((е= getchar ()) ! = EOF) {
switch (е) {
саѕе '0': саѕе '1' : саѕе ' 2': саѕе ' 3 ': саѕе ' 4':
саѕе '5': саѕе ' 6 ': саѕе ' 7 ': саѕе '8 ': саѕе ' 9' :
ndigit[c-'0 ' ]++ ;
break;
саѕе ' ':
printf( "digits=" ) ;
for (i=O ; i<lO; i++)
printf( "%d" , ndigit[i]);
printf ( " , white ѕрасе = %d , other = %d\n",
nwhite , nother) ;
return О ;
while (израз)
наредба
е еквивалентна со
uзpl ;
while (uзр2 )
наредба
изр З ;
for ( ;; )
Ова тежи кон брза елиминација на голем дел од почетниот неред , така што во
подоцнежните фази останува помалку работа . Интервалот помеѓу елементите
кои се споредуваат полека се намалува до еден, во кој момент сортирањето
ефективно преминува во сортирање со размена на соседни елементи .
#inelude <string.h>
ѕ[ј] =е;
Вежба 3-3. Напишете функција expand (ѕ1 , ѕ2) која ги проширува кратките
нотации од облик a-z во стрингот ѕ1 во еквивалентни комплетни листи abe ...
xyz во ѕ2. Допуштени вредности се и мали и големи букви како и цифри. Треба
да може да се третираат и влезни конструкции од тип а- b- е или а- zO - 9 или
-а- z . Нека појавата на- на почеток или на крај се третира буквално.
\
З.б Цикnуси do- while
Како што веќе се запознавме во Глава 1, циклусите while и for го тестираат
условот за прекин на почеток од циклусот. Спротивно на нив, кај третиот ци
клус во С, do- while, проверката се врши на крајот, после секој премин низ
телото на циклусот ; телото секогаш се извршува барем еднаш .
Синтаксата на do е
do
наредба
while (израз) ;
3.6 Циклуси Do- while 75
s[i] = '\0';
reverse(s) ;
Вежба 3-5. Напишете функција itob (n, ѕ, b) која врши претворање на цел
број n во знаковна репрезентација со основа b, сместена во стрингот ѕ. На при
мер, i tob (n, ѕ, 16) го форматира ѕ како хексадекадна репрезентација на n.
76 Контрола на текот Глава 3
Вежба 3-6 . Наnишете верзија н а itoa , која наместо два , nрифаќа три ар
гументи. Третиот аргумент е минималната шири н а н а резултантниот стрин г.
Добиениот резултат мора да биде пополнет со nразни места во случај кога ши
рината на добие ниот број е nомала од минималната nредвидена ширина на
стрингот. (т . е резултатот треба да биде nорамнет во десно. )
int n ;
nразно место.
следното nовторување за for , while или do циклусите. Кај while и do ова зна
чи моментална проверка на усл овот н а циклусот ; кај for , ко н тролата се nре
фрла н а че корот за инкреме нтирање . На редба та c ontinue се користи само во
циклуси , а не кај swi tch. Уnотреба на continue во swi tch во циклус ќе nре
дизвика n реми н ување кон следното повторување н а циклусот.
3.8 goto и озна ки 77
Н аредбата continue често се користи , кога дел од циклусот кој следи е ком
nлициран, на тој начин што замената на условот со спротивен и вовлекување
на уште едно ниво би предизвикало предлабоко вгнездување во програмата.
for ( ... )
for ( ... )
if (disaster)
gotoerror ;
}
error :
/* исчис~и го нередо~ */
found :
/* најдов еден : a[i] -- b[j] * /
Код кој вклучува goto секогаш може да се напише без него 1 иако можеби по
цена на некоја променлива или проверка пове ќе. На пример 1 кодо1 за преб а
ру вање на низата може да се напише како :
found = О ;
for (i = О ; i < n && !found; i++)
for (ј = 0 ; ј < m && !found; ј++)
if (a[i] == b[j])
found = 1 ;
if (found)
/* најдов еден: a[i-1] b[j-1] * /
е1ѕе
/* ненам најдено 5аеднички елемент */
Со мал број на исклучоци 1 како тие што ги спомнавме овде 1 код кој се потпи
ра на goto наредби во општ случај е потежок за разбирање и за одржување 1
отколку код кој не содржи goto наредби . Иако не сме догматс ки настроен и во
овој поглед 1 сепак, изгледа дека goto наредбите треб а да се избегнуваат колку
што е можно повеќе, ако не и во целост .
Глава 4: Функции и структура на програма
79
80 Функции и структура на програма Глава 4
ќе доведе до резултат:
Иако сето ова е возможно да <.е изведе и во рамките на функциј ата main ,
подобар на чин е да се направат функции за секој дел од nрограмата. Полесно е
да се работи со три мали целини отколку со една голема, од причина што незн а
чајните детали можат да се скријат во функциите , а можноста од несака н и инте
ракции е минимизирана. А деловите може да се употребат и во други програми.
"Додека nостои следна линија ", е getline , функција која ја напишавме во
Глава 1 , а " испечати ја" , всушност е printf која некој друг веќе ја обезбедил
за нас. Тоа значи дека единствено што мораме да наnишеме е рутина која ќе
донесува одлука дали една линиј а t:одржи појавување на обликот или не.
Тој пробл ем можеме да го решиме со функцијата strindex (ѕ , t) која ја
враќа п оз ицијата или индексот во ни зата ѕ каде за n очнува ни затаt , а - 1 ако
ѕ не ја содржи t. Бидејќи низите во С започнуваат со индекс нул а, сл едува
дека индексите ќе бидат или нула или позитивни , па вредноста -1 , може да
се користи како сигнал за грешка. Во случај подоцна да ни затреба некоја по
софистицирана сnо редба на облици , измените ќе бидат локализира ни само
на функцијата strindex , додека д ругите делов и на програмата ќе оста нат не
допрени ( ста ндардн ата библиотека обезбедува функција strstr која е слична
на strindex , но враќа пока жувач нам есто индекс).
После толкаво дизајнирање, доп олн увањето на програмските детали е ед
ноставно. Овде е дадена целата програма, за да видите како сите делови се
склопени заедно. Засега , обликот кој ќе се пребарува е константен стринг , што
не е најоnшт меха низам. ќе се навратиме за момент кон расправа околу и ни
цијализација на низа од знаци , а в о Глава ѕ ќе покажеме како обликот може да
се нап рави парамета р кој ќе добие вредност за време на извршување на про-
401 Основи на функци и 81
return found ;
int е, i ;
i = О;
while (--lim >О && (c=qetchar()) '= EOF && е ! = '\n ' )
s[i++] = е ;
if (е == '\n ' )
s[i++] = е ;
s[i] = '\0' ;
return i ;
82 Функции и структура на програма Глава 4
int i , ј , k;
return -1;
dummy() {}
return израз;
Изразот ќе биде претворен во тип на повра тната променлива, ако има потре
ба од таква операција. Понекогаш изразот се става во мали загради , но тие не
се задолжителни.
враќа текот кај повикувачот без ника ква вредност кога извршувањето ќе "дој
де до работ" на функцијата со доаѓање до завршната голема затворена загра
да. Случајот во кој една функција при повикување од едно место враќа некоја
вредност, а од друго не, иако ненелегален, веројатно, укажува на постоење на
проблем. Секако, ако функцијата не успее да врати вредност , нејзината "вред
ност" сигурно е ѓубре.
Програмата за пребарување на облик враќа статус од функцијата main ,
бројот на пронајдените поклопувања . Таа вредност може да се користи од око
лината од која била повикана програмата .
Механизмот на компајлирање и вчитување на една С про грама , која е
сместена во повеќе изворни датотеки, варира од систем до систем. Кај сис
темот UNIX, на пример , наредбата се спомната порано, ја извршува таа рабо
та. Претпоставете дека три функции се сместени во три датотеки , со имиња
main. е , getline . е и ѕ trindex. е . Тогаш наредбата
конверзија на влезот, бидеј ќи тогаш би барала многу повеќе простор од тој кој
планиравме да го отстапиме. Стандардната библиотека содржи функција atof
декларирана во заглавјето <ma th. h>.
Најнапред , самата atof функција мора да декларира тип на вредност кој ќе
го враќа , бидејќи не станува збор за цел број. Името на типот му претходи на
името на функцијата
iinc1ude <stdio.h>
/ * едиос~авен халхула~ор */
main ()
(
doub1e sum, atof(char []) ;
char 1ine[МAXLINE] ;
int get1ine(char 1ine[] , int max) ;
sum = О ;
while (getline(line, МAXLINE) > О)
printf( "\t %g\n", sum += atof(line)) ;
return О ;
4.2 Функции кои враќаат нецелобројни вредности 85
Второ, исто така, важно, повикувачк ата рутина мо ра да знае дека atof
враќа вредност која не е in t. Еден од начините да се обезбеди тоа , е да се
направи јасна декларација на atof фун к цијата во повикувачката рути на .
Декларацијата е покажана со пример во оваа едноставна програма - калкула
тор (Кој а одвај ја бива за средување на банкарската сметка). Таа вчитува еден
број по линија, кому може да му претходи предзнак, и ги собира броевите ,
печатејќи ја тековната сума после секој влез
Декларацијата
вели дека сумата е променлива од тип double и дека atof е функција која на
влез зема еден аргумент од тип char [] , а враќа double . Функцијата а tof мора
да биде декларирана и дефинирана конзистентно . Ако atof и неј зи ниот повик
во main се неускладени по прашање на типот во истата изворна датотек а , ком
пајлерот ќе ја открие грешката . Но, ако (што е поверојатно) , atof се преведе
посебно, таа неускладеност нема да биде откриена, п а а tof ќе врати double ,
која функцијата main ќе ја третира како int , а ние ќе добиеме резултати кои се
бесмислени.
Ако се земе предвид она што го кажавме дека д екла рац иите мора да од го
вараат на дефинициите, ова може да ви изгледа из ненадувач ки. Причината да
може да дојде до неускладеност е во тоа што ако нема функциски прототип,
функцијата имплицитно се декларира со своето прво појавување во изразот,
како што е
Ако недекларирано име се појави во израз , а после него следи лева заграда,
тогаш се подразбира дека станува збор за име на функција, за функцијата се
претпоставува дека враќа int, додека за неј зи ните аргументи не се претпо
ставува ништо. Уште повеќе, ако декла рацијата на функцијата нема аргументи
како во
double а tof () ;
return израз;
(1-2) * (4+5)
се внесува во облик
12-45+*
земи операнди
изврши операц ија
ст ави резулта т на купо т
#include -oвu,и
#define -oв u,и
1114in () { . . . )
voidpush ( double f) { . .. }
double рор (void) { . . . }
intgetop(chars[] ) { . . . }
#include <stdio.h>
#include <stdlib.h> /* for atof() */
push(atof(s));
break;
саѕе ' +' :
push(pop() + рор());
break;
саѕе '*':
push(pop() * рор());
break;
саѕе '-':
ор2 = рор () ;
push(pop() - ор2) ;
break ;
саѕе '/':
ор2 = рор () ;
i f ( ор2 ! =
О . О)
push(pop() 1 ор2);
else
printf("error: zero divisor\n" );
break;
саѕе '\n ':
printf("\t%. 8g\n", рор()) ;
break;
default:
printf("error: unknown coпunand %s\n", ѕ) ;
break;
return О ;
90 Функции и структура на програма Глава 4
int geteh{void) ;
void ungeteh{int);
int i, е;
s[l] = '\0' ;
if {!isdigit{e) && е != '. ' )
return е ; /* не е број */
i = О;
if {isdigit(e)) /* вчитај го целобројниот дел*/
while {isdigit{s[++i] =е= geteh{)))
s[i] = '\0';
if {е != EOF)
ungeteh(e);
return NUМВER;
нешто, а ја повикува getchar ако е баферот празен. Исто така, треба да има
индексна променлива која ќе ја чува позицијата на тековниот знак во баферот.
Бидејќи пристапот до баферот и индексот се заеднички за getch и ungetch
и бидејќи треба да ги задржуваат своите вредности и помеѓу функциските по
вици, тие треба да се декларираат како надворешни за двете рутини . Та ка,
getch , ungeteh и нивните заеднички променливи може да се напишат како:
Вежба 4-7 . Напишете рутина ungets (ѕ) која назад на влез ќе вра ќа цел
стринг. Треба ли ungets да има информација за buf и bufp , или, единствено,
треба да ја користи ungetch?
4.4 Правила на делокругот (анг. ѕсоре) 93
Вежба 4-8. Претпоставете дека никога ш н ема да има повеќе од еден знак за
враќа ње на влез. Модифицирајте ги getch и ungetch соодветн о.
Делокругот на едно име, е дел од програмата во чии рамки тоа име може
да се користи. За автоматска променлива декларирана на почетокот на фун к
цијата, делокругот е функцијата во која нејзиното име било декларирано.
Локалните променливи со исти им и ња во различни функции се неповрзан и.
Истото важи и за пара метрите на функциите, кои имаат природа на локални
променливи.
Делокру гот на една надворешна променл ива или функција за почнува од мо
ментот во кој е декларирана, па се до крајот на датотеката која се компајлира.
На пример, во main , ѕр , val , push и рор се дефинираат во една датотека, по
наведени от редослед, т . е .
94 Функции и структура на програма Глава 4
main () { ...
int ѕр= О;
double val [МAXVAL] ;
int ѕр;
double val [МAXVAL] ;
во датотека 1:
voidpush (double f) {
во датотека2:
intsp= О;
double val [МAXVAL] ;
calc.h:
#define NUМВER 'О '
voidpush (double) ;
double рор (void) ;
intgetop(char []) ;
int getch (void) ;
void ungetch (int) ;
register int х ;
register char е;
if ( n > О ) {
int i; /*декларација на ново i* /
intx;
inty;
f(doublex)
{
doubley;
4.9 Иницијапизација
intx=1;
char squote = '\' ' ;
long day = lOOOL * бОL * бОL *24L ; /*милисекунди /ден*/
наместо
low= О ;
high= n - 1 ;
charpattern[] = { ' о', ' u' , ' 1 ' , ' d' , '\0 ' };
4.1 О Рекурзија
if (n 1 10)
printd(n 1 10) ;
putchar(n % 10 + ' 0 ' ) ;
102 Функции и структура на програма Глава 4
една страна, поголемите или еднаквите на него на друга страна. Истата проце
дура се извршува рекурзивно за двете подмножества . Во моментот кога едно
подмножество ќе брои помалку од два елемента, не му е потребно понатамош
но сортирање; тоа ја запира рекурзијата.
Нашата верзија на quicksort алгоритмот, не е најбрзата што постои, но е
една од н ај едноста вните. Го користиме среднишниот елемент од секое подм
н ожество за партиционирање .
temp v [i] ;
v[i] v[j] ;
v[j] temp ;
4.11 е претпроцесор
или
4.11.2 Макрозамена
x=max(p+q, r+s) ;
ќе се замени со линијата
#undef qetchar
dprint (х/у)
Вежба 4-14. Дефинирајте макро swap (t,x,y) кое прави замена на двата ар
гумента од тип t. (Ќе ви помогне блоковска структура) .
4 .11 е претпро цесор 107
ни за време на компајлирањето.
Линијата iif евалуира константен целоброен изра з (кој н е мора да вк
лучува sizeof , претопувања или enum константи). Ако изразот е ненул
ти , линиите кои следат се до #endif или #elif или #else ќе бидат вкл уче
ни. Претпроцесор с киот израз #elif наликува на else-if . И з разот defined
(name) во #if е 1 ако name е дефинирано , во спротивно е о .
На пример , з а д а се осигураме де ка содржината на датотеката hdr . h е вклу
чена само еднаш , содржината на датотеките се оградени со усл ов од следниов
облик:
#if !defined(НDR)
#define НDR
#endif
#if ЅУЅТЕМ==SYSV
#define НDR "sysv. h "
#elif ЅУЅТЕМ = BSD
#define НDR " bsd.h"
#elif ЅУЅТЕМ = МЅDОЅ
#define НDR " msdos . h "
#else
#define НDR " default . h "
#endif
#include HDR
\08 Функции и структура на програма Гл ава 4
ftifndefНDR
ldefineНDR
iendif
Глава 5: Покажувачи и низи
за генерички покажувач о
дуално или во поврзани групи о Една вообичаена ситуација е дека, секој бајт ·
може да биде char , пар од еднобајтни клетки може да се третира како short
цел број, а четири соседни бајти формираат long цел број о Покажувач е група
на клетки (обично две или чети ри) кои во себе може да чуваат адреса о Така,
ако е е char и р е покажувач кој покажува кон него , ситуацијата б и можеле да ја
презентираме на следниов начин :
109
110 Покажувачи и низи Глава 5
Унарн иот оператор & ја дава адресата на еден објект, па така наредбата
р= &е ;
int х =
1, у =2, z[10] ;
int *ip ; /* ip е nокажувач кон int * /
int* р ;
е осмислен а како мнемоничка; таа вели дека изразот *ip има int вредност.
doub1e*dp , atof(char*) ;
оз нач ува дека во некој из раз *dp и atof (ѕ) имаат double вредности , и дека
аргументот на atof е по кажува ч ко н char.
Исто така , треба да забележите дека еден п окажувач е обврзан да покажува
кон некој одреден вид на објект: секој покажувач п окажува ко н специфичен
податочен тип. (Има еден исклучок на ова: " пока жу вач кон void" се кори сти
за чување вредност на кој било друг тип на покажувачи , но самиот не може
да биде дереференциран. ќе се навратиме на оваа проблематика во Поглавј е
5.11)
Ако ip покажува кон целиот број х, * ip може да се појав и во сите контексти
во кои може и х, п а така
5.2 Покажувач и и функциски аргументи 111
*ip=*ip+10 ;
го зголемува *ip за 10 .
Унарните оператори * и & се врзуваат посилно отколку аритметичките , па
така доделувањето
y=*ip+1
го зема она кон што покажува ip, му додава 1 и резултатот го доделува на у, додека
*ip += 1
++*ip
(*ip)++
iq= ip ;
ја копира содржината на ip во iq, после што iq покажува кон она кон што по
кажува и ip.
swap(a, b) ;
temp = х;
х = у;
у = temp;
temp= *рх ;
*рх= *ру;
*ру= temp;
Сликовито :
во повикува чот:
а :
b :
5.2 Покажувачи и функциски аргументи 113
Секој повик го поставува array [n] на следниот цел број кој доаѓа на пода
точен влез , а потоа го зголемува n . Забележете дека од клуч на важност е да
се предаде адресата на array[n] како параметар на getint . Не постои друг
начин getint да го прати конвертираниот број назад кон повикувачот. Нашата
верзија на getint враќа EOF за сигнализирање на крај на податочниот влез,
нула, во случај кога следниот влезен податок не е број, и позитивна вредноста,
во случај кога има валиден број на податочен влез.
Во телото на getint , *pn се користи како обична int променлива. Исто така,
ги користевме функциите geteh и ungeteh (опишани во Поглавје 4. З) за да
може дополнител ниот, знак кој мора да се прочита , да се врати назад на пода
точниот влез.
Вежба 5-l . Како што е напиша на , getint ги третира случаите во кои се поја
вуваат знаците + и - без цифра п осле нив , како валидна претста ва за н ула.
По правете ја така што ќе го враќате таквиот зна к назад на влез.
Вежба 5-2. Напишете функција getfloat , аналогн а на getint , која враќа ва
лиден реален број. Каков тип на резултат треба да врати getfloat?
Декларацијата
inta[10] ;
дефинира низа со должина 10 , односно блок од 10 последователн и објекти
именувани какоа[О], а[1] ,
... , а [9] .
а :
а[О]а[1] а[9]
.....
'\
··.
503 Покажувачи и низи 115
int *ра;
тогаш доделувањето
ра = &а[О];
го поставува ра како покажувач кон нултиот елемент на а ; т о е о , ра ја содржи
адресата на а [о] о
ра:
а[О]
Сега доделувањето
х= *ра;
а [О]
Овие забелешки се вистинити , без разлика од кој тип или големина се про
менливите во низата а о Значењето на "додавање 1 на покажувач" и воопш
то целата аритметика на покажувачите, е дека ра+1 покажува кон следниот
ра =&а [О] ;
ра=а ;
int n ;
се функционални.
Како формални параметри во една функција 1
char ѕ [] ;
и
char *ѕ;
f(&a[2])
f(a+2)
f(intarr[]) { ... }
или од облик
allocbuf :1 11 1
~~==~==~с~е~к~о~р~ис~т~и~::::::~~;.:::сс~л~об~о~д~н~о-=~~
вач и еден пока жува ч може д а се споредува со константата нула . Често наместо
нула , се користи симболичката константа NULL, како потсетник кој појасно ја
истакнува посебноста на нулата како вредност за покажувач. NULL е дефини
ран во <stdio . h>. Отсега па н ата му ќе користиме NULL .
Проверки те од облик
p<q
p+n
returnp- ѕ;
char *pmessaqe ;
тогаш изразот
никаква работа , бидејќи она што се прави во ваков случај е копирање на пока
жувачот, а не на самите знаци . За да се копираат знаците, ќе ни биде потребен
циклус. Првин ќе ја при кажеме верзијата со низ и:
i = О;
while ((s[i] = t[i]) != ' \0 ' )
i++;
/* strcmp: врати <О ахо s<t, О ахо s==t, >0 ахо s>t */
int strcmp(char *ѕ , char *t)
int i ;
for (i = О ; s[i] == t[i]; i++)
i f (ѕ [i] = '\0')
return О ;
return s[i] - t[i] ;
Верзијата со покажувачи:
/* strcmp: врати <О ахо s<t, О ахо s==t, >0 ахо s>t */
int strcmp(char *ѕ, char *t)
*--р
претставуваат стандардни идиоми за додај (анг. push) и отстрани (анг. рор) опе
рации кај купови; погледни го Поглавје 4 . 3.
Заглавјето <string . h> содржи декларации за функциите спомнати во ова
поглавје и голем број на други функции за работа со стрингови од стандардната
библиотека.
#include <stdio.h>
#include <string.h>
nlines = О;
while ((len = getline(line , МAXLEN)) > 0)
if (nlines >= maxlines 1 1 р = alloc(len) NULL)
return - 1 ;
else {
line[len-1] = ' \0 ' ; /* избриши го знакот за нов ред */
strcpy(p , line) ;
lineptr[nlines++] = р ;
return nlines ;
128 Покажувачи и низи Глава 5
swap(v 1 ++last 1 i) ;
swap(v left last);
1 1
{
char *temp;
temp=v[i];
v[i] =v[j];
v[j] =temp;
staticchardaytab[2] [13] = {
{0, 31, 28, 31, 30, 31, 30 , 31 , 31, 30 , 31 , 30, 31} '
{0 , 31, 29, 31 , 30 , 31 , 30, 31 , 31, 30, 31 , 30, 31}
};
int i , leap ;
чии што елементи, исто така, се низи. Поради тоа индексите се запишуваат како
а не
daytab[i,j] /* ПОГРЕШНО */
int *daytab[13]
132 Покажувачи и низи Глава 5
тогаш и а[З] [4] и b[З] [4] се синтаксички легални референци кон една int
вредност. Но а е вистинска дводимензионална низа: 200 локации со int-го
лемина се резервираат, а конвенционалната правоаголна индексна пресметка
кон низ и од 2 елемента, некои кон низи од ѕо, додека други да не покажуваат
кон ништо.
name:
illegal month\0 1
Jan\0 1
Feb\0 1
Каr\0 1
aname :
1~llegil montБ\O Jan\0 Feb\0 Маr\0
о 15 30 45
Н аједно ста вн ата илустрациј а за ова е програмата echo , која ги печати соп
ствените аргуме нти од кома ндн а л и ниј а во една текстуална л инија , одделени
меѓу себе со п разни места. Така , командата
печати
hello , world
Првата верзија на echo ја третира argv како ни за од знако вни покажу ва чи:
linclude <stdio.h>
linclude <string . h>
ldefine МAXLINE 1000
return found;
find -х -n pattern
long lineno = О;
int е 1 exeept =О 1 number =О 1 found =О ;
exeept= 1 ;
break ;
еаѕе ' n ' :
number= 1 ;
break ;
default :
printf ("find: illega1 option %e\n" , е) ;
arge =О ;
found= -1 ;
break;
if (argc != 1)
printf (" Usage : find -х - n pattern\ n " ) ;
else
while (getline(line , МAXLINE) >0) {
lineno++ ;
if ( (strstr (line 1 *argv) ! =NULL) != except) {
if (number)
printf( " %ld: " 1 lineno) ;
printf( " %s ", line) ;
found++;
return found ;
expr234+ *
пресметува 2 * (3+4 ) .
entab - m +n
tail -n
numeric= 1 ;
140 Покажувачи и низи Глава 5
int i, 1ast;
void swap(void *v[], int , int) ;
кој означува дека comp е покажувач кон функција која има два void* аргумента
и враќа int. Употребувањето на comp во линијата
означува дека comp е функција која враќа покажувач кон int вредност, што со
сема ја менува смислата . Веќе ја покажавме strcmp, која споредува два стрин
га . Ќе ја претставиме и nwncшp , која споредува два стринга по првата број на
вредност, која се добива преку повик до atof :
vl = atof (sl) ;
v2 = atof (ѕ2) ;
if (vl < v2)
return -1;
else if (vl > v2)
return 1;
else
return О ;
temp=v[i] ;
v[i] =v[j];
v[j] = temp ;
само го илустрира тој пр облем: * е префи ксе н оператор и има п онизок пр ио
ритет од () , п а заградите се потребни за да се обезбеди правилна асоција ција.
Иако, навистина, комплицираните деклара ции мошне ретко се појавуваат
во практика, потребно е да знаете како истите да ги разберете , а ако е потреб
но тоа, и да ги напиш ете . Добар начин е декларациите да се синтетизираат во
мали чекори со употреба на typedef , за која ќе зборуваме во Поглавје 6. 7 .
Ка ко алтернатива, во овој дел ќе презентираме п ар програми кои прават пре
творање од е во псевдокод и обратно . Псевдокодот се чита од лево кон десно .
Првата , dcl, е посложена. Врши претворање на е декларација во псевдо
код , како во наведе ните пример и :
char **arqv
arqv : пока жувач ко н п о к ажувач кон char
int (*daytab) [13]
daytab: покажувач ко н низа [ 13] од int
int *daytab[13]
daytab: ни за [13] од покажувачи кон int
void *comp ()
comp : функција која враќа покажу вач ко н void
void (*comp) ()
comp: покажувач кон функција која враќа void
char (* (*х()) [ )) ()
х : функција која враќа покажувач ко н н иза [] од покажувач и кон
функција која враќа char
char (* (*х[3]) ()) [5]
х : низа [3) од покажувач кон функција која враќа покажувач
кон низа [5] од char
dcl се бази ра на граматика која наведува декларатор, компл етн о нав еден
во Додаток А, Поглавј е 8 .5; ова е неговата п оеднос таве на форма
Кажано со збо рови, деклараторот dcl е direct- dcl на кој може да му п ретходат
некол ку * . Direct- dcl , од друга страна , може да бид е име,
dcl во мали за град и,
direct-dcl следен од мали загради, или direct-dcl следен од средн и загради со
о пцис ка величи н а.
(*pfa[]) ()
( • pta о ) ()
name
dir-dcl
1
dir-dcl
1
dcl
1
dir-dcl
1
dir-dcl
1
dcl
pfa ќе биде идентификувана како име и поради тоа како direct-dcl . Потоа pfa [ Ј ,
исто така, е direct-dcl. Пoтoa, *pfa [] се препознава како dcl, па (*pfa []) како
direct-dcl. Понатаму, (*pfa []) () е direct-dcl, па со тоа и dcl. Парсирањето може
да го илустрираме со парсирачко дрва како ова (каде direct-dcl е кратко запи
шано како dir-dc[) :
Срцето на dcl програмата се пар функции , dcl и dir- dcl , ко и парси раат
декларација врз основа на оваа граматика . Бидејќи граматиката е дефинирана
рекурзивно , функциите, како што ги препознаваат деловите на декларација
та, рекузривно се повикуваат меѓу себе ; програмата е наречена рекурзи в но
с пуштачки парсер .
#include <stdiooh>
#include <string oh>
#include <ctype oh>
int gettoken(void) ;
146 Покажувачи и низи Глава 5
return О;
if(c== '('){
if ( (c=getch()) = ' ) ' )
strcpy (token , " () " ) ;
return tokentype = PARENS ;
} else {
ungetch(c) ;
return tokentype = ' (' ;
} elseif (е= ' [ ' ) {
for (*р++=с ; (*p++=getch()) != ' ] '; )
*р = '\0' ;
return tokentype = ВRАСКЕТЅ ;
} else if (isalpha (е)) {
5.12 Комплициранидекларации 147
*р= '\0';
ungeteh(e) ;
return tokentype = NАМЕ ;
} else
return tokentype =е;
x()*[]*()ehar
во
ehar ( * ( *х () ) []) ()
return О;
148 Покажувачи и низи Глава 5
Вежба 5-19. Изменетеја undcl така што нема да додава одвишни загради на
декларациите.
• (4,3)
(0,0)
149
\50 Структури Глава б
structpoint {
intx ;
inty ;
};
struct { ... } х, у, z;
intx, у, z;
structpointpt;
pt2
ptl
--~~----------------~Х
struct rect {
struct point ptl;
struct point pt2 ;
};
Структурата rect содржи две point структури. Ако screen го декларираме како
на nокажувач кој nокажува кон неа. Секој од нив има nредности и мани .
Првата функција makepoint 1 на влез nрима два целобројни аргументаl а
како функциска вредност враќа point структура:
temp . x = х ;
temp.y = у ;
return temp;
structpoint *рр ;
означува дека рр е покажувач кон структура од тип struct point. Ако рр по
кажува кон point структура, *рр е самата таа структура, а (*рр) . х и (*рр) . у
се нејзините членови . За да ја користиме рр , б и можеле да напишеме, на при
мер,
рр= &origin ;
р- > член_на_структура
r.ptl.x
rp->ptl.x
(r .ptl) . х
(rp->ptl) .х
struct {
int len ;
char *str ;
} *р ;
Тогаш
++p->len
char *keyword[NКEYS];
int keycount[NКEYS];
char *word;
intcount ;
декларира структурен тип key, дефинира низа keytab како низа од структури
од тој тип и резервира мемориски простор за нив. Секој елемент од низата е
структура . Ова, исто така, може да се запише и како
structkey {
char *word;
int count ;
};
structkey {
char *word;
intcount;
} keytab [ ] = {
"auto", О ,
" break", О,
" саѕе ", О,
"char", О,
"const", О,
" continue", О,
" defaul t", О ,
1* ... *1
"unsiqned", О,
"void", О,
" volatile", О,
"while", О
};
{ " auto", О } ,
{ "break", О } ,
{ " саѕе ", О } ,
6.3 Низи од структури 157
int cond ;
int 1ow, high , mid;
1ow = О ;
high = n - 1 ;
whi1e (1ow <= high) {
mid = (1ow+high) 1 2 ;
if ((cond = strcmp(word, tab[mid] .word)) <О)
high = mid - 1 ;
е1ѕе if (cond > О)
1ow = mid + 1 ;
е1ѕе
return mid ;
return -1 ;
158 Структури Глава б
sizeof објект
и
Да се навратиме на функцијата
getword . Напишавме една поопшта варијан
та на функцијата
getword, отколку што тоа го бара програмата , но не е ком
плицирана. getword го прифаќа следниот "збор " кој доаѓа на влез , при што
за збор се смета стринг од букви и цифри кој започнува со буква, или еден знак
кој не е празно место . Вредноста на функцијата е првиот знак од зборот или
EOF за крај на датотека или самиот знак во случај кога тој не е буква.
if (е !=EOF)
*w++= е;
if (! isalpha (е))
*w= '\0' ;
return е ;
for ( ; --lim>O;w++)
if (! isalnum(*w = geteh ()))
ungeteh(*w);
break;
*w = '\0' ;
return word [О] ;
читан о еден знак повеќе. Повикот кон unqetch тој знак го враќа на влез каде
што ќе го очекува следниот повик. Getword, исто така, ги користи isspace
за прескокнување на п разните места, isalpha за идентификација на буквите
и isalnum за идентификација на бројки и букви; сите тие се функции од стан
дардното заглавје <ctype. h>
Jinclude <stdio.h>
linclude <ctype.h>
linclude <strinq.h>
Jdefine МAXWORD 100
low=mi.d+ 1 ;
else
return mi.d ;
return NULL ;
го вклучува првиот елемент после крајот на една низа (Т. е. &tab [n])
Во main запишавме :
struct {
char е;
inti ;
};
може да случи да бара осум бајти, а не пет . Операторот sizeof ја враќа точ
ната големина .
На крај, да фрлиме поглед на форматот на програмата : кога една функција
враќа комплициран податочен тип како што е покажувач кон структура, како во
structkey *
binsearch (char *word , struct key *tab , int n}
Ниту еден јазол не смее да има повеќе од две деца ; може да има едно или
без деца.
Јазлите се организирани така што за кој било јазол, неговото лево поддрво
содржи зборови кои се лексички помал и од неговиот, додека десното поддрво
содржи само поголеми. Даден е приказ на дрвото добиено од реченицата" now
is the t ime for all good men to come to the aid of their party".
now
18
/"-the
/"-
for men of/ """ time
all/
/""-
a.id come
"""
good "
pa.rty / """
their to
root=NULL;
while (getword(word, МAXWORD) != EOF)
i f (isalpha(word[O]))
root = addtree (root , word);
treeprint(root) ;
return О;
1* add tree :
.цо,ца ј ј азоп w, на нпи по.ц р * 1
struct treenode *addtree (struct tnode *р, char *w)
{
int cond;
strdup едноставно врши копирање н а стрингот кој се преда ва како нејзин ар
гумент на сигурна лока ција , добиена преку повик на malloc
р =
(char *) malloc(strlen(s)+l) ; /* +1 f o r '\0 ' */
if != NULL)
(р
strcpy(p , ѕ) ;
return р ;
malloc враќа NULL доколку нема расположив простор ; strdup ја пренесува таа
вредност понатаму, препуштајќи го справувањето со греш ките на повикувачот .
Меморијата резервирана со повик кон malloc се ослободува за п о вто рна упо
тр еба со повик кон функцијата free ; поглед н ете ги Глава 7 и Глава 8 .
Вежба 6-2 . Напи шете програма која чита е програма и ги печати во алфабет
ски редосл ед сите групи на имиња н а променливи, што се иде нтични во првите
Вежба 6-3. Напи шете " индекс на текст" кој печати листа н а сите зборови од
еден докуме нт и за секој збо р листа од броевите на линиите в о кои тој се поја ву
ва. Отстранете ги непотребн ите зборови како што се сврзниците, предлозите
и прилозите .
168 Структури Глава б
idefine IN 1
state =IN;
defn
6.6 П реба рување на табела 169
Низата на покажувачите е
листа:
if ((np = lookup(name)) ==
NULL) { /*не е најдено */
np = (struct nlist *) malloc(sizeof(*np)) ;
if (np = NULL 11 (np->name = strdup (name) ) =
NULL)
return NULL;
hashval = hash(name);
np->next = hashtab[hashval] ;
hashtab[hashval] = np ;
else /* веќе е најдено */
free ( (void *) np->defn) ; /* оспободн ro претходниот dfn * 1
if ((np- >defn = strdup(defn)) == NULL)
return NULL ;
return np ;
6.7typedef
е обезбедува можност наречена typedef за креирање на нови типови на
податоци. На пример, декларацијата
6.7 typedef 171
креира име Lenqth како синоним за int. Типот Lenqth може да се користи
за декларации, за претопување итн., точно на ист начин како што тоа би го
правел типот int:
го креира типот PFI, во значење " покажувач кон функција со два аргумента,
која враќа int", која може да се користи во контекст како
PFistrcmp,numcmp;
6.8 Унии
union u _ tag {
intival ;
fioat fval;
char *sval;
} u ;
име_на_унија. член
или
if (utype == INТ)
printf( "%d\n " 1 u.ival) ;
if (utype-= FLOAT)
printf( " %f\n" 1 u.fval) ;
if (utype = SТRING)
printf ("% s\n", u . sval) ;
else
printf ( " bad type %d in utype\n", utype) ;
struct {
char *name ;
intflags;
intutype ;
union {
intival;
float fval;
char *sval;
} u;
} symtab [NЅУМ] ;
symtab[i] .u.ival
*symtab[i] . u.sval
или
symtab[i] .u.sval[O]
на мемориски опсег.
#define КEYWORD 01
#define EXTRENAL 02
#define STATIC 04
ИЛИ
struct {
unsigned int is_ keyword : 1;
unsigned int is_extern : 1;
unsigned int is_static : 1;
} flags;
за поставување на битовите на 1;
за поставување на битовите на о; и
за нивно споредување.
177
178 Влез и излез Глава 7
при секој повик, getehar го враќа наредниот знак кој доа ѓа на вл ез, или EOF
кога доаѓа до крај на датотека. Симболичката константа EOF е дефинирана во
<stdio.h>. Вредноста обична и е -1 , но проверките треба да бидат пишува
ни изразен и преку EOF, за истите да бидат независни од нејзината вредност.
Во многу околини, датотеката може да биде заменета со тастатура со корис
тење на конвенцијата за редирекција на влез<; ако програмата prog користи
getehar , тогаш командната линија
prog <infile
otherprog 1 prog
intputehar (int)
prog >outfile
prog 1 anotherprog
nред nрвата референца. Кога името е ставена во загради < и >се прави преба
рување за заглавјето во стандардно множество од места (на пример, на UNIX
системи, обична е директориумот /usr/include) .
Многу програми читаат само една влезна низа и запишуваат само една
излезна низа ; за такви програми, влезот и излезат со getchar , putchar, и
Знаците за конверзија се прикажани на табела 7 .1 . Ако зна кот, кој следи после
%, не е според спецификација за конверзија, однесувањето е недефинирано.
intprintf(char*fmt , ... )
iinclude <stdarg.h>
/* minprintf : минииалиа фуикциј а printf со промеилива
листа на аргументи */
void minprintf(char *fmt , . .. )
{
va_list ар ; / * nокажува кои секој од беѕимеките arg */
char *р, *sval ;
int ival ;
double dval ;
switch(*++p){
саѕе ' d ':
ival=va_arg(ap , int);
printf ("%d " 1 ival) ;
break ;
саѕе ' f ':
dval=va_arg(ap , double) ;
printf ("%d ", dval) ;
break ;
саѕе ' ѕ ' :
нова линија се nразни места. (Пусти знаци се бланко, нова линија, carriage
return, вертикален таб и formfeed .)
Знакот за конверзија индицира интерnретација на влезното поле.
Соодветниот аргумент мора да биде покажувач , што и се бара од семантиката
на повикување по вредност во е. Знаците за конверзија се прикажани во табе
ла 7.2.
Табела 7.2 : Основни scanf конверзии
користи % 1ѕ
#include <stdio.h>
sum=O ;
while(scanf( "% l f" , &v)==1)
printf("\t%.2f\n", sum+=v);
return О;
186 Влез и излез Глава 7
25 Dec 1988
seanf ( "%d" , n) ;
наместо
eatx . cy . e
FILE *fp ;
FILE * fopen ( char *n&llle, char *mode) ;
Ова кажува дека fp е покажувач кон FILE и fopen враќа покажувач на FILE.
Забележете дека FILE е име на тип , како int , а не таг (ознака) на структура
та; се дефинира со typedef. (Детали за тоа како fopen може да се имплемен
тира на UNIX систем дадени се во Поглавје 8. ѕ)
Повикот за fopen во програма е
getc го враќа следниот знак од потокот кон кој покажува fp ; враќа EOF за крај
на датотеката или во случај на грешка.
putc е излезна функција:
intputc(intc , FILE.*fp)
7.5 Пристап до датоте ки 189
да бидат пренасочени кон други датотеки или цевки, како што е опишано во
Поглавје 7 . 1 .
getehar и putehar може да се дефин ираат преку gete , pute , stdin , и
stdout како што е прикажа но:
#include <stdio.h>
/* cat: кадоврзува датотеки , верзија 1 */
main(int argc, char *argv[])
{
FILE *fp;
void filecopy(FILE * , FILE *)
else
while(--argc >О)
if ( (fp = fopen(*++argv, " r " )) NULL) { ==
printf( " cat : can' t open %s\n, *argv) ;
return 1 ;
else {
filecopy(fp, stdout) ;
fclose(fp) ;
return О;
#include <stdio.h>
if (ferror (stdout) ) {
fprintf (stderr, "%ѕ: error wri ting stdout\n", prog) ;
exit(2);
exit(O) ;
192 Влез и излез Глава 7
еѕ = ѕ ;
strcpy (ѕ 1 t) ко пирај го t во ѕ
strncpy(s 1 t 1 n) копирај најмногу n зн аци од t во ѕ
strlen(s) врати ја долж ин ата на ѕ
strchr(s 1 c) врати покажувач кон првиот е во ѕ 1 или NULL ако го н ема
Неколку функции од <c type . h > и зведуваа т тестови на знаци и нивни кон
верзии. Во следниот дел 1 е е int кој може да се претста в и како unsigned char
или EOF. Функциите враќаат int .
7.8 Разни фун кци и 195
7.8.3 ungetc
Функцијата system ( ehar * ѕ) ја изв ршува кома ндата која се сод ржи во стрин
гот ѕ , потоа се враќа на извршување то на тековната програма. Сод ржината н а
ѕ строго за виси од локалниот оперативен систем . Како тр ивија лен пр име р , на
UNIX системи, исказот
int *ip;
7 .8 .6 Математички функции
pow(x,y) хУ
чен код може да се најде на кој било друг систем. Бидеј ќи во голем број случаи
ANSI библиотеката на е е моделирана на погодностите кои ги нуди UNIX, овој
код, исто така, може да ви помогне и во разбирањето на самата библиотека.
Поглавјето е поделено на три големи делови; влез/излез, датотечен систем
и резервирање (алокација) на меморија. Првите два дела претпоставуваат
скромно познавање на надворешните карактеристики на UNIX системите.
Глава 7 се однесуваше на влезно /излезниот интерфејс кој е униформен за
сите платформи . На секој оперативен систем рутините од стандардната библи
отека мора да се пишуваат во согласност со погодностите кои ги обезбедува тој
систем. Во наредните поглавја ќе ги о пишеме UNIХ-овите системски повику
вања за влез и излез и ќе демонстрираме како делови од стандардната библио
тека може да се имплементираат со нив .
8 . 1 Дескриптори на датотеките
Кај оперативниот систем UNIX, целоку пни от влез и излез се прави со читање
или запишување во датотеки , бидејќи сите периферни уреди, дури и тастатура
та и мониторот, се интерпретираат како датотеки од страна на датотечниот сис
199
200 Системски интерфејс на UNIX Глава 8
char е;
е мора да биде char, бидеј ќи read има п отреба од покажувач кон знак о
П ретопувањето на е во unsigned char кај повратниот израз, ја елиминира мож
носта за каков било пробл ем околу знаков ни от додато к (предзнакот) о
Втората верзија на getchar, го цепка нејзиниот влез на поголеми порции и
ги предава з наците, еден п о ед ен о
if (n == 0) { / * б аферот е празен* /
n = read (O , buf , sizeof buf) ;
bufp = buf ;
Ако овие верзии на getchar беа компајл ирани со вклуче на <stdio о h>, ќе
беш е потребно да се нап рав и #undef на името getchar, во случај и стото да
било имплеме н тирано како макро о
#include <fcntl.h>
int fd ;
int open(char *name , int fiags , int perms) ;
Како и кај fopen, аргуме нтот name е з наковен стринг кој содржи име н а дато
тека . Вториот аргимент fiags е int кој специфицира на кој начин да се отвори
датотеката; главните вредности се :
fd = open(name , O_RDONLY,O);
fd = creat(name , perms) ;
/* ср: го хопира fl во f2 */
main(int argc , char *argv[])
{
int f1 , f2 , n ;
char buf[BUFSIZ] ;
if (argc != 3)
error("Usage : ср from to " );
if ((f1 = open(argv[1] , O_RDONLY , О)) -1) ==
error( " cp : can' t open % ѕ " , argv[1]) ;
if ((f2 = creat(argv[2] , РЕRМЅ)) -1) ==
error( " cp : can ' t create % ѕ , mode % 0Зо " ,
argv[2], РЕRМЅ) ;
while ((n= read(f1 , buf , BUFSIZ)) > 0)
if (write(f2, buf, n) !=n)
error( " cp : write error on fi.le % ѕ ", argv[2]) ;
return О ;
va_start(arqs, fmt) ;
fprintf(stderr , "error: " ) ;
vprintf(stderr, fmt , arqs);
fprintf(stderr , " \n" ) ;
va_end(arqs);
exit(l) ;
lseek(fd , OL , О) ;
ќе илустрираме како некои од овие делови формираат цел ина, преку приказ
на една имплементациј а н а рут ините од стандардната библиотека, fopen и getc .
Спомнете си дека датотеки те од стандардната библиотека се опи шани пре
ку по кажувачи кон д атотеки, а н е пр еку дескриптори . Покажувач ко н датотека
претставува покажувач кон структура која содржи некол ку делови информација
за датотеката: покажувач кон бафер, со што датотеката може да биде чита на во
големи бло кови; бројач за бројот на преостан ати знаци во баферот; покажувач
кон наредната позиција на знак во баферот; датотечен дескриптор; и з наменца
кои ги опишуваат пр ивилегиите на читање /за пишување, статус н а грешки, итн.
Податоч ната с труктура која о пишува едн а датотека, е сместена во за гл авј ето
<s tdio . h>, кое мора да биде вклучено ( со #incl ude) во секоја изворна да
тотека што користи рутини од стандардната влезно/излезна библиотека. Таа,
и сто така , е вкл учена во функциите од таа библи отека. Во следниот извадок
8.5 Пример - имnлементација на fopen и getc 207
#define NULL О
#define EOF {-1)
#define BUFSIZ 1024
#define OPEN_ МАХ 2 О /* мuа:ие.пен број на е,цк:врЕ!1ЕН> C1I!q)E!IИ wn<лe»t* /
enum _ flags {
_READ = 01 , / * датотека отворена за читање * /
WRITE = 02, /* датотека отаорена за заnишуваље */
UNВUF = 04, /* датотеката е небаферирана */
EOF = 010 , /* EOF се nојави во оваа датотека */
ERR = 020 /* грешка се појави во оваа датотека */
};
if (*mode != ' r ' && *mode != ' w' && *mode != 'а')
return NULL ;
for (fp = _iob ; fp < _iob + ОРЕN_МАХ; fp++)
if {(fp->flag & (_READ 1 _WRITE)) ==О)
break ; /* found free slot */
if (fp >= iob + ОРЕN_МАХ) /* n o free slots */
return NULL ;
if ( *mode = 'w' )
fd = creat(name , РЕRМЅ) ;
else if (*mode == ' а') {
if ((fd = open(name, O_WRONLY , 0)) -- - 1)
fd = creat(name , РЕRМЅ) ;
lseek(fd , OL , 2);
else
fd = open(name, O_RDONLY, 0) ;
if (fd == -1) /* couldn't ассеѕѕ name */
return NULL ;
fp->fd = fd ;
fp->cnt = О ;
fp->base = NULL ;
fp- >flag = (*mode -- ' r ' ) ? READ _WRITE ;
return fp ;
8.5 Пример- имплементација на fopen и getc 209
int bufsize ;
Единствено што остана е да се обја сн и како за почнува сето ова . Низата _ iob
мора да биде дефин и рана и иницијализирана за stdin, stdout и stderr:
друга табела наречена " inode list". " inode" за една датотека е место каде се
чува целата информација врзана за некоја датотека, со исклучок на нејзиното
име. Еден директориумски запис обично се состои од два елемента, име на
датотеката и број на inode-oт .
За жал, форматот и точната содржина на еден директориум не се исти на
сите верзии на системот. Така, ќе ја поделиме таа задача на два дела со цел да
ги изолираме непреносливите делови. Надворешното ниво дефинира струк
тура наречена Dirent и три рутини opendir, readdir и closedir за да се
char *name;
struct stat stbuf;
int stat(char *, struct stat *) ;
stat(name, &stbuf) ;
212 Системски интерфејс на UNIX Глава 8
/* .. . */
доста п н а и може веднаш да се п е чати. Ако името претста вува директориум, то
гаш истиот мора да го обработиме датотека по датотека; истиот може да содржи
и п од-директориуми , па процесот е рекурз ивен .
void fsize(char *)
Функцијата dirwalk е општа рутина која применува функциј а врз секоја да
тотека во еден директори ум. Го отвора директо риу мот, поминува н из датоте
ките во него, повикувајќи ја функцијата за секоја од нив, потоа го затвора ди рек
ториумот и се вра ќа. Бидејќи fsize ја п овикува dirwalk за секој директор иум,
двете фу нкции рекурзивно се повик уваат една со д руга.
214 Системски интерфејс на UNIX Глава 8
dir 1 dp->name) ;
else {
sprintf(name 1 "% ѕ/ % ѕ " 1 dir 1 dp->name);
( *fcn) (name) ;
closedir(dfd);
#ifndef DIRSIZ
#define DIRSIZ 14
#endif
str uct direct { /* дирехт ориумсхи заnис */
return NULL ;
Сло~днi~:Јn4=91··· · · ·
...... .
о .. 00 .. uве uве uве
.. ... .. ..
00 .. .... о use
. ...... . .
.. 00 00 00 о
SIZe
.
-.....__адреса КОЈа се предава на корисникот
nunits = (nbytes+sizeof(Header)-1)/sizeof(header) + 1;
if ((prevp = freep) ==
NULL) {/*се уште нема листа
на слободни * 1
base . s . ptr = freeptr = prevptr = &base;
base . s.size = О ;
freep = prevp;
return (void *) (р+1) ;
Вежба 8-6. Функцијата од стандардната библиотечна calloc (n, size) враќа по
кажувач кон n објекти со големина size, со меморија иницијализирана на нула.
Напишете ја calloc, употребувајќи ја malloc или модифицирајќи ја.
Вежба 8-8. Напишете рутина bfree (р, n) која ќе ослободи произволен блок р
од n знаци во листата слободни одржува на од malloc и free . Со користење на
bfree, корисникот може во секое време да додаде статичка или надворешна
низа кон листата слободни.
Додаток А: Референтно упатство
А1. Вовед
А2.1 Белези
223
224 Референтно упатство Додаток А
д2.2 Коментари
д2.3 Идентификатори
А2.5 Константи
константа:
целобројна-константа
знаковна - конста нта
int о Ако целобројната константа има наставка UL , тогаш таа е од тип unsigned
1ongo
Објаснувањето за типовите н а целоброј ните константи оди подалеку од првото
издание, кое единст ве но ги сметаше големите целобројни константи како да
се од ти п 1ong о Наставк ите U се нови о
226 Референтно упатство Додаток А
А2 .6 Стрингови константи
{ изразорt }
во регистрите на компјутерот.
Статичките објекти можат да бидат локални во однос на еден блок или надво
решни во однос на сите блокови , но и во двата случаја ги задржуваат нивните
вредности при излез и повторен влез во функциите и блоковите . Во рамките
на еден блок, вклучувајќи го и блокот кој го обезбедува кодот на функцијата ,
статичките објекти се декларираат со кл учниот збор static. Обј ектите декла
рирани надвор од сите блокови, на исто ниво со функциските дефиниции, се
когаш се статички. Тие можат да се направат л о калн и во посебна един ица за
преведување , со користење на клучни отзбо р sta t i c; тоа им дава в натрешно
поврзување. Тие стануваат глобални за цела програма ако при нивната декла
рација експлицитно не се наведе мемориска класа , или, пак, со ко ристење н а
клучниот збор extern ; тоа им дава надворешно поврзување .
Постојат неколку фундаментални типо ви. Ста ндардн ото за главје <l imi ts.
h> опишано во Додаток Б ги дефинира најголеми те и најмал ите можни вр еднос
ти за секој тип во рамките на една л окал н а имплементација . Броев ите да дени
во Додаток Б ги прикажуваат најмалите прифатл ив и го лем и ни .
Објектите декларирани како знаци (char) се доволно големи да го склади
раат кој било член од знаковното множество на компјутерот . Ако не1<0ј знак
од тоа множество се складира во char објект, негова та вредност е една ква
на целобројниот код за тој знак и тој код е ненегативен . Други величин и може
да се чуваат во char променливи , но можниот опсег на вредн остите, а п осеб
но дали тие вредности се оз начени , за виси од имплементацијата на локалната
платформа . Неознач ените знаци декларирани како uns igned char зафаќаат
исто количество на меморија како и обичните знаци, н о тие секогаш се нене
гативни ; експлицитно означените знаци , дефинирани како signed c har, исто
така, зафаќаат исто количество на мемориј а како и обичните знаци.
Типот unsigned char не беше обработен во пр вото издан ие на оваа к н ига,
но се употребуваше во н еа . Ти пот
signed char е нов.
Покрај
char типовите , достапни се најмногу три големи ни на цели броеви ,
декларирани како short int, int и long int . Обичните int објекти имаат
природна големина која за виси од локалната архитектура ; ос танатите гол еми
ни се воведени за да задоволат одредени специј ални потреб и . Подол гите .цели
броеви обезбедуваат простор со голе,_, барем колку и просторот за пократки
те цели броеви, но во зависност од локалната имплементација об ич ните цели
броеви може да бидат еквивалентни и на кратките и на долгите цели броеви.
Сите int типови претставуваат исклучително означе ни вредности , освен ако
тоа не е наведено поинаку .
АЅ Објекти и л вредности
Аб Конвер3ии
Знак, краток цел број или целобројно битско пол е, истите означени или
не, или објект од енумерациски тип може да се користат во сите изрази каде
може да се користи целоброен тип. А ко еден int може да ги репрезентира
сите вредности од оригиналниот тип , тогаш вредноста се претвора во int; во
та. Кога · р еален број со погол ема прециз ност се претвора во тип со пониска
прециз ност и вредноста е во репрезентативниот опсег резултатот може да биде
следната поголема или помала репрезентативна вредност . Во случај во кој ре
зултатот е надво р од о псегот однесувањето е неде финирано.
-Прво, ако кој бил о од оп ера ндите е од тип long d o uble , друг иот се пре
твора во long double .
-Инаку , ако кој било операнд е од тип double, другиот се претвора во
double .
-Инаку, ако кој било операнд е од тип float , другиот се претвора во float .
-И наку , и врз двата о п еранда се изведуваат инте грални пр омоции; по -
А .б Конверзии 233
тоа ако едниот операнд е од тип unsigned long int , другиот се претвора во
н а оригиналниот по кажувач .
A6.7void
Кој било покажувач кон објект може да се претвори во тип void* без загу
ба на информации . Ако резултатот се претвори назад во тип на оригиналниот
покажу вач , резултатот е оригиналниот покажувач. За разлика од конверзиите
од покажувач кон покажувач, дискутирани во Параграф А б. б , кои во о пшт
случај бараат експлицитно претопување, покажувачите можат да се доделат на
и од покажувачи од тип void* и може да се споредуваат со нив.
Оваа интерпретација на покажувачите од тип void* е нова; претходно пока
жувачите од тип char* играа улога на генерички покажувач. ANSI стандардот
посебно ја нагласува интеракцијата помеѓу void* покажувачите и објектните
покажувачи во доделувањата и релациите, додека кај интеракциите помеѓу
п окажувачите од другите ти п ови претопувањето експлицитно се наведува .
А.7 Изрази 235
А7.И3ра3и
Ако тиnот на еден из раз или п оди з ра з за некој тип Т е "низа од Т", тога ш
вредноста на изразот е покажувач кон првиот објект од н изата и тиnот на из
раз от е променет во " nокажувач кон Т" о Оваа конверзија не се случува ако
изразот е оnерандот од унарниот о пе рато р & или од++ , -- , sizeof, или како
примарен-израз:
идентификатор
константа
стринг
(израз )
А7 .3 Постфиксни изрази
постфиксен-израз:
примарен-израз
постфиксен-израз {израз]
постфиксен-израз (листа-на-аргументи изразиор)
постфиксен-израз.идентификатор
постфиксен-израз- >идентификатор
постфиксен-израз++
постфиксен-израз--
листа-на-аргументи-изрази:
израз- за-доделување
листа-на-аргументи-изрази, израз-за-доделување
А.7 Изрази 237
ра з граничување .
При подготвувањето за повикот кон една фун кција , се прави копија од се
кој аргумент; целокупното предавање н а аргуме нт ите е строго по вредност .
Функција може да ја менува вредноста на нејзините параметарски објекти кои
се копии од аргументните изрази , но тие промени не можат да влијаат н а вред
н остите од аргуме нтите. Меѓутоа , возможно е д а се предаде покажува ч при
што се подразбира дека фун кцијата може да ја менува вред носта на објектот
кон кој покажува п окажувачот.
П остојат два стила по кои можат да се де кларираат функциите. Со новиот
238 Референтно упатство Додаток А
Така изра зот Е1->МОЅ е ист како (*Е1) . моѕ. Структурите и у ниите се обра-
ботени во Параграф АВ. з.
Во прв ото издание на оваа книга веќе постоеше правило дека име на член во
таков израз мора да припаѓа н а структурата или у нијата спомната во постфикс
ниот израз ; сепак, постоеш е забелешк а дека ова прав ило н ема да се наметну
ва. Понов ите компајлери и ANSI инсистираат на неговата примена.
у нарен- израз:
постфиксен-израз
++унарен-израз
--унарен-изра з
sizeof унарен-израз
sizeof (име-на- тип )
вкупниот број на бајти во низата . Применет врз структура или унија резулта
тот е бројот на бајти во објектот , вклучувајќи го и потребното порамнување за
објектот да се смести во низата : големината на низата од n елементи е n пати од
големината на еден елемент. Операторот не може да се примени врз операнд
од функциски тип или врз некомплетен тип или врз битско поле . Резултатот е
неозначена интегрална константа; конкретниот тип е дефиниран со имплемен
тацијата. Стандардното заглавје <stddef . h> (погледни Додаток Б) го дефини
ра овој тип како size_ t .
А7 .5 Претопувања
Унарен израз на кој му претходи име на тип ограден со мали загради предиз
викува конверзија на вредноста од изразот во именуваниот тип.
израз-за-претопувањ е:
унарен-израз
мултипликатив ен-израз :
адитивен -израз:
мултипликатив е н - израз
uзраз-за-поместување:
адuтивен-израз
израз-за-поместување << адитивен-израз
израз-за-поместување >> адитивен-uзраз
А7 .9 Релациски оператори
релациски-израз:
израз-за-поместување
Операторите < (помал о) , > (поголема) , <= (помал о или еднакво) и >= (по
големо или еднакво) враќаат о доколку наведената релација е невистин ита и
1 доколку е вистинита о Типот на резултатот е int о Вообичаените аритмети чки
кон верзии се изведуваат врз аритметички операнди о Покажувачите од објекти
кон ист тип (игнорирајќи какви било квалификатори) може да се споредуваат;
резултатот за виси од релативните локации во адресниот простор на пока жува
ните и ндекси о Ако р покажува кон последниот член од една н и за тогаш p+l се
споредува како поголема од р, иа ко p+l покажу ва на дво р од низата о Во спро
тивно, споредувањето покажу вачи е недефинираноо
Овие п равила мал ку ги либерализи раат о граничувањата наведени во прво
то издание дозволувајќи споредба на п окажувачи кон разл ичн и членови н а
структ ура ил и ун ија о Исто така , го легализираат споредувањето со покажувач
кој е за еде н елемент надвор од крајот н а н екоја ни за о
И-израз:
израз-за - еквиваленција
И-израз & израз-за-еквиваленција
ИЛИ-израз:
Исклучително-ИЛИ-израз
ИЛИ-израз 1исклучително-ИЛИ-израз
А7.14Лоrички оператор И
логичко-И-израз:
ИЛИ-изр аз
логичко -И- израз && ИЛИ-израз
Операторот && групира од лево кон десно. Враќа 1 ако и двата оператора
се ра злични од о , во спротив но о. За разлика од & , && гара н тира е ва луација
од лево кон десно: се евалуира првиот о перанд вклучувајќи ги сите стра н ични
ефекти ; ако е еднаков н а о , вредноста на изразот е о. Во спротивно се евалуи
ра д есниот опера нд и ако е ед наков на о вредноста н а изразот е о, во с п роти в-
246 Реф ерентно уп атство Додаток А
А7 .1 б Условен оператор
условен-израз:
логички-ИЛИ-израз
логички -ИЛИ-израз ? израз: условен-израз
Првиот израз се евал уира вклучувајќи ги сите с транич н и ефекти; ако е неед
наков на о, резултат е вредн оста на вториот израз, во спротивно, вредноста
н а третиот израз. Се евалуира само еден од вто риот или третиот операнд. Ако
вториот и третиот операнд се аритметички, тога ш се изведуваат вообичаените
аритметич ки конверзии за да се доведат до заедни чки тип , и тој тип е тип на
резултатот . Ако и двата се void , или структури или унии од ист тип , или пока
жувачи кон објекти од ист тип, резултатот има вредн ост на заедничкиот тип .
Ако еде н од нив е покажувач , а други от ко н с танта о , нулата се претвора во тип
покажувач, и резултатоте од тој тип . Ако еден од нив е покажувач кон void , а
другиот е н екој друг покажувач , д ругиот покажувач се претвора во покажувач
кон v oid , и тоа е типот на резултатот . При с поредување н а п окажувачи , кои
било квал и фикатори во типот кон кој покажува покажувач от се незначај ни , но
резултантни от тип ги наследува квалификаторите и од д вете стра н и на усло
вот.
Сите имаат потреба од л вредност како лев операнд, и истата мора да биде
променлива : не смее да биде низа , не смее да биде од некомплетен тип , или
функција. Исто така , типот не смее да биде квалифику ван со const; ако е струк
тура или унија , не смее да содржи член или потчл ен квалификуван со const .
Типот на изразот за доделување е определен со неговиот лев операнд, а негова
та вредност е вредноста која е з ачувана во леви от операнд после додел увањето.
При едноставно доделување со =, вредно ста на изразот ја за мену ва она а
на објектот кој е посочен од л вредноста. Мора да биде в истина барем едно од
овие тврдења: двата операнда се од аритметички тип , во кој случај десниот
операнд се претвора во типот од лев о со додел увањето ; или двата опе ранд а
се структури или унии од истиот тип; или еден о перанд е покажу вач а друг и от
е покажувач кон void, или левиот операнд е покажу вач, а десниот констан
тен израз со вредност нула ; или двата операнда се покажу вачи кон фу н кци и
или објекти чии типови се исти со исклучок на можната отсутност на const или
volatile кај десниот операнд. Израз во форма El ор= Е2 е еквивалентен с о
El = El ор Е2 со таа разлика што El се евал у ира само еднаш .
А7.18 Операторзапирка
израз:
израз-за-доделување
израз , израз-за-доделување
условен - израз
А8 Декларации
декларација:
декларациски-спецификатори инит -декларатор- листа.Р,;
декларациски-спецификатори :
спецификаторu- на-мемориска-класа декларациски-спе цификатори.Р,
спецификатор - на -тип декларациски-спецификатори opt
квалификатор-на-тип декларациски-спецификатори ор<
инит-декларатор-листа:
инит-декларатор
инит-декларатор-листа, инит-декларатор ·
инит-декларатор:
декларатор
декларатор = иницијализатор
Деклараторите ќе бидат разгледани подоцна ( Параграф А8.5); ги содржат
имињата кои се декларираат. Една декларација мора да има баре м еден д е
кларатор, или спецификаторот на неговиот тип мора да декларира структурен
таг , униски таг или чл е но в ите од една ен умерац ија ; п разни де кл арации не се
дозволени.
спецификатор-на-меморuска-класа:
auto
register
static
extern
typedef
спецификатор-на-тuп:
void
char
short
int
long
float
double
signed
unsigned
структурен - или-униски-спецификатор
енумерациски-специфuкатор
typedef-uмe
Најмногу еден од зборовите long или short може да биде наведен заедно
со int; значењето е исто и ако int не се спомене. Зборот long може да биде
наведен заедно со double . Најмногу еден од signed или unsigned може да се
А.8 Декларации 251
наведе заедно со int и л и кој било од неговите short или long варија ции, или
со char. И двете може да се појават сам и и во тој случај се подразбира int.
Спецификаторот signed е корисен за наметнува ње знак на char објекти ; може
но не мора да се користи со другите интегрални ти пови . Во спротивно најмно
гу еден спецификатор на тип може да биде зададен во една деклара ција . Ако
истиот недостига од декл а рацијата, се з ема дека е int.
Исто така, типовите може да бидат квалифи кувани, со цел да назначат посеб
ни карактеристики на објектите кои се декларираат.
квалификатор-на-тип:
const
volatile
структурен-или-униски -спецификатор:
структура-или-унија идентификаторopt { структурна-декларациска-листа }
структура-или-унија идентификатор
структура-или-унија :
struct
union
252 Референтно упатство Додаток А
структурна-декларациска -листа:
структурна-декларација
структурна-декларациска-листа структур на-декларација
структурна-декларација:
спецификатор-квалификатор -листа структурна-декларациска-листа;
спецификатор-квалификатор-листа:
тип -спецификатор спецификатор-квалификатор-листа opt
тип-квалификатор спецификатор-квалификатор-листа opr
структурна-декларациска-листа:
структурен-декларатор
структурна-декларациска-листа, структурен-декларатор
структурен-декларатор:
декларатор
декларатор •Р' : константен- израз
структура-или-унија идентификатор;
мемориска единица , тоа може да биде поделено помеѓу единици или, па к, еди
ницата може да биде проширена. Неименувано поле со ш ирочи на о , намет
нува такво nроширување, па следното поле ќе за почне на работ од следната
алокациска единица .
Унија може да се смета како структура кај која сите членови започнуваат на
мемориско растојание о од почетокот и чија големина е доволна да чува кој
било од нејзините членови . Најмногу еден од членовите може да биде с клади
ран во унијата во кое било време. Ако покажувач кон унија се претопи во тип
на покажувач кон член, резултатот се однесува на тој член .
Едноставен пример на структурна декларација:
struct tnode {
char tword[20] ;
intcount;
struct tnode *left;
struct tnode *right ;
кој содржи низа од 20 знаци, еден цел број и два покажувача кон слични струк
тури. Еднаш кога ќе се зададе оваа декларација , декларацијата
sp->count
s . left
s.right->tword[O]
Воопшrо, член на унија може да биде разгледуван само во случај кога на унијата и
била доделена вредност со користење на истиот тој член. Сепак, една посебна гаран-
д о8 Декларации 255
union {
struct {
int type ;
} n;
struct {
int type ;
int intnode ;
} ni ;
struct {
int type ;
floa t fl.oa tnode ;
} nf ;
} u;
А8.4 Енумерации
ен.умерациски-спецификатор:
enum иден.тификаторopt { листа-ен.умератори}
enum иден.тификатор
листа-ен.умерат ори :
ен.умерат ор
листа-енумератори , ен.умератор
ен.умератор:
иден.тификатор
иден.тификатор = кон.стан.тен- израз
256 Референтно упатство Додаток А
АЅ.Ѕ Декпаратори
декларатор:
покажувач opr дuректен-декларатор
директен-декларатор:
идентификатор
(декларатор)
директен-декларатор {константен-израз opr ]
дuректен -декларатор ( листа-т ип-на -параметри)
дuре ктен - декларатор ( листа-идентuфu катори0Р' )
покажувач:
( Dl )
* тип-квалификатор-листаopt Dl
И типот на идентификаторот во декларацијата Т Dl "модификатор-на-тип
Т" , типот на идентификаторот на D е "модификатор-на -тип тип-квалифика
тор-листа покажува ч кон т ': Квалификаторите кои следат после * се примену
ваат врз самиот покажувач , а не кон објектот кон кој што покажува тој.
На пример , да ј а разгледаме декларацијата
int*ap[) ;
258 Референтно упатство Додаток А
=
int i , *pi , *const cpi &i;
const int ci = 3, *pci ;
декларираат цел број i и покажувач кон цел број pi о Вредноста на констант
ниот покажувач cpi не може да се промени ; секогаш ќе покажува кон иста ло
кација, иако вредноста кон која покажува може да се менува о Целиот број ci
е константа , и не може да се менува (иако може да се иницијализира, како
овде) о Тип от на pci е " покажувач кон const int" и самиот pci може да се
смени да покажува кон друго место , но вредноста кон која покажува не може
да се менува со доделување преку pci о
Dl {константен-израз.Р,Ј
floatfa[17] , *afp[17] ;
Dl (листа-тип - на-параметри )
листа-тип-на - параметри:
листа- параметри
лисrпа-параметри ,
листа-параметри :
параметарска-декларација
листа-параметри 1 параметарска-декларација
параметарска-декларација:
декларациски-спецификатори декларатор
декларациски-спецификатори апстрактен-деклараторорr
260 Референтно упатство Додаток А
D 1(листа-на-идентификаториор)
листа-на-идентuфикатори:
идентификатор
листа-на -идентификатори, идентификатор
На пример , декларацијата
декларира функција f која враќа цел број, функција fpi која враќа покажувач
кон цел број и покажувач pfi кон функција која вра ќа цел број . Во ниту еден од
овие случаи нема специфицирано тип на параметар ; тие се по стар стил.
Во декларацијата од нов стил
strcpy е функција која враќа int, со два аргумента, првиот е покажувач кон
знак, а вториот е покажувач кон константни знаци. Параметарските имиња се
ефективни коментари. Втората функција rand не зема аргументи и враќа int.
Функциските декларатори со параметарски прототипови се најважната проме
на на јазикот воведена со ANSI стандардот. Имаат предност во однос на дек
лараторите од "стар стил" од првото издание бидејќи обезбедуваа т детекција
на грешки и препознавање на аргументите при функциски повици, но по цена
на: метеж и конфузија при нивното воведување и потребата за п риспособу
вање на двете форми. Одредена синтаксичка грдост беше потребна заради
компатибилност, имено void како експлицитен маркер на функциите од нов
стил без параметар.
Нотацијата .. , ... "за варијабилни функции , исто така , е нова и заедно со
макроата од стандардното заглавје <stdarg. h>, формализираат ме ха низам
кој беше официјално забранет, но неофициј а лно прифатен во првото издание.
Овие нотации беа преземен и ОД јазикот е++ о
А8.7 Иницијаnи3ација
иницијализатор:
израз-за -доделување
{ листа-иницијализатори}
{ листа-иницијализатори,}
листа- иницијализатори:
иницијализатор
листа-иницијализатори, иницијализатор
колку што има чл е нови во подагрегатот ; преоста н атите елеме нти од листата
го инициј а лизираат следни от член од агре гатот од кој што е дел подагр е гатот.
А.8 Декларации 263
На пример,
int х [] = { 1 , 3, 5 } ;
floa t у [ 4] [3] ={
{1,3 , 5} ,
{2,4,6},
{3,5 , 7},
};
floa t у [ 4 ] [ 3] = {
1 , 3, 5 , 2 , 4 , 6 , 3, 5 , 7
};
floa t у [ 4] ( 3] ={
{1}, {2} , {3} , {4}
};
име-на-тип :
апстрактен -декларатор:
покажува ч
покажувачорt директен-апстрактен-декларатор
директ ен-апстрактен-декларатор:
(апстрактен -декларатор)
директен-апстрактен-декларатор opt [константен-израз ор,Ј
директен-апстрактен-декларатор opt (листа-тип- на-параметри opt>
int
int *
int*[З]
int (*) []
int * ()
int (*[]) (void)
имињата соодветно ги означуваат типовите " цел број ", " покажувач кон цел
број ", " ни за од три покажувачи кон цели броеви " , " покажувач кон н е н аведен
број н а цели броев и ", " функција од неспецифицира ни п а раметри , кои враќа
ат покажувач кон цел број", и " низа со ненаведена големина од пок ажувачи
кон функции кои немаат параметри и кои враќаат цели броеви".
А8.9 Typedef
typedef-uмe:
идент ификатор
Една typedef декларација додава како атрибут тип на секое име п омеѓу него-
А.8 Декларации 265
конструк циите
Blocknob ;
extern Blockptr bp ;
Complex z , * zp ;
се легални декларации. Типот на b е long, на bp е п окажувач кон long, и на zе
наведената структура ; zp е покажува ч кон таква структура.
специфицираат на друг нач и н. На при мер, b има исти тип како кој било lon g
објект .
Имињата декларирани со typedef може повто рн о да се декларираат во
внатрешен делокруг, но мора да се наведе непр азно множество на с п ецифи
катори кон типот . На пр имер
extern Blockno ;
го декл а рира .
А8 . 1 О Еквивалентност на тиnови
А9 Наредби
наредба:
означ ен а-наредба
изразна-наредба
сложена наредба
наредба-за избор
наредба -за-повторување
скок-наредба
Означена-наредба :
идентификат ор : наредба
саѕе константен-израз : наредба
default: наредба
изразна-наредба:
изразорr ;
сложена-наредба:
{ декларациска -листа ор
,листа-наредби opt }
декларациска-листа:
декларација
декларациска-листа декларација
листа-наредби:
наредба
листа-наредби наредба
наредба-за-избор:
if (израз) наредба
if (израз) наредба else наредба
swi tch (израз) наредба
268 Референтно упатство Додаток А
наредба-за-повторување :
while (израз) наредба
do нapeдбa while (израз);
for (изразopt ; изразopt ; изразupt ) нар едба
е еквивалентна со
изразl;
while (израз2) {
наредба
изразЗ;
}
скок-наредба:
goto идентификатор;
continue;
break;
return израз opf
единица-за превод:
надворешна-декларација
единица-за-превод надворешна-декларација
надворешна-декларација:
функциска-дефиниција
декларација
функциска-дефиниција:
декларациски-спецификатори opr декларатор декларациска-листа opr
сложена-наредба
директен-декларатор (листа-тип-на-параметри)
директен-декларатор (листа-идентификатори opr)
inta, b, е;
/* . . . */
за параметрите .
така. Конечно, ако еден тип специфицира функција од стар стил , а другиот по
сите основи идентична функција од нов стил со параметарски декларации , се
зема дека типовите се поклопуваат.
А 11 .1 Лексички делокруr
имиња. Тие класи се: објекти, функции, typedef имиња и enum константи;
ознаки; тагови на структури, унии и енумерации; и членови на секоја структу
ра или унија посебно.
Овие правила се разликуваат на неколку начини од тие опишани во прво
то издание на овој прирачник. Ознаките претходно не поседуваа сопствен
простор на имиња; таговите на структурите и униите имаа посебни просто
ри на имиња, а кај некои имплементации, исто така, енумерациските тагови;
ставањето на различни типови на таrови во истиот простор е ново ограничу
вање. Најважната разлика од првото издание е дека секоја структура или унија
креира посебен простор на имиња за нејзините членови, па истото име може
да се појави во неколку различни структури. Ова правило е во употреба веќе
неколку години.
А 11.2 Повр3ување
А 12. Претпроцесирање
??= # ?? ( [ ??<
??/ \ ??) ] ??>
?? ' л
??! 1 ??-
за еквивалентни.
ft undef идентификатор
Дефиницијата
За дадената дефиниција
#define са t (х , у) х ## у
#definexcat(x , у) cat(x , y)
f include секвенца-од-белези
претпроцесорски-услов :
if-линија:
ft if константен-израз
ft ifdef идентификатор
ft ifndef идентификатор
280 Референтно упа тство Додаток А
elif-дeлoвu:
elif-лuнuja текст
elrif-дeлoвu opt
elif-лuнuja:
lf elif константен-израз
еlѕе-дел:
е/ѕе-линија текст
еlѕе-линија:
lfelse
ус-лови .
Константн иот израз во #if и lfelif е предмет на обично макрозаменување.
Уште повеќе 1 кои било изрази во форма
defined идентификатор
или
defined ( идентификатор )
Контролните линии
#ifdef идентификатор
#ifndef идентификатор
соодветно се еквивалентни со
# if defined идентификатор
# if ! defined идентификатор
А 12.8 Pragma
# pragma секвенца-од-белези o pt
282 Референтно упатство Додаток А
#
нема никаков ефект.
А 13. Граматика
надворешна-декларација:
функциска -дефиниција
декларација
функциска-дефиниција:
декларациски-спецификатори opt декларатор декларациска-листаорt
сложена -наредба
декларација:
декларациски-спецификатори листа-иницијални-декларатори ор.;
декларациска-листа:
декларација
декларациска-листа декларација
декларациски- спецификатори:
спецификатор-на-мемориска-класа декларациски-спецификатори opt
тип-спецификатор декларациски-спецификатори op t
тип-квалификатор декларациски-спецификатори opt
спецификатор-на-мемориска-класа: еден од
auto register static extern typedef'
mun сп ецификатор: еден од
void char short int long float double siqned
unsigned структурен-или-униски-спецификатор енумерациски-специфи
катор typedef-uмe
тип-квалификатор: еден од
const volatile
структурен-или-униски-спецификатор:
структура-или-унија идентификатор opt { структурна-декларациска
листа}
структура -или-унија идентификатор
'
284 Референтно упатство Додаток А
структура-или-унија: еден од
struct union
структурна-декларациска-листа:
структурна-декларација
структурна-декларациска -листа структурна-декларација
листа-иницијални-декларатори:
иницијален-декларатор
листа-иницијални-декларатори, иницијален-декларатор
иницијален-декларатор:
декларатор
декларатор = иницијализатор
структурна-декларација:
спецификатор-квалификатор-листа структурна-декларациска-листа;
спецификатор-квалификатор-листа:
тип-спецификатор спецификатор-квалификатор-листа opt
тип-квалификатор спецификатор-квалификатор-листа •Р'
структурна-декларациска-листа:
структурен-декларатор
структурна-декларациска-листа, структурен-декларатор
структурен-декларатор:
декларатор
декларатор opt: константен-израз
енумерациски -спецификатор:
enum идентификатор opt { листа-енумератори}
enum идентификатор
листа-енумератори:
енумератор
енумератор:
идентификатор
идентификатор = константен-израз
декларатор:
покажувачopt директен-декларатор
А.13 Граматика 285
директен-декларатор:
идентификатор
(декларатор)
директен-декларатор [константен-израз opr]
директен-декларатор (листа-тип-на-параметри)
директен-декларатор (листа-идентификаториopt )
покажувач:
тип-квалификатор-листа:
тип-квалификатор
тип-квалификатор-листа тип-квалификатор
листа-тип-на-параметри:
листа-параметри
листа-параметри:
параметарска-декларација
листа-параметри , параметарска-декларација
параметарска-декларација:
декларациски-спецификатори декларатор
декларациски-спецификатори апстрактен-декларатор opt
листа-идентификатори:
идентификатор
листа-идентификатори, идентификатор
иницијализатор:
израз-за-доделување
{ листа-иницијализатори}
{ листа-иницијализатори, }
листа-иницијализатори:
иницијализатор
листа -иницијализатори, иницијализатор
име-на-тип:
директен-апс_mрактен-декларатор:
(апстрактен-декларатор)
директен-апстрактен-декларатор opt { константен-израз орЈ
директен-апстрактен-декларатор opt (листа-тип-на-параметри ор)
typedef-uмe:
идентификатор
наредба:
означена-наредба
изразна-наредба
сложена-наредба
наредба-за-избор
наредба-за-повторување
скок-наредба
означена-наредба:
идентификатор: наредба
саѕе константен-израз : наредба
defaиlt : наредба
изразна-наредба:
израз.Р,;
сложена-наредба:
{ декларациска-листаopt листа-наредби ,} ор
листа-наредби:
наредба
листа-наредби наредба
наредба-за-избор:
if(израз) наредба
if(израз) наредба else наредба
switch (израз) наредба
наредба-за-повторување:
while (израз) наредба
do наредба while (израз);
for (изразор,; израз ор,; изразор) наредба
А.13 Граматика 287
скок-наредба:
goto идентификатор;
continиe;
break;
retиrn израз opf
израз:
израз-за-доделување
израз, израз-за-доделување
израз-за-доделување:
условен-израз
условен-израз:
логички-ИЛИ-израз
логички-ИЛИ-израз? израз: условен-израз
константен -израз:
условен-израз
логички-ИЛИ-израз:
логички-И-израз
логички-ИЛИ-изразii логички-И-израз
логички-И-израз:
ИЛИ-израз
логички-И-израз && ИЛИ-израз
ИЛИ-израз:
исклучително-ИЛИ-израз
ИЛИ-изразi исклучително-ИЛИ-израз
исклучително-ИЛИ-израз:
И-израз
исклучително-ИЛИ-израз л И-израз
И-израз:
израз-за-еднаквост
И-израз & израз-за-еднаквост
288 Референтно упатство Додаток А
израз-за-еднаквост:
релациски-израз
израз-за-еднаквост == релациски-израз
израз-за-еднаквост != релациски-израз
израз-за-поместување
израз-за-поместување:
израз-за-додавање
израз-за-поместување << израз-за-додавање
израз-за-поместување >> израз-за- додавање
израз-за-додавање:
мултипликативен-израз
израз-за-додавање + мултипликативен-израз
израз-за-додавање -мултипликативен-израз
мултипликативен-израз:
израз-за-претопување:
унарен израз
( име-на-тип) израз-за-претопување
унарен-израз:
постфиксен израз
++унарен израз
-- инарен израз
унарен-оператор израз-за-претопување
sizeofунарен-израз
sizeof ( име-на- тип)
постфиксен-израз:
примарен-израз
постфиксен-израз [израз]
постфиксен-израз (аргумент-израз-листаор)
постфиксен-изразо идентификатор
постфиксен-израз ->+ идентификатор
постфиксен-израз ++
постфиксен-израз --
примарен-израз:
идентификатор
константа
стринг
(израз)
аргумент-израз-листа:
израз-за-доделување
листа-израз-за-доделување, израз-за-доделување
константа:
интегрална-константа
знаковна-константа
реалнобројна-константа
енумерациска-константа
контролна-линија:
# define идентификатор секвенца-од-белези
# define идентификатор (идентификатор, .. о, идентификатор)
секвенца-од-белези
# иndef идентификатор
# inclиde < име-на-датотека >
# inclиde "име-на-датотека "
# line константа " име-на-датотека "
# line константа
# error секвенца -од-белези opt
# pragтa секвенца-од-белези opt
#
претпроцесорски -услов
290 Референтно упатство Додаток А
претпроцесорски-услов:
if-лuнuja:
# if константен-израз
# ifdef идентификатор
# ifndef идентификатор
elif-дeлoвu:
elif-лuнuja текст
elif-дeлoвuopr
elif-лuнuja:
# elifконстантен-израз
еlѕе-дел:
еlѕе-линија текст
еlѕе-линија:
#else
Додаток Б: Стандардна библиотека
ltinclude <Заглавје>
29 1
292 Стандардна библиотека Додаток Б
Еден поток се поврзува со датотека или уред преку негово отворање; таа
врска с е прекинува со затворање на потокот . Отворање на датотека враќа по
кажувач кон објект од тип FILE , кој чува разни податоци потребни за контрола
на потокот. Наизменично ќе ги користиме термините "датотечен покажувач " и
"пото к ", во случаите каде нема двосмисленост.
Кога една програма за почнува со извршување, трите потоци stdin, stdout
и ѕ tderr веќе се отворени .
fopen ја отвора именуваната датотека , и враќа поток , или, пак, NULL вред
ност во случај на неус пех . За полетоmode легални се следниве вредности :
како во "rb" или "w+b", тогаш станува збор за бинарна датотека. Имињата на
датотеките се ограничени на FILENAМE_МAX број на знаци. Најмногу FOPEN_
МАХ број на датотеки може да бидат отворени во еден момент.
FILE *freopen (const char *filename, const char *mode , FILE *stream)
freopenja отвора датотеката во наведениот мод и асоцира поток со
неа. Враќа поток, или NULL при појава на грешка . freopen за проме
на на датотеките асоцирани со stdin , stdout или stderr .
int setvbuf (FILE *stream , char *buf , int mode, size_ t size)
setvbuf го контролира баферирањето кај потокот; мора да биде
повикана пред читање запишување или која било друга операција.
М одат _ IOFВF предизвикува целосно баферирање, _ IOLВF линиско
баферирање на текстуални датотеки , а за_IONВF нема баферирање.
Ако полето buf не е NULL, истото ќе се користи како бафер, во спро
тивно ќе се алоцира бафер . Полето size ја определува големината на
баферот . Во случај на грешка setvnuf враќа ненулта вредност.
на полето format. Враќа број на запишани знаци , или негативен број во слу
чај на грешка. Стрингот за форматирање содржи два типа на објекти: оби чни
објекти, кои се копираат во излезниот поток , и спецификации за конверзија ,
од кои секоја предизвикува конверзија и печатење на следниот последователен
аргумент во fprintf. Секоја спецификација за почнува со знакот % и завршува со
знак за конверзија. Помеѓу % и знакот за конверзија, во редослед, може да има:
бланко: доколку првиот знак не е знак плус или знак минус , напред
се додава празно место.
- Модификатор за должина h, 1 (буквата ел), или L . " h " укажува дека со
одветниот аргумент треба да биде печатен како short или unsiqned short ;
" 1" укажува дека аргуме нтот е од тип lonq или unsiqned lonq . " L " ука жува
дека аргументот е 1onq doub1e .
полето arg 1 кое е иницијализирано со макрото va_ start и можеб и со пов ици
кон va_ arg. Погледнете ја дискусијата на <stdarg. h> Дел 57.
Едно влезно поле се дефинира како стринг од непразни знаци ; се протега до следното
празно место или колку што е широчината на полето доколку е наведен а . Тоа импли
цира дека scanf ќе чита преку границата на линијата за да го најде својот влез 1 бидејќи
знаците за нови линии се п разни места . (Знаци за праз но место се знакот за блан ко,
таб, знакот за нова линија, знакот за нов ред, верmкален таб и знак за нов лист. )
Знакот за конверзија укажува на интерпретацијата на влезното п ол е .
Соодветниот аргумент мора да биде покажувач. Легалните знаци за ко н верзиј а
се пр и кажани во табела Б. 2.
На знаците за конверзија d 1 i 1 n 1 о 1 u и х може да и м претход и h докол
ку аргументот е покажувач кон short а не int 1 или со 1 (буква ел) доколку
а ргументот е покажувач кон 1ong . На знаците за конверзиј а е 1 f 1 и g може да
им претходи 1 ако во аргументната листа има покажувач кон doub1e а н е кон
зад. ungetc го враќа знакот кој бил пратен назад или EOF во случај на
грешка.
clearer(fp) .
враќа ѕ
еоѕ(х) КОСИНУС ОД Х
t&n(x) тангенс од х
char**)NULL) .
void*malloc(size_tsize)
malloc враќа покажувач кон простор за еден објект со големина
size 1 или NULL доколку барањето не може да се задоволи. Просторот
не е иницијализиран .
void*bsearch(constvoid*key,constvoid*base,size_tn , size_tsize,
int (*cmp) (constvoid *keyval, constvoid *datum))
bsearch пребарува низ base [О] ... base [n-1] за елемент кој одго
вара на *key. Функцијата cmp мора да врати негативен резултат ако
нејзиниот прв аргумент (клучот на барањето) е помал отколку нејзи
ниот втор аргумент (елемент на табелата) , нула ако се еднакви и по
зитивна вредност ако е поголем. Елементите на низата base мора да
бидат во растечки редослед. bsearch враќа покажувач кон пронајде
ниот елемент или NULL доколку истиот не постои .
308 Стандардна библиотека Додаток Б
div_tdiv(intnum, intdenom)
div пресметува количник и остаток од num/denom. Резултатот се
сместува во int членовите quot и rem во структура од тип div_t.
assert (израз) ,
va_listap;
Макрото
i f (setjmp(env) == О)
/* дојди туха nри дирехтен nових*/
else
/* дојди туха со nовихуваље на longjmp */
пречекорување на опсег
tm_isdst е поз итивен ако сме во сезона со поместено време 1 нула до колку
clock_tclock(void)
clock го враќа потрошеното процесорско времето од страна н а
програмата од почетокот на нејзиното извршување 1 или -1 ако инфор
мацијата не е достапна . clock () /CLК_PER_SEK е време во секунди .
лентна е со
asctime(localtime(tp))
size_t strftime (char *ѕ, size_t Slll4x , const char *fmt, const struct
tm *tp)
strftime ја форматира информацијата за датумот и времето содр
жана во *tp, во стрингот ѕ во согласност со полето fmt, аналогно на
%Ѕ секунда (00-61).
%U број на седмица во годината (недела е 1-от ден од седмицата) (00-
53) .
%w ден од седмицата (о- б 1 недела е о) .
%W број на седмица од годината (понеделник е 1-от ден од седмицата)
(00-53).
%х локална претстава на датумот.
%% %.
МАХ char
СНАR MIN О или ЅСНАR MIN минимална вредност за
char
INТ МАХ 32767 максимална вредност за
int
INТ MIN -32767 минимална вредност за
int
LONG МАХ 2147483647 максимална вредност за
long
LONG MIN -2147483647 минимална вредно ст за
long
314 Стандардна библиотека Додаток Б
signedchar
ЅСНАR MIN -127 минимална вредност за
signedchar
ЅНRТ МАХ +32767 максимална вредност за
short
SHRT MIN -32767 минимална вредност за
short
UCНAR МАХ 255 максимална вредност за
unsigned char
UINT МАХ 65535 максимална вредност за
unsigned int
ULONG МАХ 4294967295 максимална вредност за
unsigned 1ong
USHRT МАХ 65535 максимална вредност за
unsigned short
броевиприсобирање
FLT DIG б декадни цифри на прецизност
FLT EPSILON 1Е-5 најмалиот број х, за кој 1. о +х ~ 1 . о
FLT МАNТ DIG број на цифри на основата FLT_ RADIX
во мантиса
3 17
318 Преглед на промените Додато к В
Параграф.А.7.7.
- Контролниот израз и саѕе ознаките кај swi tch 1 може да бидат од инте
грален тип.
Индекс
' апостроф 21.43-45,226 45,226
-- оператор за декрементирање ( намал ување за \f нов_лист (анг. formfeed), знак за 45,226
1) 20, 55, 124, 238 \п нова_линија, знак за 7, 17, 22. 43-45, 226, 291
- оператор за одземање 49, 241 \r знак за нов ред (анг. carriage returп) 45,226
- операторот унарен минус 238-239 \t таб, знак за 9, 12, 45,226
! логички о перато р за негација 50, 238-239 \v вертикален таб, знак за 45,226
!= оператор за.е разли чн о од• 18, 49, 243 \х хексадекадна излезна секвенца 43, 226
• наводни к 9, 22, 45, 227 л битски оператор: исклучиво ИЛИ 57, 243
# претпроцесорски оператор 105.278 _ знакот подвлечено4 1 , 226,291
## претпроцесорски оператор 105,278 _FILE_ преmроцесорско име 309
#def iпе 15,104.276 _ LINE_ претпроцесорско име 309
#def ine наспроти enum 46,175 _fillbuf фун кција 209
#def ine со аргументи 104 _IOFBF, _IOLBF, _IONBF 294
#def ine, мултилиниски 104 1битски оператор: ИЛИ 57, 243
#else, #elif 107,281 11 логички оператор ИЛИ 24, 49, 58, 246
#endif 107 - операторот комплемент на 58, 238-239
#error 282 + оператор за собирање 49, 241
#if 107, 158, 279 + оnераторот уна рен nлус 238-239
#ifdef 107,281 ++ оператор за ин крементирање (зголемување
#ifndef 107,281 за 1) 20, 55,1 24, 238
#include 38, 103, 178, 279 += оператор за доделување 59
#line 282 < оnератор за помало од 49, 242
#pragrma 282 « оператор за nоместување во лево 58, 242
#undef105,202, 278 <= оnератор за nомало или една кво на 49, 242
% оnератор за остаток при цел обројно делење <assert.h> заглавие (анг. header) 308
(модул) 49, 241 <ctype.h> заглавје 51,301
%1d претворање 20 <errno.h> заглавје 301
& адресен оп ератор 109, 238 <float.h> заглавје 42,314
&& логички оп еартор И 24, 49, 58, 243 <liraits.h> заглавје 42,314
&. битски оператор: И 57, 243 <locale.h> заглавје 291
* оператор за множење 49, 241 <math. h> заглавје 52, 304
*оператор за дереференцирање 110,238 <setjmp.h> заглавје 309
, оператор за пирка 73, 247 <signal .h> за главје 311
. оператор за членство во структура 150, 235 <stdarg.h> загла вје 182, 205, 309
.. . декларација 182, 237 <stddef .h> заглавје 121 , 158, 291
.h екстензија на име на датотека 38 <stdio.h> заглавје б, 18, 104-105, 119, 177-178,291
1оператор за делење 11,49,241 <stdio.h>, сод ржини од 207
?: тернарен оператор за условен израз 61, 246 <stdlib.h> заглавје 83, 166, 305
\\ знакот контраниз (анг. backslash) 9, 45 <string.h> заглавје 46, 124, 302
\О знакот null ( ништо, нула, празно) 35, 45, 226 <time.h> заглавје 311
\а знак за аларм 45,226 = оnератор за доделување 19, 50, 246
\b зна к за бришење на знак (анг. backspace) 9, == оnератор за еднаквост 21, 49, 243
32 1
322 Програмски јазик С Индекс
клучни зборови, програма за броење на 15б мали букви, програма за претвора ње во 179
командна линија, аргументи од 133-1 38 мемориски простор, дефиниција на 249
коментар 10,223-224, 27б мемориски простор, заземач (алокатор) 1бб,
компајлирање наС програма б, 28 217-221
компајлирање на повеќе датотеки 82 мемориски простор, резервирање на 249
ком пајли ра ње, засебно
79, 93, 273 меморискиот простор, редослед на низа во 131,
комплемент на, операторот , - 58, 238-239 259
конкатенација ( надоврзување ) на белези 105, 278 множење, оnераторот, • 49, 241
конкатенација ( надоврзување) на стрингови модул (остаток при делење), операторот, % 49,
45,105,227 241
константа, искористување на 278 модуларизација 27, 32, 39, 79,87-88, 126
константа , суфикс на 43, 22б мултипликативни оператори 241
константа, тип на 43, 22б main функција б
константен израз 45,б9, 107,247 main, return од 29, 192
константи 43, 224 makepoint функција 152
контраниз, знакот (а нг. backslash), \\ 9, 45 malloc библиотечна функција 1б8, 195, 30б
контролен знак 302 malloc функција 219
контролна линија 103, 27б-278 memchr библиотечна функчија 304
memcmp библиотечна функција 304
л memcpy библиотечна функција 304
л вредност (aнг.lvalue) 230 memmove библиотечна функција 304
лево поместување, оператор за, << 58, 242 memset библиотечна функчија 304
лексикографско подредување 138 mktime библиотечна функција 312
лексички делокруг 273 modf библиотечна функција 305
лексички конвенчии 223 month_day функција 130
линии, програма за броење на 21 month_name функција 132
линии, спојување на 27б morecore функција 220
листа на клучни зборови 224
листање на директориуми , програма за 21 О н
логичка негачија, операторот,! 50, 238-239 наводник, знакот, • 9, 22, 45, 227
логички OR, операторот, ! ! 24, 49, 58, 24б нагорно претоnување на аргумент 54, 237
логички израз, нумеричка вредност на 52 нагорно претопување, интегрално 52, 230
логичко И, операторот, 5.& 24, 49, 58, 243 надворешна (глобална) променлива 3б, 86, 228
локализација, прашања околу 291 надворешна (глобална) променлива, декларачија
labs библиотечна функција 308 оf3б,270
ldexp библиотечна функција 305 надворешна (глобална) променли ва, дефиниција
ldiv библиотечна функција 308 of38,273
localtime библиотечна функција 312 надворешна(глобална) декларација 270-271
log,log 10 библиотечни функции 305 надворешни (глобални ) имиња, должина на 41,
long double, константа 43, 227 224
long double, тип 42,227 надворешни (глобални) статички променливи 97
long, константа 43,22б надворешно (глобално) поврзување 8б, 224, 228,
long, тип 11, 20, 42, 227, 250 250, 275
LONG_MAX, LONG_MIN ЗОб најдолга линија, програма за 33, 37
longjmp библиотечна функчија 309 научна (анг.
scientific) нотација 43, 8б
lookup функција 170 небафериран getchar 201
lower функција 51 небафериран влез 200
ls наредба 210 негативни индекси 117
нееднаквост, оператор за, != 18,49,243
м некомплетен тип 251
макро претпроцесор 103,275-282 неконзистентна декларација на тип 85
макроа со аргументи 104 нелегална покажувачка аритметика 119-1 21, 1б2,
Програмски јазик С Индекс 327
покажувач наспроти liиза 114, 116-117, 122, 132 претворање, float-double 52, 232
покажувач, void * 109, 120, 140,233 претворање, експицитен оператор за види
покажувач, аргумент 117 претоn ување
покажувач, безличен (анг. null) 119, 232 претворање, знаковен-целоброен 2б,50, 230
покажувач, генерирање (созда вање) на 234 претворање, покажувач-целоброен 232-234, 241
покажувач, декларација на 110, 117,257 претворање, реален-целоброен 54, 230
покажувач, иницијализација на 119, 1б2 претворање, целоброен-знаковен 54
покажувач, претворање на 1бб, 232, 241 претворање, целоброен-покажувач 233, 241
покажувачи и индекси 114,1 1б,259 претворање, целоброен-реален 13, 230
покажува чи , дозволени операции врз 120 претопување, конверзија преку 54, 232-234, 241
покажувачи, низа од 125 претопување, оператор за 54, 1б6, 195, 232, 241,
покажувачи, одземање на 120, 1б2, 232 263
покажувачи, споредба на 119, 1б2, 219, 225 претпроцесор, макро 103, 275-282
покажувачка аритметика 110, 115, 117-120, 137, претпроцесорси оператор, defiпed 107,281
1 б2, 241 претпроцесорски оператор , # 105, 278
покажувачка аритметика, градирање во 121, 232 nретпроцесорски оператор, ## 105, 278
покажувачка аритметика, недозволена 119-121, претпроцесорско име, _FILE_ 309
1б2, 241 претпроцесорско име, _LINE_ 309
покажувач-целоброен, претворање 231-233, 241 претпроцесорско име, однапред дефинирано 282
пол е ѕее би тско пол е префисно ++и-- 55, 124
полска нотација 87 пречекорување (анг. overflow) 49,234,304, 311
помало или еднакво на, операторот, <= 49, 242 nречекорување на долна граница (анг. uпderflow)
помало од, операторот, < 49, 242 49, 304, 311
поместување, оператори за 57, 242 привилегии на датотека 204
постфиксен ++и-- 55, 123 примарен израз 234
поток, бинарен 187,291-292 пристап кон датотека, мод 187, 209, 292
поток, текстуален 17, 177, 291 провизорна дефиниција 273
празен исказ види пull исказ програма за calculator 85, 87, 89, 185
празен стринг 45 програма за cat 187, 189-192
празна функција 82 програма за del 14б
п разни места, програма за броење на 25, 70 програма за echo 134-1 35
nразни место, бланко 223 програма за fsize 213
празно место, знаци за 184, 194, 297, 302 програма за uпdcl 147
преведување, редослед на 275 програма за броење на зборови 22, 163
преведување, фази на 223, 275 програма за броење на знаци 19
превод, еди ница за 223, 270, 273 програма за броење на знаци 19
предимство (предност) на оператори 19, б2, 111 , програма за броење на клучни зборови 15б
154-155, 234 програма за броење на линии 21
преносливост 3, 43, 51 , 58, 172, 177, 179, 217 програма за броење на празни места 25, 70
престапна година, пресметка на 49, 130 програма за копирање (пресликување) на
претворања, вообичаени аритметички 50, 232 датотека 18-19, 201,204
претво рање (конверзија) 231-233 nрограма за листање на директориум 21 О
претворање (промена ) на името на низа 11б, 234 програма за надоврзување на датотеки 187
претворање на покажувач 166,232,241 програма за најдолга линија 33, 37
претворање на тип преку returп 8б, 270 програма за наоѓање на облик (форма , анг.
претворање на тип, оператор за види правила за pattern)79, 81, 135-137
претворање преку претоnување 50, 52, 232 програма за подредување 126,139
nретворање на функција 234 nрограма за претворање во мали букви 179
претворање преку поврат (анг. returп) 8б, 270 програма за претворање на температура 9-1 О,
претворање со доделување 52, 246 13-15,17
претворање со претопување 54, 232-234, 241 програма за табела за поврзување 1б8
претворање, double-float 54, 232 програма, форма на 11, 21 , 25, 47, 1б2, 223
Програмски јазик С Индекс 329
nрограма, читливост на 11, 61, 76, 101,172 register спецификатор на класа на мемориски
програмски аргументи види аргументи од nростор 97, 249
командна линија remove библиотечна функција 292
променлива 228 rename библиотечна функција 292
променлива должина, листа на аргументи со return (nоврат) од main 29, 192
182,205,236,260,270,309 return, иcкaзoт 28,35, 82, 86,270
променлива, автоматска 36,87,228 return, nретворање на тип преку 86, 270
променnива, адреса на 32, 11 О, 238 reverse функција 73
променлива, надворешна (глобална) 36, 86, 228 rewind библиотечна функција 301
променливи, должина на имиња на 224 Richards, М. 1
променливи, синтакса на имиња на 41 , 224 Ritchie, D. М. xi
nрототиn на функција 29, 35, 54, 85, 140, 236
perror библиотечна функција 301 е
рор функција 90 самореференцирачка структура 164,253
pow библиотечна функција 27, 305 секвенца на искази 266
power функција 28, 31 селекција, исказ за 268
printd функција 102 симболички ко нстанти, должина на 41
printf библиотечна функција 7, 12, 20, 179, 296 синтакса на имињата на nроменливите 41 , 224
printf претворања, табела на 180, 2% синтаксна н отација227
pгintf примери, табела на 14,180 системски nовици 199
ptlnreet функција 152 сложен исказ 65, 98, 266, 270-272
ptrdiff_t име на тип 121, 172, 242 современ стил, функција во 236
push функција 90 сnецификатор на класа н а мемориски простор
putc библиотечна функција 188,299 249
putc макро 207 сnецификатор на класа на мемориски простор,
putchar библиотечна функција 17, 178, 188, 299 auto 249
puts библиотечна функција 192, 299 сп ецификато р на класа на меморис ки nростор,
extern 36, 38, 93, 249
р сnецификатор н а кла са на мемориски п ростор,
реален-целоброен, претворање 54, 230 register 97, 249
реална константа 13, 43, 227 сnеци фикатор н а класа на мемори с ки n ростор,
реални, типови на 229 static 97, 249
реrистер, адреса на 249 спецификатор н а класа на мемори с ки n ростор,
редирекција види влез/излез, редирекција отсуство на 250
(nренасочување) nри спецификатор на тип 250
редослед на извршување 24, 58, 63, 75, 90, 105, спецификаторот enum 46, 256
111 , 234 спецификаторот struct 256
редослед на nреведување 275 спецификаторот union 256
резервирани зборови 42,224 сnојување на линии 276
резервирање на мемориски простор 249 сnоредување н а покажувачи 119, 162, 219, 243
рекузивно-спуштачки napcep 144 сnроведува
стринг литерал види стринг константа, тип на 234 stdin 188, 292
стринг, должина на 35, 45, 122 stdout 188, 292
стрингови, надоврзување на 45,105,227 str index функција 81
структура, вгнездена 151 strcat библиотечна функција 302
структура, големина на 162, 239 strcat функција 57
стру ктура, декларација на 150,251 strchr библиотечна функција 302
структура, име на член на 150, 253 strcmp библиотечна функција 302
структура, иницијализација на 150, 262 strcmp функција 124
структура, оператор за членство во, . 150, 235 strcpy библиотечна функција 302
структура, операторот п о кажувач на,-> 154, 235 strcpy функција 123-1 24
структура, покажувач на 160 strcspn библиотечна функција 304
структура, самореференцирачка 164, 253 strerror библиотечна функција 304
структура, таг ( име, ознака) на 150, 251 strf time библиотечна функција 312
структури, взаемно рекурзивни 164, 253 strleп библиотечна функција 304
структури, иницијализација на низа од 156 strlen функција 46, 11б, 121
структури, низа од 155 strncat библиотеч на функција 302
структурна референца , семантика на 237 strncmp библиотечн а функција 302
структурна референца , синтакса 237 strпcpy библиотечна функција 302
суфикс, константен 226 strpbrk библиотечна функција 304
sbrk системски повик 219 strrchr библиотечна функција 302
scanf библиотечна функција 112, 184, 298 strspn библиотечна функција 304
scanf изземање од доделување 184, 297 strstr библиотечна функција 304
scanf претворања, табела на 185, 298 strtod библиотечна функција 305
SEEK_CUR, SEEK_END, ЅЕЕК_ЅЕТ 301 strtok библиотечна функција 304
setjmp библиотечна функција 309 strtol, strtoul библиотечни функции 306
setbuf библиотечна функција 294 struct спецификатор 251
setvbuf библиотечна функција 294 swap функција 103, 112, 129, 141
Shell, D. L. 72 switch, исказот 69, 88, 268
shellsort функција 73 syscalls.h вклучувачка датотека 201
short, тип 11, 42, 239, 250 system библиотечна функција 195, 308
SIG_DFL, SIG_ERR, SIG_IGN 311
signal библиотечна функција 31 1 т
sin библиотечна функција 305 табела за поврзување, nрограма за 168
sinh библиотечна функција 305 табела на printf претворања 180,296
ѕ izе_tименатип 121 ,1 58, 172,239,292 табела на printfпpимepи 14,180
sizeof, операторот 107, 121 , 158,238-239, 299 табела на scanf претворања 185, 298
sprintf библиотечна функција 182, 297 табела на излезни секвенци 45, 226
sqrt библиотечна функција 305 табела на оператори 63
squeeze функција 56 табела на стандардни заглавја 291
srand библ иотечна функција 306 таг (име, ознака ) на enumeration 256
srand функција 55 таг (име, ознака ) на union 256
sscanf библиотечна функција 298 таr (име, ознака) на структура 150, 251
stat системски повик 212 тастатура, влез од 17,177,200
stat структура 21 2 текстуален поток 17, 177, 291
stat.h include file 212-213 текстуални ли н ии, подредување на 125, 139
static класа на мемориски простор 36, 97, 228 температура, програма за претворање на 9-1 О,
static променливи , внатрешни 97 13-15, 17
static променливи , надворешни (глобал ни) 97 терминал, влез и излез од 17
static функциска декларација 97 тип на константа 43, 226
static, специфи катор на класа на мемориски тип на стринг 234
простор 97, 249 тип, декларација на 257
stderr 188, 190, 292 тип, квалификатор на 246, 250
Програмски јазик С Индекс 331
ц
цевка 178, 200
целоброен-знаковен, nретворање 54
целоброен-nокажувач, nретворање 233,241
целоброен-реален, nретворање 13,230
целобројна константаt 13,43,226
циклус види while, for, do
calloc библиотечна функција 195, 306
canonrect функција 154
саѕе ознака (aнг. label ) 69, 266
cat, nрограма 187,189-190
се команда 6, 82
ceil библиотечна функција 305
char, тиn 11 , 42, 227, 250
clearerr библиотечна функција 301
clock библиотечна функција 311
clock_t име на тиn 31 1
CLOCKS_PER_SEC 311
close системски nовик 205
closedir функција 216
const квалификатор 47, 229, 250
continue, исказот 77, 269
сору функција 33, 38
соѕ библиотечна функција 305
cosh библиотечна функција 305
Програмски јазик С
Брајан В. Керниган 1 Денис М. Ричи
Од предговорот
Како што рековме во предговорот на првото издание, "С станува покорисен како
што расте и искуството во работата со него". После десетгодишно дополнително
искуство, се уште го мислиме тоа. Се надеваме дека оваа книга ќе ви помогне да го
научите е и успешно да го користите.
ISBN 978-608-4535-48-5
9 786084 535485