int a = 5; // бүтiн айнымалы
int* р = &a; /* нұсқауышқа а шамасының
int* p (&a);
адресі жазылады */
/* жоғарыдағы операция орындалуының басқа тəсілі */
басқа инициалданған нұсқауыш мəнінің көмегімен:
int* r = р;
адрес ретінде қолданылатын жиымның немесе функцияның аты арқылы («Жиымдар» жəне «Функциялардың атауларын параметр ретінде беру» бөлімдерін қараңыз, 57 б., 82 б.):
int b[10]; // жиым
int* t = b; // жиым басының адресін меншіктеу
…
void f(int a){ /*... */ } // функцияны анықтау void (*pf)(int); // функцияға нұсқауыш pf = f; // функция адресін меншіктеу
Нұсқауышқа жады аймағының адресін айқын түрде меншіктеу:
char* vp = (char *)0xB8 000 000;
Мұндағы 0xB8 000 000 – он алтылық түрдегі тұрақты, (char *) – типті түрлендіру операциясы; тұрақты «char-ға нұсқауыш» типіне түрлендіріледі.
Бос мəнді меншіктеу:
int* suxx = NULL; int* rulez = 0;
Алғашқы жолда NULL тұрақтысы қолданылады, ол C тілінің кейбір тақырыптық файлдарында нөлге тең нұсқауыш ретінде анықталған. Жай ғана 0 түріндегі белгілеуді қолдану ұсынылады, себебі int типіндегі бұл мəн стандартты тəсілдер көмегімен мəтінге (контекстке) сəйкес дұрыс түрлендіріледі. Нөлдiк адресi бар объектілердің болмауына кепілдік берілетіндіктен, нұсқауыштың нақты объектіге сілтеме жасау шартын тексеру үшiн бос нұсқауышты қолдануға болады.
Динамикалық жады аймағын бөліп беру жəне нұсқауышқа оның адресін меншіктеу:
new операциясының көмегімен:
int* n = new int; // 1
int* m = new int (10); // 2
int* q = new int [10]; // 3
□ malloc1 функциясының көмегімен:
int* u = (int *)malloc(sizeof(int)); // 4
Жоғарыдағы мысалдың 1 операторындағы new операциясы int типіндегі шаманы орналастыруға жеткілікті болатын динамикалық жады аймағын бөліп, осы аймақтың бастапқы адресін n айнымалысында сақтауды орын- дайды. Ал n айнымалысының өзіне жады бөлу (нұсқауышты орналастыруға жеткiлiктi көлемде орын беру) программаны компиляциядан өткізу кезеңінде орындалады.
операторында (жоғарыда аталған əрекеттерден басқа) қосымша бөлінген динамикалық жадыны 10 мəнімен инициалдау жүзеге асырылады.
операторындағы new операциясы int типті 10 санға (10 элемент- тен тұратын жиым) арналған жады бөлу ісін орындайды жəне осы жады аймағының бастапқы адресін жиымның атауы ретінде қарастыруға болатын q айнымалысына жазып қояды. Жиымның атын қолдану арқылы оның кез кел- ген элементін пайдалануға болады. Жиымдар туралы 57 б. қараңыз.
Егер жады бөлу əрекетін орындау мүмкін болмаса, онда стандарт бойынша bad_alloc ерекше операциясы туындауы тиіс (олар туралы «Аластамаларды өңдеу» бөлімінде – 240 б., ал жады бөлу кезіндегі қателіктер туралы 412 б. мəліметтер берілген).
операторда дəл 1 оператордағы сияқты əрекеттер орындалады, бiрақ олар С кiтапханасынан мұраланған malloc жады бөлу функциясының көмегімен атқарылады. Функциға тек бiр параметр – бөлінетін жады көлемі байтпен беріледі. (int*) конструкциясы нұсқауыштың функциядан қайтарылатын типін қажетті типке түрлендіру үшiн қолданылады (типтерді айқын түрде түрлендіру туралы 249 б. қараңыз). Егер жады бөлу мүмкін болмаса, онда функция 0 мəнін қайтарады.
mallос функциясына қарағанда, new операциясын қолданудың артықшылықтары бар, əсiресе, ол объектілермен жұмыс iстегенде ыңғайлы болып табылады.
Егер жады new операциясының көмегімен бөлінген болса, оны delete арқылы, ал malloc функциясымен бөлінген жадыны – free функциясының көмегімен босату керек. Мұндайда нұсқауыш-айнымалы сақталады жəне оны қайталап инициалдауға болады. Жоғарыда көрсетілген динамикалық айныма- лылар келесідей түрде жойылады:
delete n; delete m; delete [] q; free (u);
Егер жады new[] көмегімен бөлінген болса, оны босату үшін delete[]
функциясын қолдану керек. Мұндайда жиымтың өлшемі көрсетiлмейдi. Егер
1malloc функциясын қолдану үшін программаға тақырыптық файлын қосу керек.
тік жақша қойылмаса, қате туралы хабарлама берілмейді, бірақ жиымның тек алғашқы элементі бос болып белгіленеді де, қалғандарын кейінгі опе- рацияларда пайдалануға болмайды. Мұндай қол жеткізуге болмайтын жады ұяшықтары «қоқыс» деп аталады.
НАЗАР АУДАРЫҢЫЗ
Егер нұсқауыш-айнымалы өзінің əрекет ету аймағынан шығып кетсе, оған бөлінген жады аймағы босатылады, яғни нұсқауыш сiлтеме жасап тұрған динамикалық айнымалыға қол жеткізу мүмкін болмай қалады. Мұндайда динамикалық айнымалының өзіне бөлінген жады босатылмайды. «Қоқыстың» пайда болуының басқа бір жағдайы – инициалданған нұсқауышқа басқа нұсқауыштың мəнiн меншіктеу. Мұндай кездерде оның бастапқы мəні мүлдем жойылады.
Жұлдызшалар, жай жəне тiк жақшалар комбинациясы арқылы құрама типтерді жəне құрама типтерге нұсқауыштарды сипаттауға болады, мысалы,
int *(*p[10])();
операторында int типіне нұсқауыштарды қайтаратын параметрсiз функцияларға деген 10 нұсқауыштан тұратын жиым жарияланған.
Келісім бойынша тік жəне жай жақшалардың басымдықтары (басымдылықтары) бірдей, бірақ олар жұлдызшадан гөрі басымырақ болып табылады да, солдан оңға қарай қарастырылады. Қарастыру реттілігін өзгерту үшiн қосымша жай жақшалар қолданылады.
Күрделi сипаттамаларды қарастыру кезінде «iштен сыртқa қарай» ережесін ұстану керек, оның əрекеттері:
егер атаудың оң жағында тік жақшалар бар болса, онда – бұл жиым, ал жай жақшалар болған жағдайда – бұл функция;
егер атаудың сол жағында жұлдызша бар болса, бұл бұрынырақ сипатталған конструкцияға нұсқауыш;
егер оң жақта жабылған жай жақша кездессе, онда жақша ішінде жоғарыда көрсетілген ережелерді пайдаланып алып, содан соң сыртқы өрнектерді қарастыру керек;
ең соңғы кезекте тип спецификаторы қарастырылады.
Жоғарыда берілген сипаттама үшін қарастырылатын приориттеттер реттілігі цифрлер көмегімен көрсетілгенде, төмендегідей болады:
int *(*p[10])();
4 2 1 3 // сипаттаманы қарастыру реттілігі
Достарыңызбен бөлісу: |