1. Giriş
Gəlin sualdan başlayaq: ümumiyyətlə, bir dövrü digərinin içinə niyə yerləşdirmək lazımdır? Məsələ ondadır ki, tez-tez bizim məlumatlarımız və ya məsələlərimiz sadəcə bir xətt üzrə deyil, məsələn, cədvəl, grid və ya hətta çoxölçülü struktur şəklində təşkil olunur. Tutaq ki, sən ekrana vurma cədvəlini çıxarmaq, ikiölçülü massiv üzrə keçmək və ya bütün element cütlərinin kəsişmələrini hesablamaq istəyirsən. Burada bir dövr bəs etməyəcək — dövr içində dövr lazımdır.
Proqramlaşdırmada daxili dövr — sanki iki zəngli saat kimidir: xarici başlayır çalmağa, onun içində isə daha biri işə düşür və hər dəfə birincisi aktiv olanda çalır. Yəni, bir "xarici" iterasiya gedərkən, daxili dövr tam öz yolunu keçir (və bunu hər dəfə xarici üçün təkrar edir).
Yaxşı nümunə — saatlar və dəqiqələr. Saatlar — 0-dan 23-ə qədər xarici dövr, dəqiqələr isə 0-dan 59-a qədər daxili dövrdür. Xarici dövrün hər dəyişməsində daxili dövr bütün dəyərlərini keçir.
2. Daxili dövrlərin sintaksisi
C#-da daxili dövrlərin sintaksisi adi dövrlərdən heç nə ilə fərqlənmir — sadəcə bir dövrü başqasının gövdəsində yazırsan. Gəlin for və while ilə nümunələrə baxaq:
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
Console.Write($"{i},{j} ");
}
Console.WriteLine();
}
Burada xarici dövr i dəyişənini idarə edir (0-dan 2-yə qədər), daxili isə j dəyişənini (0-dan 3-ə qədər). Hər bir i üçün daxili dövr tam şəkildə j=0-dan j=3-ə qədər keçir. Bu kodu işə salsan, ekranda gözəl koordinat cədvəli görəcəksən:
0,0 0,1 0,2 0,3
1,0 1,1 1,2 1,3
2,0 2,1 2,2 2,3
Oxşar nümunə while ilə:
int i = 0;
while (i < 3)
{
int j = 0;
while (j < 4)
{
Console.Write($"{i},{j} ");
j++;
}
Console.WriteLine();
i++;
}
Diqqət yetir: xarici dövrün hər keçidində daxili dövrün dəyişəni (j) yenidən başlanmalıdır, yoxsa yalnız bir sətr görəcəksən!
3. Daxili dövrlərin işləmə nümunələri
Nümunə 1: şahmat taxtasının çıxarılması (8x8)
Gəlin ilk tapşırığımız — ekrana klassik şahmat taxtasını qara və ağ xanalar şəklində çıxaraq (tutaq ki, # — qara, _ — ağ). Bunu daxili for dövrləri ilə edək:
for (int row = 0; row < 8; row++)
{
for (int col = 0; col < 8; col++)
{
if ((row + col) % 2 == 0)
Console.Write("_");
else
Console.Write("#");
}
Console.WriteLine();
}
Nəticə:
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
Vacib məqam: daxili dövr təmin edir ki, hər bir sətr üçün (row) bütün sütunlar üzrə keçirik (col). Daxili dövr olmasa, taxta strukturu alınmazdı — yalnız bir sətr və ya bir sütun olardı.
Nümunə 2: vurma cədvəli
Daxili dövrlər üçün klassik nümunə! Gəlin 1-9 arası vurma cədvəlini çıxaraq:
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= 9; j++)
{
Console.Write($"{i * j,3} ");
}
Console.WriteLine();
}
${i * j,3} formatlaşdırması cədvəlin səliqəli görünməsi üçün boşluq əlavə edir.
Nəticə:
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
...
9 18 27 36 45 54 63 72 81
4. Daxili dövrlər və onların idarə olunması — incəliklər
break və continue daxili dövrlərdə necə işləyir
Bax, burada bir çox yeni başlayanlar səhvə yol verir! Əgər break və ya continue daxili dövrdə istifadə etsən, onlar yalnız həmin dövrə təsir edir. Xarici dövr isə öz işinə davam edir.
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
if (j == 3)
break; // yalnız daxili dövrdən çıxırıq!
Console.Write($"{i},{j} ");
}
Console.WriteLine();
}
Nəticə:
0,0 0,1 0,2
1,0 1,1 1,2
2,0 2,1 2,2
Əgər sənə iki daxili dövrdən birdən çıxmaq lazımdırsa (məsələn, cədvəldə ilk uğurlu uyğunluq tapılan kimi axtarışı dayandırmaq), adətən flag və ya xüsusi üsul (məsələn, return — əgər hər şey funksiya daxilindədirsə) istifadə olunur.
5. Daxili dövrlərin vizuallaşdırılması
Bəzən daxili dövrlərin icra ardıcıllığını "görmək" çətin olur. Gəlin aşağıdakı blok-sxemə baxaq:
Cədvəl şəklində — i 1-dən 3-ə, j isə 1-dən 4-ə qədər olduqda neçə iterasiya olacaq?
| i | j (hər i üçün dəyişir) | Daxili dövrün iterasiyaları |
|---|---|---|
| 1 | 1, 2, 3, 4 | 4 |
| 2 | 1, 2, 3, 4 | 4 |
| 3 | 1, 2, 3, 4 | 4 |
| Cəmi: 3 × 4 = 12 |
6. Daxili dövrlərlə işləyərkən səhvlər və tələlər
Yayılmış səhv — daxili dövrün dəyişənini səhv başlatmaq. Məsələn, onu xarici dövrün kənarında elan etmək, amma hər addımda sıfırlamamaq. Nəticədə daxili dövr ümumiyyətlə işləməyə bilər və ya səhv işləyər.
int j = 0;
for (int i = 0; i < 3; i++)
{
while (j < 4) // Ay aman! j artıq ilk iterasiyadan sonra 4 ola bilər.
{
Console.Write($"{i},{j} ");
j++;
}
Console.WriteLine();
}
Burada dövr yalnız bir dəfə işləyəcək. Daxili dövrün dəyişənlərini xarici dövrün içində başlatmağı unutma!
Həmçinin, təsadüfən iki daxili dövrü eyni dəyişən adı ilə yazsan, kompilyator səni danlayacaq: dəyişən artıq təyin olunub.
for (int i = 0; i < 3; i++)
{
for (int i = 0; i < 3; i++)
{
Console.Write($"{i},{i} ");
}
Console.WriteLine();
}
GO TO FULL VERSION