for迴圈巢狀,C語言for迴圈巢狀詳解

2020-07-16 10:04:22
前面我們講的是單個 for 迴圈的使用,最後再跟大家講一下多層 for 之間的巢狀使用。雖說是多層,事實上 for 迴圈巢狀的層數也不能太多。通常為兩個 for 迴圈的巢狀,超過兩個的極少使用。

與單個 for 迴圈相比,多個 for 迴圈的巢狀在邏輯上更複雜一點,但並不難懂。直接給大家寫一個程式:
# include <stdio.h>
int main(void)
{
    int i, j;
    for (i=0; i<4; ++i)
    {
        printf("問世間情是何物, 直教生死相許n");
        for (j=0; j<3; ++j)
        {
            printf("兩情若是久長時, 又豈在朝朝暮暮n");
        }
    }
    return 0;
}

輸出結果是:
問世間情是何物, 直教生死相許
兩情若是久長時, 又豈在朝朝暮暮
兩情若是久長時, 又豈在朝朝暮暮
兩情若是久長時, 又豈在朝朝暮暮
問世間情是何物, 直教生死相許
兩情若是久長時, 又豈在朝朝暮暮
兩情若是久長時, 又豈在朝朝暮暮
兩情若是久長時, 又豈在朝朝暮暮
問世間情是何物, 直教生死相許
兩情若是久長時, 又豈在朝朝暮暮
兩情若是久長時, 又豈在朝朝暮暮
兩情若是久長時, 又豈在朝朝暮暮
問世間情是何物, 直教生死相許
兩情若是久長時, 又豈在朝朝暮暮
兩情若是久長時, 又豈在朝朝暮暮
兩情若是久長時, 又豈在朝朝暮暮


其實,多層 for 迴圈巢狀的執行過程與單個 for 迴圈的執行過程是一模一樣的。多層 for 迴圈的巢狀只不過是將單個 for 迴圈大括號中的“語句”換成了 for 迴圈而已。

下面看看上面程式中兩個 for 迴圈巢狀是怎麼執行的。
1) 首先求解表示式 1,即給變數 i 賦初值,i=0;表示式 1 只執行這一次,下面都不會再執行了。

2) 然後求解表示式 2,即 0<4 成立,則執行 for 迴圈中的內嵌語句: 
printf("問世間情是何物, 直教生死相許n");
for (j=0; j<3; ++j)
{
    printf("兩情若是久長時, 又豈在朝朝暮暮n");
}
首先 “printf("問世間情是何物,直教生死相許n")”,然後執行內部 for 迴圈,對這個 for 迴圈再次應用“單個 for 迴圈”的執行過程:
  1. 首先求解表示式 1,即給變數 j 賦初值,j=0。
  2. 然後求解表示式 2,即 0<3 成立,則執行 for 迴圈中的內嵌語句,即 “printf("兩情若是久長時,又豈在朝朝暮暮n");”。
  3. 然後執行表示式 3,變數 j 自加 1,即變數 j 由 0 變為 1。
  4. 然後求解表示式 2,即 1<3 成立,則執行 for 迴圈中的內嵌語句,即“printf("兩情若是久長時,又豈在朝朝暮暮n");”。
  5. 然後執行表示式 3,變數 j 自加 1,即變數 j 由 1 變為 2。
  6. 然後求解表示式 2,即 2<3 成立,則執行 for 迴圈中的內嵌語句,即“printf("兩情若是久長時,又豈在朝朝暮暮n");”。
  7. 然後執行表示式 3,變數 j 自加 1,即變數 j 由 2 變為 3。
  8. 然後求解表示式 2,即 3<3 不成立,則內部的迴圈結束。對內部的 for 而言迴圈是結束了,但對外部的 for 而言,“for 迴圈的執行”過程才執行到表示式 3。
3) 然後執行表示式 3,變數 i 自加 1,即變數 i 由 0 變為 1。

4) 然後再求解表示式 2……
……

就這樣一直迴圈下去,直到外層迴圈結束,整個迴圈才結束。

