Menu

Daxil olun Qeydiyyat

C Proqramlaşdırma Dili

Siyahılar

Siyahılar

Biz 6-cı mövzuda Cərgələr ilə tanış olduq. Misal üçün, əgər biz int tipli və 10 elementdən ibarət cərgə yaratmaq istəyiriksə, onda int x[9]; yazırıq. Bu zaman yaddaşda hər biri 4 bayt (int) olan, 10 yerdən ibarət hissə ayrılır və bu hissənin başlanğıcına x adı ilə müraciət olunur.

Cərgələr çox əlverişlidir və çox istifadə olunur, lakin onların bir mənfi cəhəti var. Onlar statikdirlər, yəni əgər 100 baytlıq struct ishci tipindən olan 1000 elementli "Mühəndislər" cərgəsi elan etmişiksə (struct ishci muhendisler[1000];), bu zaman yaddaşda 100*1000 bayt yer ayrılır.
Əgər proqramın icrasının müəyyən nöqtəsində bizim bu cərgəyə ehtiyacımız yoxdursa, onda biz bu yaddaşı azad edə bilmərik. Belə olan hallarda siyahılardan istifadə edirlər. Siyahılar bir tərəfdən ünvan dəyişənləridir, yəni onları proqramın icrası zamanı istənilən vaxt yaradıb, silə bilərik. Digər tərəfdən isə, siyahılar cərgələri xatırladır. Onların hər bir elementi digər elementlə əlaqəli olduğundan, onların hamısına eyni adla müraciət etmək olur. Siyahıların cərgələrdən üstün cəhəti odur ki, siyahılar dinamikdirlər və onlara istənilən sayda element əlavə etmək olar. Cərgələr ilə isə, bu mümkün deyil. Əgər 10 elementli cərgə elan etmişiksə, 11-ci elementi ona heç bir yolla əlavə etmək olmaz.

Siyahıların sintaksisini verməzdən və proqram nümunələri ilə tanış olmazdan əvvəl, gəlin, siyahıların yaddaşda necə yerləşməsi ilə tanış olaq.

Əgər biz hər hansı bir tipdən (adi və ya struct) olan adi dəyişən elan etmək istəyiriksə, onda tip deyishenin_adi; sintaksisindən istifadə edirik.
Məsələn:
int x;
struct ishci muhendis;

Əgər biz hər hansı bir tipdən (adi və ya struct) olan ünvan dəyişəni elan etmək istəyiriksə, onda tip *deyishenin_adi; sintaksisindən istifadə edirik.
Məsələn:
int *x;
struct ishci *muhendis;

Əgər biz hər hansı bir tipdən (adi və ya struct) olan cərgə elan etmək istəyiriksə, onda tip (deyishenin_adi[elem_sayi];) sintaksisindən istifadə edirik.
Məsələn:
int x[10];
struct ishci muhendis[10];

Hər hansı bir tipdən (adi və ya struct) olan siyahı elan etmək isə, bir balaca artıq iş tələb edir. Gəlin, bunu konkret misal üzərində izah edək.
ishci tipindən olan muhendisler siyahısını elan edək, daha sonra, bu siyahıya bir neçə obyekt əlavə edək.
Verilmiş tipdən siyahı yaratmaq üçün yeni tip yaratmaq (struct) lazımdır. Baxdığımız məsələ üçün yeni yaradacağımız tipin adı ishci_siyahı olsun.

Sintaksis belə olar:


struct siyahinin_tipinin_adi {

    tip1 dey1;
    tip2 dey2;
    .
    .
    tipn deyn;

struct siyahinin_tipinin_adi *kecid_deyisheni; }

Misal:


struct siyahi1{

    char msg[10];
    int x;

struct siyahi1 *novb_el;}

Beləliklə, biz yeni tip yaratdıq, struct siyahi1;
Bu tipdən olan syh ünvan dəyişənini elan edək.
struct siyahi1 *syh;
Hal-hazırda yaddaşda vəziyyət aşağıdakı kimidir.

syh-ya yaddaşda yer ayırıb, onun elementlərinə qiymətlər mənimsədək.


syh = malloc(sizeof(struct siyahi));
memset(syh,0,sizeof(struct siyahi));
strcpy(syh->ad, "Əli");
syh->x=9;
syh->novb_el=NULL;

Yaddaşın vəziyyəti:

Hal-hazırda siyahımızda 1 element var. Siyahıya yeni element əlavə edək. Bunun üçün struct siyahi tipindən olan digər ünvan dəyişəni (dey1) elan edib, elementlərinə qiymətlər mənimsədək. Daha sonra, dey1-i syh-ya elavə edərik. (Əsas məqam).


