Sunday, September 20, 2015

3

Лекц – 3 Си буюу Си програмчлалын хэл
СИ ХЭЛНИЙ ПРОГРАМЫН БҮТЭЦ
/STRUCTURE OF C PROGRAMMING LANGUAGE/
Зорилго: Энэ хичээлээр Си хэлний програмын бүтэцтэй танилцаж, толгой файлыг ашиглаж сурна.
Лекцийн агуулга:
1.1.     Програмын бүтэц
1.2.     Толгой файлыг ашиглах
3.1.  Програмын бүтэц
Си хэл дээрх програм бол ямар нэг текст байдаг. Текст нь мөрүүдэд хуваагдсан байна. Мөр болгоны төгсгөлд, мөрийн төгсгөлийг заагч ASCII тэмдэгт болон шинэ мөрийн эхлэл рүү шилжүүлэгч ASCII тэмдэгтүүд байрлана. Компьютерын дэлгэцнээ ийм текст нь дээрээс доошоо мөр мөрөөрөө цуварч харагддаг. Гэхдээ мөрийн төгсгөлийг заагч тэмдэгтүүд харагдахгүй. Учир нь тэр бол үл дүрслэгдэх тэмдэгт (удирдах код) юм.
Логикийн хувьд Си хэл дээрх програм олон тооны функц төрлийн дэд програмууд болон өгөгдлүүдээс тогтох ёстой. Функц нь өгөгдлийг боловсруулах үйлдлүүдийг агуулдаг. Ер нь бол Си хэлэнд процедур төрлийн дэд програм гэж байхгүй. Зөвхөн функц төрлийн дэд програм л тодорхойлогдсон байдаг.
Функцуудын дунд main гэсэн нэртэй нэг функц үндсэн програмын үүргийг гүйцэтгэнэ. Энэ функцыг үндсэн функц гэдэг. Үндсэн функц нь ямар ч Си програмд дандаа оршиж байх ёстой. Үндсэн функцын нэрийг дураар сонгож болохгүй бөгөөд ямагт main гэсэн нэртэй байна. Програм ажиллаж эхлэхэд хамгийн түрүүнд энэ функц удирдлагыг өөртөө авах бөгөөд бусад функц эндээс дуудагдаж ажиллана.
Хамгийн энгийн Си програм нь дан ганц main функцээс тогтсон байна. Ийм програмын бүтэц нь:
препроцессорын_директивүүд               /* препроцессорын командууд */
void main( )                                               /* үндсэн функцын толгой хэсэг (заавал бичих ёстой!) */
{                                                                 /* функцын биеийн эхлэл (заавал бичих ёстой!) */
       өгөгдлийг_зарлах;                              /* хувьсагчууд, тогтмолууд г.м. */
       биелэгдэх_операторууд;                  /* үйлдлүүд */
}                                                                 /* функцын биеийн төгсгөл (заавал бичих ёстой!) */
гэсэн хэлбэртэй. Энэ бүтцийн дагуу хамгийн анхны, хамгийн хялбар жишээ програмыг бичье. Энэ нь компьютерын дэлгэцнээ Сайн уу! гэсэн үг хэвлэдэг програм юм. Үүний алгоритмыг зурвал:
гэсэн маш цомхон блок-схем байна.
Харин програмын текст нь:
#include <stdio.h>
void main( )
{
       printf (“Sain uu!\n”);               /*Дэлгэцэнд Sain uu!” гэсэн мэндчилгээ гаргана.*/
}
Ингээд л болоо. Програм бичигдэж дууслаа. Энэ програмд ямар нэг өгөгдөл зарласан хэсэг байхгүй гэдгийг шууд хэлье. Учир нь тэгэх шаардлага алга юм.
Ингээд уг програмын хэсгүүдтэй тус бүрд нь танилцъя.
3.2.Толгой файлыг ашиглах
Хамгийн эхний:
#include <stdio.h>
гэсэн мөр бол препроцессорын директив юм. Тэгэхээр препроцессорын директив гэж юу вэ? Препроцессорын директив гэдэг нь препроцессорыг удирдагч команд юм. Тэгвэл препроцессор гэж юу вэ?
Үүнд хариулахын тулд Си хэл бол дээд төвшний програмчлалын хэл гэдгийг санацгаая. Си хэл дээр бичсэн програмыг зөвхөн машины хэл рүү хөрвүүлсний дараа л компьютер биелүүлж чадна. Хөрвүүлэлтийг компилятор (хөрвүүлэгчхэмээх програм 
хийдэг:
 Тэгвэл препроцессор гэдэг нь хөрвүүлэгч програмын тусгай бүрдэл хэсэг юм.  Препроцессорын үүрэг бол програмын текстийг (эх кодыгхөрвүүлэгдэхээс нь өмнө 
Боловсруулах(хувиргахявдал юм. Ө.х. хөрвүүлэгчийн үндсэн хэсэг ажиллаж эхлэхээс урьтаж препроцессор ажилладаг бөгөөд эх кодыг ямар нэг байдлаар боловсруулдаг      байна. Боловсруулагдсантекст нь мөн л Си хэл дээр байх болно. Тиймээс дээр
үзүүлсэн схемийг үнэн хэрэгтээ:
гэж дүрслэх ёстой. Харин яг яаж боловсруулах вэ гэдгийг нь програм зохиогч өөрөө тодорхой командуудын тусламжтайгаар препроцессорт зааж өгдөг. Эдгээр командыгпрепроцессорын директивүүд гэнэ.
Препроцессор нь ажиллаж эхлэнгүүтээ эх кодыг мөр мөрөөр тандаж, ‘#’ гэсэн тэмдгээр эхлэсэн мөрүүд байгаа эсэхийг хайдаг. Хэрэв ийм мөр тааралдвал түүнийг препроцессорын директив хэмээн ойлгож, энэ директивийн дагуу текстийг хувиргана. Тиймээс препроцессорын директив ямагт # тэмдгээр эхлэх ёстой. Түүнчлэн препроцессорын директив нь дангаараа нэг мөр болж байх ёстой. Эдгээрийг тооцвол препроцессорын директивийг дараах загварын дагуу бичнэ:
#директивийн_нэр препроцессорын_лексемүүд
Энд:
·          директивийн_нэр – тухайн нэг препроцессорын директивийг төлөөлөх үг
·          препроцессорын_лексемүүд – буюу preprocessing token гэдэг нь тэмдэгт тогтмолууд, файлын нэр, идентификаторууд, үйлдлийн тэмдгүүд, тоонууд, мөр-тогтмолууд, мөн сул зайнаас ялгаатай дурын тэмдэгтүүд байж болно.
Си хэлэнд дараах директивүүд (директивийн нэрүүд) тодорхойлогдсон байна. Үүнд:
#include
#define
#undef
#if
#ifdef
#ifndef
#else
#endif
#elif
#line
#error
#pragma
Явцын дунд бид эдгээр директивүүдтэй танилцах болно.
Тэгэхээр бид одоо препроцессор, препроцессорын директив гэж юу болох талаар өнгөц ойлголттой болсон тул буцаад жишээ програм руугаа оръё. Энд буй #include директивтухайлан ямар үүрэгтэй болохыг харъя.
#include директив
Энэ директив нь програмын текстэнд өөр файлаас текст оруулж ирж тавих зориулалттай. Директивийг бичих 2 загвар байдаг. Эхнийх нь:
#include < файлын_нэр >
Хоёр дахь нь:
#include “файлын_нэр
Энд:
·          файлын_нэр - програм руу оруулах текстийг агуулсан файлын нэр.
Препроцессор ийм директивтэй таармагцаа, заасан нэр бүхий файлыг хайж эхлэдэг.
Хэрэв файлын нэрийг < > дотор бичсэн байвал хайлтыг програмчлалын системийн стандарт хавтсууд дотор тодорхой дүрмийн дагуу хийнэ. Стандарт хавтсууд гэдэг нь хатуу диск дээр системийн үүсгэж байрласан ерөнхий хавтас доторх дэд хавтсууд юм. Жишээлбэл Турбо Си++ системийн хувьд хатуу диск дээр C:\TC гэсэн замаар суусан байг гэвэл системийн стандарт хавтсууд нь C:\TC\BGI, C:\TC\BIN, C:\TC\CLASSLIB, C:\TC\INCLUDE, C:\TC\LIB, C:\TC\EXAMPLES г.м. хавтсууд байх болно.
Хэрэв файлын нэрийг дотор бичсэн байвал хайлтыг манай програмын файл байрлах тэр хавтсанд (бид програмынхаа текстийг бичээд түүнийгээ тогтмол санах ой буюу хатуу диск дээр файл болгож хадгалах хэрэгтэй биз дээ, сарын дараа дахиад хэрэг болох ч юм бил үү?) эхлэж хийгээд олдоогүй бол харин стандарт хавтсуудаас үргэжлүүлэн хайж эхлэдэг.
Ингээд заасан нэр бүхий файл олдвол түүний дотор агуулагдах бүх текстийг препроцессор нь програмын текст рүү, яг директив байрлах тэр мөрөөс эхлэн оруулж тавьдаг.
Манай жишээ програмд эхний хэлбэрийг ашигласан байгаа:
#include <stdio.h>
Энд stdio.h гэсэн файлын нэрийг бичжээ. Ө.х. энэ файлын агуулгыг програмд оруулж ирэхээр заасан байна. Тэгвэл энэ ямар учиртай файл вэ?
Үүнд хариулахын тулд үндсэн функцын биед буй ганц үйлдлийг харцгаая. Энэ нь:
printf (“Sain uu!\n”);
гэсэн оператор байгаа. График дүрслэлээр бол энэ нь:
гэсэн элемент байна. Операторыг сайтар харах аваас printf() гэсэн функц ба түүний аргумент болох Sain uu!\nгэсэн мөр-тогтмолоос бүтсэн нь мэдэгдэнэ. Энэхүү printf()
функц бол гаралтын үйлдлийг гүйцэтгэгч стандарт функц бөгөөд аргументэд нь бичсэн өгөгдлийг гаралтын хэрэгсэлд гаргах үүрэгтэй. Стандарт функц гэж хэрэглэгчийн зохиогоогүй, урьдчилан тодорхойлогдсон функцыг хэлдэг. Стандарт функц бол Си хэлэнд өөрт нь харьяалагдахгүй, харин Си хэлний стандарт санд харьяалагддаг юм. Стандарт сан гэж олон тооны стандарт функцын цогцыг хэлдэг бөгөөд энэ нь хөрвүүлэгчтэй хамт ирнэ. Тэгвэл хэлэнд өөрт нь үл харьяалагдах ийм стандарт функцыг програмдаа ашиглахын тулд тухайн функцын талаарх тодорхой мэдээллийг програмдаа эхлээд оруулж ирэх хэрэгтэй болдог. Ийм мэдээлэл нь мөнхүү stdio.h гэсэн файл дотор агуулагддаг юм. Энэ нь функцын прототип (prototype) буюу эх загвар хэмээх бичиглэл байдаг. Тиймээс printf() гэсэн стандарт функцыг ашиглахын тулд энэ функцын прототипийг агуулсан stdio.h файлыг програмдаа оруулж ирэх хэрэгтэй юм.
#include <stdio.h>
гэсэн директив чинь чухам үүнийг л хийгээд байгаа юм шүү дээ. Одоо препроцессор манай жишээ програмын текстийг яаж боловсруулах нь ойлгомжтой болсон байх. Дүрслэн үзүүлвээс:
Тэмдэглэн хэлэхэд, stdio.h файлд зөвхөн ганц printf() функцын прототип агуулагдахгүй. Оролт, гаралтын үйлдэл гүйцэтгэхэд зориулагдсан өөр олон функцын прототип агуулагддаг. Үүнийг дээрх зургаас харж болно.
h өргөтгөлтэй ийм файлыг толгой файл (header file) гэж нэрлэнэ. Толгой файл хэмээн нэрийдсэний учир нь түүнийг ямагт програмын текстийн эхэнд (толгойд) залгаж байх нь зохимжтой гэдгийг зааж байгаа юм.
Стандарт сангийн бүх функцын прототипүүд төрөл, зориулалтаараа ангилагдан өөр өөр стандарт толгой файлуудад хуваагдан агуулагдсан байдаг. Олон тооны стандарт толгой файл бий. Ж.нь Турбо Си++ хөрвүүлэгчтэй хамт ирдэг стандарт файлуудаас дурдвал:
·          alloc.h – санах ойтой ажиллах        
·          assert.h – програмыг шинжлэх
·          conio.h – текст горимд оролт, гаралтын төхөөрөмжтэй ажиллах
·          ctype.h – тэмдэгттэй ажиллах
·          dos.h – MSDOS үйлдлийн системтэй ажиллах
·          errno.h – алдаа шалгах
·          float.h – бодит тоон өгөгдөлтэй ажиллах
·          graphics.h – график горимд ажиллах
·          limits.h - бүхэл тоон өгөгдлийн хязгаарын утгууд
·          math.h – математик тооцоо хийх
·          mem.h – санах ойтой ажиллах
·          signal.h – онцгой тохиолдлуудыг шийдвэрлэх
·          stdarg.h – хувьсах тооны аргументууд бүхий функцтэй ажиллах
·          stdio.h – оролт, гаралтын хэрэгслүүд
·          stdlib.h – ерөнхий хэрэглээний функцууд (мөн санах ойтой ажиллах)
·          string.h – тэмдэгт мөртэй ажиллах
·          time.h – он, сар, өдөр болон хугацаатай ажиллах
г.м. Энд дурдаагүй өөр олон файл бий гэдгийг бас сануулъя. Дээрх толгой файлуудын зарим нь ANSI стандартад тодорхойлогдсон бол заримыг нь зөвхөн Турбо Си хөрвүүлэгч өөрөө нэмдэг.
Энэ сэдвийг дүгнээд дараах зүйлийг хэлж болно. Стандарт функцтэй ажиллахын тулд стандарт санд хандалт хийх хэрэгтэй. Стандарт санд хандахын тулд тохирох стандарт толгой файлыг оруулах хэрэгтэй. Эс тэгвээс хөрвүүлэгч алдаа заах болно. Түүнчлэн толгой файлын нэрийг буруу бичсэн тохиолдолд хөрвүүлэгч мөн алдаа заах болно. Мөн стандарт толгой файлын нэрийг ямагт < > дотор бичих хэрэгтэй:
#include <стандарт_толгой_файлын_нэр>
Бага зэрэг өөрчилсөн жишээ програм
Манай жишээ програм дэлгэц дээр мэндчилгээ гаргах ёстой. Гэтэл програмыг хөрвүүлээд, ажиллуулахад дэлгэцэнд ямар ч мэндчилгээ харагддаггүй байна. Үүнийг өөрсдөө туршиж үзээрэй. Яагаад ингэж байна вэ? Ямар нэг алдаа байна уу?
Ямар ч алдаа байхгүй. Үнэн хэрэгтээ програм ном ёсоороо ажиллаж, дэлгэцэнд Sain uu! гэсэн мэндчилгээгээ хэвлээд шууд төгсчихөж байгаа юм. Програм төгсөнө гэдэг нь түүний хэрхэн биелж байгаа процесс дэлгэцнээс алга болж, тухайн програмыг ачаалахаас өмнөх тэр төлөвтөө дэлгэц шилжиж орно гэсэн үг. Асуудлын гол нь компьютер програмыг өөрийн хурдаар, маш түргэн биелүүлэх тул биелэх процессыг програм зохиогч харж амжихгүй байгаа юм. Тиймээс манай програм үгээ хэвлэсний дараагаар шууд төгсөлгүй, түр паузлан зогсдог байх хэрэгтэй. Ингэснээр дэлгэцэнд хэвлэгдсэн үгийг хэрэглэгч харах боломжтой болно.
Үүний тулд жишээ програмдаа бага зэрэг өөрчлөлт оруулж, дараах хэлбэртэй болгоно:
#include <stdio.h>
#include <conio.h>
void main( )
{
       printf (“Sain uu!\n”);
       getch();
}
Бас нэг #include директив болон getch(); гэсэн оператор нэмсэн нь шууд харагдаж байна. Энэ оператор нь getch() хэмээх функцыг дуудсан байна. Уг функцыг ашиглахын тулд conio.h гэсэн файлыг оруулж ирсэн нь илт. Ө.х. getch() функцын прототип нь энэхүү толгой файлд агуулагддаг аж.
getch() функц нь компьютерын гараас ямар нэг товч дарагдах хүртэл програмын биелэлтийг түр зогсоодог байна. Хэрэв товч дарвал түүний ASCII кодыг утга болгон буцаана. Гэхдээ дарагдсан товчинд харгалзах тэмдэгтийг дэлгэцэнд гаргахгүй. Тэмдэглэн хэлэхэд энэ функц ANSI стандартад хамаарахгүй бөгөөд Турбо Си хөрвүүлэгчийн өөрийнх нь нэмэлт юм. Ер нь conio.h файл бүхэлдээ Турбо Си хөрвүүлэгчийн өөрийнх нь оруулж ирдэг толгой файл бөгөөд зөвхөн MS-DOS үйлдлийн системд ажиллахад зориулагдсан оролт, гаралтын хэрэгслүүдийг агуулдаг.
Манай өөрчлөгдсөн жишээ програм яаж ажиллах нь одоо ойлгомжтой болсон байх. Програмыг ачаалмагц дэлгэцэнд Сайн уу! гэсэн мэндчилгээ гарна. Харин доод талын шинэ мөрийн эхэнд курсор шилжсэн байх болно. Учир нь бид мөр-тогтмолыг бичихдээ төгсгөлд нь \n гэсэн удирдах кодыг залгасан байгаа. Удирдах код нь шинэ мөрөнд курсорыг шилжүүлэх үйлдлийг илэрхийлдэг бөгөөд дэлгэцэнд гардаггүй. Ингээд програм төгсөлгүйгээр түр зогсолт хийнэ. Учир нь getch() функц ажиллаж байгаа нь тэр. Тиймээс товч дарахгүй байгаад л байвал мэндчилгээ дэлгэцэнд харагдсан хэвээр л байх болно. Харин гараас дурын товч (ENTER, ESC, SPACE, A, B, 5 г.м.) дарахад л програм төгсөх болно.
Энэ сэдвийг дуусгахын өмнө жишээ програмаа дахиад жаахан өөрчилье. Тухайлбал текстэндээ тайлбар хийж өгье. Энэ нь програмын биелэлтэд ямар ч нөлөөгүй. Зүгээр л, мартсан байж байгаад дараа нэг харахад ойлгомжтой байхад дөхөм болов уу:
#include <stdio.h>                         /* printf() функцын прототипийг агуулсан толгой файл */
#include <conio.h>                        /* getch() функцын прототипийг агуулсан толгой файл */
void main( )
{
       printf (“Sain uu!\n”);               /* дэлгэцэнд мэндчилгээ хэвлэх оператор */
       getch();                                    /* гараас товч дарах хүртэл програмыг түр зогсоох оператор */

}

No comments:

Post a Comment