Тази секция описва системата на С за динамично заделяне . В основата и са функциите malloc ( ) и free ( ) . Всеки път когато се извиква malloc ( ) част от оставащата свободна памет се заделя . Всеки път когато се извика free ( ) паметта се освобождава . Региона от свободна памет от който се заделя паметта се нарича хийп . Прототипите на функциите за динамично заделяне са в STDLIB.H . Всички С/С++ компилатори ще включват най – малко тези четири функции за динамично заделяне : calloc ( ) , malloc ( ) , free ( ) и realloc ( ) . Обаче вашия компилатор почти сигурно съдържа допълнителни варианти на тези функции за да съгласува различни опции и разлики на средата . Ще трябва да проверите документацията на компилатора си . Въпреки че С++ поддържа функциите за динамично заделяне описани тук , не трябва да ги използвате във С++ програми . Причината за това е че С++ доставя специалните оператори за динамично заделяне наречени new и delete . Има няколко предимства от използването на операторите в С++ за динамично заделяне . Първо new автоматично заделя достатъчното количество памет за типа данни за заделяне . Второ , връща правилния тип указател към тази памет . Трето и new и delete могат да бъдат предефинирани . Откакто new и delete имат предимство над функциите в С за динамично заделяне , тяхната употреба е препоръчителна за С++ програми .( за разглеждане на new и delete , виж Глава 5 )
calloc ( )
# include < stdlib . h >
void *calloc ( size_t num , size_t size ) ;
Функцията calloc ( ) заделя памет големината на която е равна num * size . Така calloc ( ) заделя достатъчно памет за масив от num обекта с размер size . Функцията calloc ( ) връща указател към първия байт на заделения регион . Ако няма достатъчно памет за изпълнение на заявката се връща нулев указател . Винаги е важно да проверите че върнатата стойност не е нулев указател преди да опитате да я използвате . Свързани функции са free ( ) , malloc ( ) и realloc ( ) .
free ( )
# include < stdlib . h >
void free ( void *ptr ) ;
Функцията free ( ) освобождава паметта указвана от ptr в хийпа . Това прави паметта свободна за бъдещо заделяне . Наложително е free ( ) да бъде извикана с указател който е бил преди това заделен с една от системните функции за динамично заделяне ( една от malloc ( ) или realloc ( ) ) .Използването на невалиден указател при извикване най – вероятно ще разруши механизма за управление на паметта и ще причини срив на системата . Свързани функции са calloc ( ) , malloc ( ) и realloc ( ) .
malloc ( )
# include < stdlib . h >
void *malloc ( size_t size ) ;
Функцията malloc ( ) връща указател към първия байт от регион в паметта с размер size който е бил заделен от хийпа . Ако има недостатъчно памет в хийпа за изпълнение на заявката malloc ( ) връща нулев указател . Винаги е важно да проверите че върнатата стойност не е нулев указател преди да опитате да я използвате . Опита за използване на нулев указател обикновенно ще доведе до срив на системата . Свързани функции са free ( ) , realloc ( ) и calloc ( ) .
Програмен съвет
Ако пишете 16 – битови програми за фамилията процесори 8086 ( такива като 80486 или Pentium ) , тогава вашия компилатор ще доставя допълнителни функции за заделяне които съгласуват сегментния модел на паметта използван от тези процесори когато работят в 16 – битов режим . Например , това ще са функции които заделят памет от FAR хийпа ( хийпа който е извън подразбиращия се сегмент за данни ) които могат да заделят указатели към паметта която е по – голяма от един сегмент и също да освобождават такава памет .
realloc ( )
# include < stdlib . h >
void *realloc ( void *ptr , size_t size ) ;
Функцията realloc ( ) променя размера на преди това заделената памет указвана от ptr към такава определена от size . Стойността на size може да бъде по – голяма или по – малка от първоначалната . Връща се указател към блока памет понеже може да е необходимо за realloc ( ) да премести блока по ред на нарастване на неговия размер . Ако това стане , съдържанието на стария блок се копира в новия блок – няма загуба на информация . Ако ptr е 0 , realloc ( ) просто заделя size байта от памет и връща указател към тях . Ако size e 0 , паметта указвана от ptr е освободена . Ако няма достатъчно свободна памет в хийпа за заделянето на size байта , се връща нулев указател и първоначалния блок памет остава непроменен . Свързани функции са free ( ) , malloc ( ) и calloc( )
ГЛАВА 11 – Разнообразни функции на С
Функциите разглеждани в тази глава не могат лесно да се сложат в никоя друга категория . Те включват различни преобразувания , обработка на аргументи с различна дължина , сортиране и търсене и генериране на случайно число . Много от функциите обхванати тук изискват употребата на хедъра STDLIB.H . В този хедър са дефинирани два типа , div_t и ldiv_t които са типове стойности връщани съответно от div ( ) и ldiv ( ) . Също се дефинира и типа size_t които е беззнакова стойност връщана от sizeof . Tези макроси също са дефинирани :
Макрос значение
NULL Нулев указател
RAND_MAX Максималната стойност
която може да бъде върната
от функцията rand ( )
EXIT_FAILURE Стойността върната на
извикващия процес ако
прекъсването на програмата
е неуспешно
EXIT_SUCCESS Стойността върната на
извикващия процес ако
прекъсването на програмата
е успешно
Ако функцията изисква различен хедърен файл от STDLIB.H тогава при описанието на функцията ще го обсъдиме .
abort ( )
# include < stdlib . h >
void abort ( void ) ;
Функцията abort ( ) предизвиква незабавно ненормално прекъсване на програмата . Обикновенно файлове не се записват . В среди които поддържат това , abort ( ) ще върне имплементационно – зависима стойност на извикващия процес ( обикновенно операционната система ) показваща грешка . Свързани функции са exit ( ) и atexit ( ) .
abs ( )
# include < stdlib . h >
int abc ( int num ) ;
Функцията abs ( ) връща абсолютната стойност на цялото число num . Свързанa функция е labs ( ) .
assert ( )
# include < assert . h >
void assert ( int exp ) ;
Макроса assert ( ) дефиниран в хедъра ASSERT.H пише информация за грешка в stderr и след това прекъсва изпълнението на програмата ако израза exp се изчислява на 0 . В противен случай assert ( ) не прави нищо . Макар че точния изход е имплементационно – зависим , много компилатори използват съобщение подобно на това :
Assertion failed : < expression > , file , line < linenum >
( Грешно твърдение : < израз > , файл < файл > , ред < номер на ред >
Макроса assert ( ) е обикновенно използван за да ви помогне да определите дали програмата действа правилно , с израз който е създаден по такъв начин че да се изчислява на true само когато няма възникнали грешки . Не е необходимо да премахвате изразите assert ( ) от сорс кода когато програмата е дебъгната понеже ако макроса NDEBUG е дефиниран ( като нещо ) макросите assert ( ) ще бъдат игнорирани . Свързанa функция е abort ( ) .
atexit ( )
# include < stdlib . h >
int atexit ( void ( *func ) ( void ) ) ;
Функцията atexit ( ) предизвиква функцията указвана от func да бъде извикана за нормално прекъсване на програмата . Функцията atexit ( ) връща 0 , ако функцията е успешно регистрирана като прекъсваща функция и 0 в противен случай . Най – малко 32 функции могат да бъдат установени и те ще бъдат извикани в обратен ред на тяхното установяване . Свързани функции са exit ( ) и abort ( ) .
atof ( )
# include < stdlib . h >
double atof ( const char *str ) ;
Функцията atof ( ) преобразува низа указван от str в double стойност . Низа трябва да съдържа валидно число с плаваща точка . Ако това не е така , връщаната стойност е неопределена . Числото може да бъде прекъснато от всеки символ който не може да бъде част от валидно число с плаваща точка Това включва празните символи , пунктуациите ( различни от точки ) и символите освен “ Е “ или “ е “ . Това значи че ако atof ( ) е извикана със “100.00HELLO “ ще бъде върната стойността 100.00 . Свързани функции са
atoi ( ) и atol ( ) .
atoi ( )
# include < stdlib . h >
int atoi ( const char *str ) ;
Функцията atoi ( ) преобразува низа указван от str в int стойност . Низа трябва да съдържа валидно цяло число . Ако това не е така , връщаната стойност е неопределена , обаче повечето изпълнения ще върнат 0 . Числото може да бъде прекъснато от всеки символ който не може да бъде част от цяло число . Това включва празните символи , пунктуациите и символите . Това значи че ако
atoi ( ) е извикана със “ 123.23 “ ще бъде върната стойността int 123 , а
“ .23 “ ще бъде отхвърлена . Свързани функции са atof ( ) и atol ( ) .
atol ( )
# include < stdlib . h >
long atol ( const char *str ) ;
Функцията atol ( ) преобразува низа указван от str в long стойност . Низа трябва да съдържа валидно дълго цяло число . Ако това не е така , връщаната стойност е неопределена , обаче повечето изпълнения ще върнат 0 . Числото може да бъде прекъснато от всеки символ който не може да бъде част от цяло число . Това включва празните символи , пунктуациите и символите . Това значи че ако atol ( ) е извикана със “ 123.23 “ ще бъде върната стойността long int 123L , а “ .23 “ ще бъде отхвърлена . Свързани функции са atof ( ) и
atoi ( ) .
bsearch ( )
# include < stdlib . h >
void *bsearch ( const void *key , const void *buf ,
size_t num , size_t size , int ( *compare ) ( const void * , const void * ) ) ;
Функцията bsearch ( ) изпълнява двоично търсене в сортирания масив указван от buf и връща указател към първия член който съвпада със ключа указван от key . Броя на елементите в масива е определен от num , a размера ( в байтове ) на всеки елемент е size . Функцията указвана чрез compare се използва да сравнява елемент от масива с ключа . Формата на compare функцията трябва да бъде както следва :
int func_name ( const void *arg1 , const void arg2 ) ;
Тя трябва да връща стойност както е описано тук :
Сравнение Върната стойност
аrg1 е по – малко от arg2 по – малка от 0
аrg1 е равна на arg2 0
аrg1 е по – голяма от arg2 по – голяма от 0
Масива трябва да бъде сортиран в нарастващ ред с най – нисък адрес съдържащ най – малкия елемент . Ако масива не съдържа ключа се връща нулев указател . Свързана функция е qsort ( ) .
div ( )
# include < stdlib . h >
div_t div ( int numerator , int denominator ) ;
Функцията div ( ) връща частното и остатъка от операцията numerator / denominator ( числител / знаменател ) в структура от тип div_t . Структурата тип div_t е дефинирана в STDLIB.H и има само тези две полета :
int quot ; /* частно */
int rem ; /* остатък */
Свързана функция е ldiv ( ) .
exit ( )
# include < stdlib . h >
void exit ( int exit_code ) ;
Функцията exit ( ) предизвиква незабавно нормално прекъсване на програма . Стойността на exit_code се подава на извикващия процес обикновенно операционната система , ако средата поддържа това . По конвенция ако стойността на exit_code е 0 , или EXIT_SUCCESS , означава нормално прекъсване на програмата . Ненулева стойност или EXIT_FAILURE се използва да покаже имплементационно – дефинирана грешка . Свързани функции са atexit ( ) и abort ( ) .
getenv ( )
# include < stdlib . h >
char *getenv ( const char *name ) ;
Функцията getenv ( ) връща указател към информация за средата свързана със низ указван от name в имплементационно – дефинирана таблица за информация за средата . Средата на програмата може да включва такива неща като наименования на пътища и налични устройства . Точното естество на тези данни зависи от изпълнението . Ще трябва да проверите ръководството на компилатора за подробности . Ако извикването на getenv ( ) е със аргумент който не съвпада със нищо от данните за средата , се връща нулев указател . Свързана функция е system ( ) .
labs ( )
# include < stdlib . h >
long labs ( long num ) ;
Функцията labs ( ) връща абсолютната стойност на num . Свързана функция е abs ( ) .
ldiv ( )
# include < stdlib . h >
ldiv_t ldiv ( long numerator , long denominator ) ;
Функцията ldiv ( ) връща частното и остатъка от операцията numerator / denominator ( числител / знаменател ) в структура от тип div_t . Структурата тип div_t е дефинирана в STDLIB.H и има само тези две полета :
int quot ; /* частно */
int rem ; /* остатък */
Свързана функция е div ( ) .
longjmp ( )
# include < setjmp . h >
void longjmp ( jmp_buf envbuf , int status ) ;
Функцията longjmp ( ) предизвиква изпълнението на програмата да се върне в точката на последното извикване на setjmp ( ) . Тези две функции предоставят начин за прескачане между функции . Забележете че се изисква хедъра SETJMP.H . Функцията longjmp ( ) действа чрез пренастройване на стека са състоянието както е описан в envbuf , който трябва да е установен чрез по – ранно извикване на setjmp ( ) . Това предизвиква изпълнението на програмата да се върне на израза следващ извикването на setjmp ( ) . Така компютъра се
“ измамва “ да смята че никога не е напускал функцията която извиква
setjmp ( ) . ( Като някакво образно обяснение , функцията longjmp ( ) прескача през времето и ( паметта ) пространството към предишна точка във програмата без изпълняването на нормалния процес за връщане към функция ) Буфера envbuf е от тип jmp_buf който е дефиниран в хедъра SETJMP.H . Буфера трябва да бъде установен чрез извикване на setjmp ( ) преди извикването на longjmp ( ) . Стойността на status става връщана стойност на setjmp ( ) и може да бъде изисквана за определяне откъде идва прескачането . Единствената стойност която не е разрешена е 0 . Най – общата употреба на longjmp ( ) e за връщане от дълбоко вложени цикли когато стане грешка . Свързана функция е setjmp ( ) .
qsort ( )
# include < stdlib . h >
void qsort ( void *buf , size_t num , size_t size ,
int ( *compare ) ( const void * , const void * ) ) ;
Функцията qsort ( ) сортира масива указван oт buf чрез използване на Quicksort ( разработен от C. A. R Hoare ) . Quicksort е считан за най – добрия общо сортиращ алгоритъм . След връщане , масива ще бъде сортиран . Броя на елементите е определен от num , а размера ( в байтове ) на всеки елемент е size . Функцията указвана чрез compare се използва да сравни два елемента от масива . Формата на compare функцията трябва да бъде както следва :
int func_name ( const void *arg1 , const void arg2 ) ;
Тя трябва да връща стойност както е описано тук :
Сравнение Върната стойност
аrg1 е по – малко от arg2 по – малка от 0
аrg1 е равна на arg2 0
аrg1 е по – голяма от arg2 по – голяма от 0
Масива е сортиран в нарастващ ред с най – нисък адрес съдържащ най – малкия елемент . Свързана функция е bsearch ( ) .
Програмен съвет
Когато използвайки qsort ( ) искате да сортирате масива в намаляващ ред ( тоест от голям към малък ) просто обърнете израза използван в сравняващата функция . Тогава сравняващата функция връща следните стойности :
Сравнение Върната стойност
аrg1 е по – малко от arg2 по – голяма от 0
аrg1 е равна на arg2 0
аrg1 е по – голяма от arg2 по – малка от 0
Също ако искате да използвате bsearch ( ) в масив който е сортиран в намаляващ ред , ще трябва да използвате обърнатата сравняваща функция .
raise ( )
# include < signal . h >
int raise ( int signal ) ;
Функцията raise ( ) изпраща сигнал определен от signal към изпълняваната програма . Тя връща 0 ако е успешна и ненула в противен случай . Тя използва хедъра SIGNAL.H . Следните сигнали са дефинирани от стандарта ANSI C . Разбира се вашия компилатор може да доставя и допълнителни сигнали .
Макрос значение
SIGABRT Прекъсваща грешка
SIGFPE Грешка в плаващата точка
SIGILL Лоша инструкция
SIGINT Потребителя е натиснал Ctrl - C
SIGSEGV Непозволен достъп до паметта
SIGTERM Прекъсва програмата
Свързана функция е signal ( ) .
rand ( )
# include < stdlib . h >
int rand ( void ) ;
Функцията rand ( ) генерира поредица от псевдослучайни числа . Всеки път когато се извика се връща цяло число между 0 и RAND_MAX . Свързана функция е srand ( ) .
setjmp ( )
# include < setjmp . h >
int setjmp ( jmp_buf envbuf ) ;
Функцията setjmp ( ) запазва съдържанието на системния стек в буфера envbuf за следващо извикване на longjmp ( ) . Тя използва хедъра SETJMP.H . Функцията setjmp ( ) връща 0 при извикване . Обаче longjmp ( ) подава аргумент на setjmp ( ) когато се изпълни и това е тази стойност ( винаги ненула ) която ще бъде стойност на setjmp ( ) след като е станало извикване на longjmp ( ) ( Виж “ longjmp ( ) “ за допълнителна информация ) . Свързана функция е longjmp ( ) .
signal ( )
# include < signal . h >
void ( signal ( int signal , void ( *func ) ( int ) ) ) ( int ) ;
Функцията signal ( ) регистрира функцията определена от func като манипулатор за сигнала определен от signal . Tака функцията указвана от func ще бъде извиквана когато се получи signal от програмата . Стойността на func може да бъде адреса на сигнало – манипулираща функция или един от следните макроси дефинирани в SIGNAL.H :
Макрос Значение
SIG_DFL Използва подразбиращо се
манипулиране на сигнала
SIG_IGN Отхвърля сигнала
Ако адреса на функцията е използван , определения манипулатор ще бъде изпълнен когато се получи неговия сигнал . При успех signal ( ) връща адреса на предишната дефинирана функция за определения сигнал . При грешка се връща SIG_ERR ( дефиниран в SIGNAL.H ) . Свързана функция е raise ( ) .
srand ( )
# include < stdlib . h >
void srand ( unsigned seed ) ;
Функцията srand ( ) се използва за установяване на началната точка на поредицата генерирана от rand ( ) ( Функцията rand ( ) връща псевдослучайни числа ) . srand ( ) се обикновенно използва да разреши на множество пуснати програми да използват различни поредици от псевдослучайни числа чрез определяне на различни начални точки . Обратно , вие също можете да използвате srand ( ) да генерира същата псевдослучайна поредица отново и отново чрез извикването й със същото число преди началото на всяка поредица . Свързана функция е rand ( ) .
strtod ( )
# include < stdlib . h >
double strtod ( const char *start , char **end ) ;
Функцията strtod ( ) конвертира низа представен от число съхранено в низа указван от start в double и връща резултата . Функцията работи по следния начин : Първо всеки празен символ в низа указван от start се отрязва . След това се прочита всеки символ в числото . Всеки символ който не е част от число със плаваща точка ще прекъсне процеса . Това включва празните символи , пунктуациите ( различни от точка ) и символите без “ Е “ и “ е “ . Накрая end се установява да сочи остатъка от първоначалния низ . Това означава че ако strtod ( ) се извика със “ 100.00 Pliers “ ще се върне стойността 100.00 а end ще сочи интервала който предхожда “ Pliers “ . Ако няма конвертиране се връща 0 . Ако стане препълване strtod ( ) връща или HUGE_VAL или - HUGE_VAL ( показващи положително или отрицателно препълване ) и глобалната променлива errno се установява на ERANGE . Свързана функция е atof ( ) .
strtol ( )
# include < stdlib . h >
long strtol ( const char *start , char **end , int radix ) ;
Функцията strtol ( ) конвертира низа представен от число съхранявано в низа указван от start в long и връща резултата . Основата на числото се определя чрез radix . Ако radix е 0 , основата се определя по правилата които управляват константните спецификации . Ако radix e различно от 0 , то трябва да бъде в интервала от 2 до 36 . Функцията strtol ( ) работи по следния начин : Първо всеки празен символ в низа указван от start се отрязва . След това се прочита всеки символ в числото . Всеки символ който не може да е част от long ще прекъсне процеса . Това включва празните символи , пунктуациите и символите . Накрая end се установява да сочи остатъка от първоначалния низ . Това означава че ако strtol ( ) се извика със “ 100 Pliers “ ще се върне стойността 100L а end ще сочи интервала който предхожда “ Pliers “ . Ако резултата не може да се представи чрез long , strtol ( ) ще върне или LONG_MAX или LONG_MIN и глобалната променлива errno ще се установи на ERANGE , показвайки грешка в интервала . Ако няма конвертиране се връща 0 . Свързана функция е atol ( ) .
strtoul ( )
# include < stdlib . h >
unsigned long strtoul ( const char *start , char **end ,
int radix ) ;
Функцията strtoul ( ) конвертира низа представен от число съхранявано в низа указван от start в unsigned long и връща резултата . Основата на числото се определя чрез radix . Ако radix е 0 , основата се определя по правилата които управляват константните спецификации . Ако radix e различно от 0 , то трябва да бъде в интервала от 2 до 36 . Функцията strtoul ( ) работи по следния начин : Първо всеки празен символ в низа указван от start се отрязва . След това се прочита всеки символ в числото . Всеки символ който не може да е част от unsigned long ще прекъсне процеса . Това включва празните символи , пунктуациите и символите . Накрая end се установява да сочи остатъка от първоначалния низ . Това означава че ако strtoul ( ) се извика със “ 100 Pliers “ ще се върне стойността 100L а end ще сочи интервала който предхожда “Pliers “ . Ако резултата не може да се представи чрез unsigned long , strtoul ( ) връща ULONG_MAX и глобалната променлива errno ще се установи на ERANGE , показвайки грешка в интервала . Ако няма конвертиране се връща 0 Свързана функция е strtol ( ) .
system ( )
# include < stdlib . h >
int system ( const char *str ) ;
Функцията system ( ) подава низа указван от str като команда към командния процесор на операционната система . Ако system ( ) се извика с нулев указател , ще върне ненула . В противен случай се връща 0 ( Някакъв С/С++ код ще бъде изпълнен на някои системи без операционна система и командни процесори , така че не трябва да приемате че в системата има команден процесор ) . Връщаната стойност на system ( ) зависи от изпълнението . Обикновенно тя ще върне 0 ако командата бъде успешно изпълнена и ненула в противен случай . Свързана функция е exit ( ) .
va_arg ( ) , va_start ( ) и va_end ( )
# include < stdarg . h >
type va_arg ( va_list argptr , type ) ;
void va_end ( va_list argptr ) ;
void va_start ( va_list argptr , last_parm ) ;
Макросите va_arg ( ) , va_start ( ) и va_end ( ) работят заедно за да разрешат променлив брой аргументи да бъдат подадени на функция . Най – общия пример на функция която приема променлив брой аргументи е printf ( ) . Типа va_list е дефиниран в STDARG.H . Общата процедура за създаване на функция приемаща променлив брой параметри е следния : Функцията трябва да има поне един известен параметър , но може и повече по – предни параметри в списъка със променливи параметри . Най – десния известен параметър е наречен last_parm . Името last_parm се използва като втори параметър при извикване на va_start ( ) . Преди да бъде използван някой от параметрите с променлива дължина , аргументния указател argptr трябва да бъде инициализиран чрез извикване на va_start ( ) . След това параметрите се връщат чрез извикване на va_arg ( ) с type който е типа на следващия параметър . Накрая след като са са прочетени всички параметри и по – ранно връщане от функцията , извикването на va_end ( ) трябва да осигури че стека е правилно въстановен . Ако не се извика va_end ( ) е много вероятен срив на програмата . Свързана функция е vprintf ( ) .
Програмен съвет
Т очната употреба на va_start ( ) , va_end ( ) и va_end ( ) най – добре се илюстрира с пример . Тази програма използва sum_series ( ) за да връща сумата на редица от числа . Първия аргумент съдържа броя на следващите аргументи . В този пример се сумират първите 5 елемента от следния ред :
Изхода показва “ 0 . 968750 “ .
/* Пример за променливи аргументи - сумиране на редица */
# include < stdio . h >
# include
double sum_series ( int , . . . ) ;
int main ( void )
{
double d ;
d = sum_series ( 5 , 0.5 , 0.25 , 0.125 , 0.0625 , 0.03125 ) ;
printf ( “ Sum of series is %f \n “ , d ) ;
return 0 ;
}
double sum_series ( int num , . . . )
{
double sum = 0.0 , t ;
va_list argptr ;
/* инициализиране на argptr */
va_start ( argptr , num ) ;
/* сумиране на редицата */
for ( ; num ; num - - ) {
t = va_arg ( argptr , double ) ;
sum + = t ;
}
/* извършва правилно прекъсване */
va_end ( argptr ) ;
return sum ;
}
Сподели с приятели: |