struct siyahi *dey1; 
dey1 = malloc(sizeof(struct siyahi));
memset(dey1,0,sizeof(struct siyahi));
strcpy(dey1->ad, "Əli");
dey1->x=9;
dey1->novb_el=NULL;

Yaddaşın vəziyyəti:

dey1–i yaratdıq, onu syh-ya elave edək (qoşaq).

Qeyd: Bütün siyahılara yeni obyektlərin əlavə olunmasında aşağıdaki qaydadan istifadə edirlər.

syh->novbel=dey1;
Yaddaşa baxaq:


Beləliklə, biz siyahıya yeni element əlavə etdik. Lakin dey1 ünvan dəyişəni hələ də bizim siyahının son elementinə müraciət edir. Belə saxlamaq olmaz, bu, təhlükəlidir. Ünvan dəyişənləri ilə işləyən zaman xüsusilə ehtiyatlı olmaq lazımdır. Bizim siyahıda istifadəçilərin qiymətli məlumatları ola bilər. Əgər ona hansısa ünvan dəyişəni bizim nəzərimizdən uzaq müraciətdədirsə, onda bu o deməkdir ki, biz proqramımızda istifadəçi məlumatlarına açıq pəncərə yerləşdirmişik. Pis proqramlaşdırma təcrübəsi!
Gəlin, dey1-in syh-ya olan müraciətini ləğv edək. Bunu üçün sadəcə olaraq, dey1=NULL; yazmağımız yetər.
Gəlin, syh-ya daha bir obyekt əlavə edək. dey azad olduğundan, ondan istifadə edə bilərik.


dey1 = malloc(sizeof(struct siyahi));
memset(dey1,0,sizeof(struct siyahi));
strcpy(dey1->ad, "Vəli");
dey1->x=10;
dey1->novb_el=NULL;

Obyekti yaratdıq, onu siyahıya əlavə edək.
İndi tutaq ki, siyahıda 10 obyekt var.

Biz istəyirik ki, siyahıda olan 3-cü obyektin x elementini çapa verək. Kod aşağıdakı kimi olacaq.


struct siyahi *dey1;
dey=syh;


İkinci obyektə sürüşmək üçün yazırıq.
dey1=dey1->novb_el;

Bir addım da sürüşsək, onda 3-cü obyektin üstünə düşürük.
dey1=dey1->novb_el;

İndi dey1 siyahıda 3-cü obyektə müraciət edir və biz asanlıqla x elementini çap edə bilərik.
printf("%d\n",dey->x);

Ümumiyyətlə, dey1=dey1->novb_el; kodu siyahıda yuxarıdan aşağı hərəkət etmək üçün istifadə olunur. Bu zaman manevr imkanlarını artırmaq üçün siyahının ilk və son elementlərinə istinad edən ünvan dəyişənlərindən istifadə olunur. Aşağıdakı kimi:


//prog_9_1.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* struct işçilər adlı siyahı elan edirik */

struct ishciler{
    char ad[20];
    int x;

struct ishciler *novb_el;};


int main(int argc, char *argv[]){

struct ishciler *muhs,*dey; /* mühəndislər */

muhs = malloc(sizeof(struct ishciler));
memset(muhs,0,sizeof(struct ishciler));

muhs->x=50;
strcpy(muhs->ad,"Vəli");

/* Keçid elementini NULL-a mənimsədirik.
   Yaddaşda heç bir yerə istinad etməsin. */

muhs->novb_el=NULL;

/* muhs siyahısında artıq bir obyektimiz var, əlavə obyektlər əlavə edək */

dey = malloc(sizeof(struct ishciler));
memset(dey,0,sizeof(struct ishciler));
dey->x=60;
strcpy(dey->ad,"İmran");

/* Keçid elementini NULL-a mənimsədirik.
   Yaddaşda heç bir yerə istinad etməsin. */

dey->novb_el=NULL;

/* Yeni obyekti yaratdıq. */
/* Yeni yaratdığımiz dey obyektini siyahıya əlavə edək. */

muhs->novb_el=dey;	/* Hal-hazırki vəziyyət Şəkil 9.3-ə uyğundur. */

/* dey-in siyahıya olan istinadını ləğv edək. */

dey=NULL;	/* Şəkil 9.4 */

/* Siyahıda olan obyektlərin elementlərini çap edək. */

dey=muhs;	/* dey siyahının əvvəlinə istinad edir. */

printf("muhs siyahısında olan elementlər\n");
while(dey!=NULL){
printf("%s,%d\n",dey->ad,dey->x);
dey=dey->novb_el;	/* Növbəti elementə sürüşürük,
                        əgər dey==NULL -sa (siyahının sonu), onda dövrü bitir. */
}

return 0;
}

Nümunə

Proqramı yerinə yetirək.