總之,不管是單個 for 迴圈還是多個 for 迴圈的巢狀,它們的執行過程是一樣的。只不過如果是“多個 for 迴圈的巢狀”,則其執行過程也是巢狀的。

for迴圈巢狀程式設計練習

1) 求出 1!+2!+3!+…+n!的和。

對於這個程式前面用一個for程式設計也可以實現,但是邏輯性太強,現在再用for迴圈巢狀程式設計實現一下:
# include <stdio.h>
int main(void)
{
    int n = 0;  //儲存1!+2!+3!+…+n!中n的值
    int i = 0, j = 0;  //迴圈變數
    int m = 1;  //用於計算每個數的階乘
    unsigned long sum=0;  /*階乘的值往往很大, 定義成long型。雖然如此, 下面輸入的n的值也不能太大, 不然long也放不下*/
    printf("請輸入n的值:");
    scanf("%d", &n);
    for (i=1; i<=n; ++i)
    {
        for (j=1; j<=i; ++j)  //求一個數的階乘
        {
            m = m*j;
        }
        sum = sum + m;  //求完之後就立即把它加到sum中
        m = 1;
    }
    printf ("sum = %ldn", sum);
    return 0;
}
輸出結果是:
請輸入n的值:10
sum = 4037913

我們看到 n 的值僅為 10 結果就這麼大,要再大點 long 型別肯定是存放不了的。此外,有人可能會糾結這樣的問題,程式開頭定義那麼多變數,可是我寫的時候怎麼知道後面要用到哪些變數呢?其實,這些變數都不是剛開始寫程式的時候就定義的,大多數情況下都是“若剛開始知道定義哪些變數那麼就定義上,如果不知道那就不定義,等到後面需要用再回到前面進行定義”,這才是正常的邏輯。

2) 求出用 50元、20元 和 10元換算 100元有幾種方式?

思路:用窮舉法, 將所有可能的情況都列出來, 用 for 迴圈可以實現窮舉
分析:100 元單用 50 換算, 最多需要兩張;用 20 元換算, 最多需要五張;用 10 元換算最多需要十張
# include <stdio.h>
int main(void)
{
    int w, e, s;  //w代表wushi;e代表ershi;s代表shi
    for (w=0; w<=2; ++w)
    {
        for (e=0; e<=5; ++e)
        {
            for (s=0; s<=10; ++s)
            {
                if (100 == 50*w+20*e+10*s)
                {
                    printf("%d  %d  %dn", w, e, s);
                }
            }
        }
    }
    return 0;
}
輸出結果是:
0  0  10
0  1  8
0  2  6
0  3  4
0  4  2
0  5  0
1  0  5
1  1  3
1  2  1
2  0  0

3) “百錢買百雞”是中國古代一個著名的列舉法題目。所謂列舉就是將所有可能的情況全部列出來的意思。for 迴圈巢狀是實現列舉的一種手段,上面的換算也是一種列舉。假設公雞 5 元一隻,母雞 3 元一隻,小雞 1 元 3 只,現在給你 100 元,要你買回 100 隻雞,求出公雞、母雞、小雞分別為多少隻。 
# include <stdio.h>
int main(void)
{
    int x, y, z;  //x、y、z 分別表示公雞、母雞、小雞
    for (x=0; x<20; ++x)
    {
        for (y=0; y<33; ++y)
        {
            z = 100 - x - y;  //小雞也可以用迴圈,但是能用二層迴圈解決的就不要用三層。
            if ((0 == z%3) && (100 == 5*x + 3*y + z/3))  //將 0==z%3 放前面更好,因為 && 是“短路與”,前面不成立後面就不會執行了,所以把計算量小的放前面。
            {
                printf("x = %d, y = %d, z = %dn", x, y, z);
            }
        }
    }
    return 0;
}
輸出結果是:
x = 0, y = 25, z = 75
x = 4, y = 18, z = 78
x = 8, y = 11, z = 81
x = 12, y = 4, z = 84