user@gnu_linux:~/prg# 
user@gnu_linux:~/prg# gcc prog_9_1.c -o prog_9_1
user@gnu_linux:~/prg# 
user@gnu_linux:~/prg# ./prog_9_1
muhs siyahısında olan elementlər
Vəli,50
İmran,60
user@gnu_linux:~/prg# 
user@gnu_linux:~/prg# 

İndi isə, gəlin, bu proqramın funksiyalardan istifadə etdiyimiz halına baxaq.


//prog_9_2.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* struct işçilər adlı siyahı elan edirik */

struct ishciler{
    char ad[20];
    int yash;

struct ishciler *novb_el;};

/* Çox vaxt siyahının tipini elan etdikdən sonra
   ilk və son elementlərinə istinad edən ünvan dəyişənlərindən
   istifadə edərək, yeni tip yaradırıq. Aşağıdakı kimi: */

struct ishci_syh{
struct ishciler *ilk_el;	/* Siyahının ilk elementinə istinad edən ünvan dəyişəni */
struct ishciler *son_el;	/* Siyahının son elementinə istinad edən ünvan dəyişəni */
};

/* Yeni yaratdığımız tipdən dəyişən (siyahı) elan edək */

struct ishci_syh *syh;

/* İndi isə, siyahı ilə istifadə edəcəyimiz funksiyaları elan edək. */

void elave_et(struct ishci_syh *,char *,int );	/* Siyahıya yeni element əlavə etmək üçün */

void cap_et(struct ishci_syh *);	/* Siyahının elementlərini çap etmek üçün */

int main(int argc, char *argv[]){

syh = malloc(sizeof(struct ishci_syh));
memset(syh,0,sizeof(struct ishci_syh));

/* İlk və son elementləri NULL -a mənimsədək. */

syh->ilk_el=NULL;
syh->son_el=NULL;

/* Siyahıya obyektlər əlavə edək. */

elave_et(syh,"Əli",45);
elave_et(syh,"Samir",37);
elave_et(syh,"Tahir",40);
elave_et(syh,"Rüstəm",43);
elave_et(syh,"Hidayət",55);
elave_et(syh,"Tofiq",38);
elave_et(syh,"İbrahim",24);

/* Siyahının elementlərini çap edək. */

cap_et(syh);

return 0;
}


/* elave_et funksiyası */

void elave_et(struct ishci_syh *syh, char *s, int x){

struct ishciler *dey;

dey=malloc(sizeof(struct ishciler));
memset(dey,0,sizeof(struct ishciler));

strcpy(dey->ad,s);
       dey->yash=x;
       dey->novb_el=NULL;

/* Obyekti yaratdıq, elementlərinə qiymətlər mənimsətdik.
   İndi obyekti siyahıya əlavə edək. */

/* Burada aşağıdakı qaydadan istifadə edəcəyik.
   Əgər siyahıda obyekt yoxdursa, onda ilk və son element
   yeni yaratdığımız obyektə istinad etməlidir,
   əks halda, obyekti siyahının sonuna artıracağıq.
   Bu cür əlavə etmə məsələnin şərtindən və
   proqramçının istəyindən asılı olur. */
    
/* Yoxlayaq, əgər siyahı boşdursa, onda ilk və son element
   yeni obyektə istinad etsin və dey-in istinadını ləğv edək. */
    
if ((syh->ilk_el==NULL)&&(syh->son_el==NULL)){
     syh->ilk_el=dey;
     syh->son_el=dey;
     dey=NULL; }
else {

/* Siyahıda artıq obyekt var, yeni obyekti (dey)
   siyahının sonuna əlavə et və dey-in istinadını leğv et. */

syh->son_el->novb_el=dey;	/* dey-i siyahının sonuna qoşuruq. */
syh->son_el=dey;		/* son_el-i yeni yerinə (sona) sürüşdürürük. */ 
dey=NULL;			/* dey-in siyahıya istinadını leğv edirik. */ 
}
}


/* cap_et funksiyası */


void cap_et(struct ishci_syh *syh){

struct ishciler *dey;

dey=syh->ilk_el;

printf("Siyahının elementləri\n");

while(dey!=NULL){
printf("%s,%d\n",dey->ad,dey->yash);
dey=dey->novb_el;
}
}

Nümunə

Proqramı yerinə yetirək.


user@gnu_linux:~/prg# 
user@gnu_linux:~/prg# gcc prog_9_2.c -o prog_9_2
user@gnu_linux:~/prg# 
user@gnu_linux:~/prg# ./prog_9_2
Siyahının elementləri
Əli,45
Samir,37
Tahir,40
Rüstəm,43
Hidayət,55
Tofiq,38
İbrahim,24
user@gnu_linux:~/prg# 
user@gnu_linux:~/prg# 


Bizi dəstəkləyənlər