2016年5月25日 星期三

給新手的C++教學 (上冊) - 11. 結構 (Structure)

回到「給新手的C++教學 (上冊)」

上一章

第九章,我們學到了函式
函式真的好好用耶!

咦?真的嗎?
現在,給你三個直線方程式
請你輸出這三條直線相交所形成的三角形的三個頂點座標 (也就是直線的三個交點的座標)

輸入格式:有三行,第$i$行包含第$i$條直線的資訊:三個數字$a_i$、$b_i$、$c_i$,代表第$i$條直線的方程式$a_i x+b_i y=c_i$ (保證三條直線可以形成一個三角形)
輸出格式:有三行,第$i$行包含第$i$個頂點 (交點) 的座標資訊:兩個數字$x_i$、$y_i$,代表第$i$個頂點座標$(x_i,y_i)$ (請輸出小數,頂點順序隨意)

提示:兩條直線$a_{1}x+b_{1}y=c_{1}$、$a_{2}x+b_{2}y=c_{2}$的交點求法:

$\begin{cases}
    &a_{1}x+b_{1}y=c_{1}\\
    &a_{2}x+b_{2}y=c_{2}
\end{cases}\cdots\cdots ①$

$①\Rightarrow
\begin{cases}
    &a_{1}a_{2}x+b_{1}a_{2}y=c_{1}a_{2}\cdots\cdots ②\\
    &a_{1}a_{2}x+a_{1}b_{2}y=a_{1}c_{2}\cdots\cdots ③
\end{cases}$

$②-③\Rightarrow (b_{1}a_{2}-a_{1}b_{2})y=c_{1}a_{2}-a_{1}c_{2}$

$\Rightarrow y=\frac{c_{1}a_{2}-a_{1}c_{2}}{b_{1}a_{2}-a_{1}b_{2}}$

$①\Rightarrow
\begin{cases}
    &a_{1}b_{2}x+b_{1}b_{2}y=c_{1}b_{2}\cdots\cdots ④\\
    &b_{1}a_{2}x+b_{1}b_{2}y=b_{1}c_{2}\cdots\cdots ⑤
\end{cases}$

$④-⑤\Rightarrow (a_{1}b_{2}-b_{1}a_{2})x=c_{1}b_{2}-b_{1}c_{2}$

$\Rightarrow x=\frac{c_{1}b_{2}-b_{1}c_{2}}{a_{1}b_{2}-b_{1}a_{2}}$

p.s. 以上推導過程看不懂也沒關係

$\therefore$兩線交點為$(\frac{c_{1}b_{2}-b_{1}c_{2}}{a_{1}b_{2}-b_{1}a_{2}},\frac{c_{1}a_{2}-a_{1}c_{2}}{b_{1}a_{2}-a_{1}b_{2}})$

啊不就三條直線兩兩求交點就好?
懶得寫三遍同樣的東西,就弄成一個函式吧~
引數 (甚麼是引數?) 就傳遞兩條線的資訊,然後函式就可以進行計算,最後回傳交點的座標......
等等,怎麼回傳「一個座標」?
float、int、char,都不對呀
我們需要一次回傳「兩個float」

2016年5月19日 星期四

給新手的C++教學 (上冊) - 10. 變數的作用範圍 (Scope)

回到「給新手的C++教學 (上冊)」

上一章

不知你在之前的章節中做練習時,電腦是否莫名其妙地說你寫錯呢?
舉個例子
還記得第6章的練習題嗎?
題目是這樣的:
「輸入一個整數n,然後輸入n個數字
最後把這n個數字的順序顛倒,然後輸出」
當你學完陣列之後,馬上就興高采烈地寫下了程式碼:

#include<cstdio>
int main()
{
    int n;
    scanf("%d",&n);
    int a[n];
    int i=0;
    while(i<n)
    {
        scanf("%d",&a[i]);
        i=i+1;
    }
    int i=n-1;
    while(i>=0)
    {
        printf("%d ",a[i]);
        i=i-1;
    }
    printf("\n");
}

然後,電腦就說你寫錯了
然後,電腦就說你寫錯了XD
哦~原來我前面已經宣告了一個名字為「i」的變數了,不能再宣告一個名字一模一樣 (同樣是「i」) 的變數
p.s. 雖然之前的章節完全沒有提到,這個命名不能重複的規則請讀者務必了解,仔細想想應該就會發現這個規則合情合理,否則最後會分不清楚「i」到底是指哪一個變數

如果你還是搞不懂發生了甚麼事,將上面的程式碼和第6章提供的程式碼解答比對一下,看看有甚麼差別吧~

現階段,這種問題是很好解決的
以目前的知識,可以想到的方法有2種:

2016年5月17日 星期二

給新手的C++教學 (上冊) - 9. 函式 (Function)

回到「給新手的C++教學 (上冊)」

上一章

依照慣例,在本章依然要給你一個題目,然後你就會發覺需要學習某種新技能,才能有效率的寫出可以解決問題的程式碼 (?)

給你一個正整數$n$,請求出第$n$個卡特蘭數
提示:
第$n$個卡特蘭數$=C^{2n}_{n}-C^{2n}_{n+1}$
其中$C^{a}_{b}=\frac{a!}{b!(a-b)!}$
其中「$x!$」念作「$x$階層」,$x!=1*2*3*...*x=\prod_{k=1}^{x}k$

當然,$n$不能太大,否則會發生溢位 (overflow) 的情況 (甚麼是溢位?)
所以$n$的範圍會在$1\sim 6$內

卡特蘭數列:1、2、5、14、42、132、......

你的程式答對前6項了嗎?

參考程式碼:

#include<cstdio>
int main()
{
    int n;
    scanf("%d",&n);
    int a=1,b=1,c=1;
    int i=1;
    while(i<=2*n)
    {
        a=a*i;
        i=i+1;
    }
    i=1;
    while(i<=n)
    {
        b=b*i;
        i=i+1;
    }
    i=1;
    while(i<=2*n-n)
    {
        c=c*i;
        i=i+1;
    }
    int first=a/(b*c);
    a=1,b=1,c=1,i=1;
    while(i<=2*n)
    {
        a=a*i;
        i=i+1;
    }
    i=1;
    while(i<=n-1)
    {
        b=b*i;
        i=i+1;
    }
    i=1;
    while(i<=2*n-(n-1))
    {
        c=c*i;
        i=i+1;
    }
    int second=a/(b*c);
    printf("%d\n",first-second);
    return 0;
}

程式碼中,變數a、b、c分別表示$C^{a}_{b}$中的$a!$、$b!$、$(a-b)!$

當輸入$n=6$時,程式輸出第6個卡特蘭數「132」了!
你可能會覺得:程式碼好冗長呀~
然後心裡想說:等一下一定會教一個更簡單的方法
咦?XD

沒錯!
接下來,本章會教你,怎麼利用「函式 (Function)」來化簡你的程式碼!

2016年5月10日 星期二

給新手的C++教學 (上冊) - 8. 字元 & 字串 (Charactor & String)

回到「給新手的C++教學 (上冊)」

上一章

不知你是否嘗試過讓程式做到以下事情:
輸入一個名字 (大小寫字母組成),輸出「Hello, 名字!」

1. 土法煉鋼法

我們已經學過怎麼輸入一個字元 (甚麼是字元?),也知道怎麼用直接的方式 (用兩個「'」框起來) 表示一個字元
所以,我們可以一個一個的輸入字元,然後一一判斷是不是大小寫字母,當輸入的字元不是大小寫字母時,我們就知道一個「名字」已經輸入完了 (因為名字只能由大小寫字母組成)

套用上一章所學的簡化方式,我們就可以實現這個輸入名字的功能 (以下程式碼已經假設名字的長度$\leq$一百萬):

#include<cstdio>
int main()
{
    char name[1000001];
    int i=0;
    while(1==1)
    {
        scanf("%c",&name[i]);
        char c=name[i];
        if(c!='a'&&c!='b'&&c!='c'&&c!='d'&&c!='e'&&c!='f'&&c!='g'&&c!='h'&&c!='i'&&c!='j'&&c!='k'&&c!='l'&&c!='m'&&c!='n'&&c!='o'&&c!='p'&&c!='q'&&c!='r'&&c!='s'&&c!='t'&&c!='u'&&c!='v'&&c!='w'&&c!='x'&&c!='y'&&c!='z'&&c!='A'&&c!='B'&&c!='C'&&c!='D'&&c!='E'&&c!='F'&&c!='G'&&c!='H'&&c!='I'&&c!='J'&&c!='K'&&c!='L'&&c!='M'&&c!='N'&&c!='O'&&c!='P'&&c!='Q'&&c!='R'&&c!='S'&&c!='T'&&c!='U'&&c!='V'&&c!='W'&&c!='X'&&c!='Y'&&c!='Z')break;
        i=i+1;
    }
    printf("Hello, ");
    int j=0;
    while(j<i)
    {
        printf("%c",name[j]);
        j=j+1;
    }
    printf("!\n");
    return 0;
}

我才不信你會想這樣搞咧,對吧?
52個字母一一判斷實在是太累了,而且容易打錯

很幸運地,對電腦來說,「一個字元」其實就是「一個數字」
例如:「M」對應到「77」、「o」對應到「111」
如果你硬要把這些字元用整數的「%d」輸出 (而不是字元的「%c」),你看到的就是這些字元所對應到的數字
我用以下程式碼做示範:

#include<cstdio>
int main()
{
    printf("%d %d\n",'M','o');
}

沒意外的話,程式會輸出「77 111」

程式輸出「77 111」了!

因此,你甚至可以把每個直接表示的字元用數字來取代
把上面輸入一個名字的程式改寫成這樣:

#include<cstdio>
int main()
{
    char name[1000001];
    int i=0;
    while(1==1)
    {
        scanf("%c",&name[i]);
        char c=name[i];
        if(c!=97&&c!=98&&c!=99&&c!=100&&c!=101&&c!=102&&c!=103&&c!=104&&c!=105&&c!=106&&c!=107&&c!=108&&c!=109&&c!=110&&c!=111&&c!=112&&c!=113&&c!=114&&c!=115&&c!=116&&c!=117&&c!=118&&c!=119&&c!=120&&c!=121&&c!=122&&c!=65&&c!=66&&c!=67&&c!=68&&c!=69&&c!=70&&c!=71&&c!=72&&c!=73&&c!=74&&c!=75&&c!=76&&c!=77&&c!=78&&c!=79&&c!=80&&c!=81&&c!=82&&c!=83&&c!=84&&c!=85&&c!=86&&c!=87&&c!=88&&c!=89&&c!=90)break;
        i=i+1;
    }
    printf("Hello, ");
    int j=0;
    while(j<i)
    {
        printf("%c",name[j]);
        j=j+1;
    }
    printf("!\n");
    return 0;
}

測試看看,程式依然是同樣的邏輯!

輸入「Mobius」,程式依然是輸出「Hello, Mobius!」
(順帶一提,「Mobius」是我們「105級高雄中學科學班成果發表會的名稱,歡迎大家前去看看~~~)

2016年5月8日 星期日

給新手的C++教學 (上冊) - 7. 讓程式碼看起來更簡單 (Simplify the code)

回到「給新手的C++教學 (上冊)」

上一章

上一章有提到,利用前6章所學,已經可以完全掌控電腦了

現在,我想問你,能否寫出一個程式,完成以下任務呢?
輸入一個字元,請判斷這個字元是不是「小寫母音字母 (a、e、i、o、u)」,是的話輸出「Yes」,否則輸出「No」(甚麼是字元?複習一下第2章吧~)

題外話:
怎麼表示「一個字元 (charactor),代表小寫字母『a』」呢?
不知道沒關係,因為之前的章節沒有提到XD
答案是「'a'」(用兩個「'」框住你想表達的字元)
這個表示法雖然是隨手提及,但是非常重要,之後的教學只要看到兩個「'」框起來的東西,你都要把它當作「一個字元」來看待

參考解答:

#include<cstdio>
int main()
{
    char a;
    scanf("%c",&a);
    if(a=='a')
    {
        printf("Yes\n");
    }
    else
    {
        if(a=='e')
        {
            printf("Yes\n");
        }
        else
        {
            if(a=='i')
            {
                printf("Yes\n");
            }
            else
            {
                if(a=='o')
                {
                    printf("Yes\n");
                }
                else
                {
                    if(a=='u')
                    {
                        printf("Yes\n");
                    }
                    else
                    {
                        printf("No\n");
                    }
                }
            }
        }
    }
    return 0;
}

你可能會發現:程式好冗長啊
有沒有簡單一點的寫法呢?
會這樣問,答案當然是「有」啊

可以發現,有很多的大括號 (「{」和「}」) 包起來的部分都只有一行程式碼 (「printf("Yes\n");」或「printf("No\n");」)
在這種情況下,大括號其實是可以省略的

所以,程式碼也可以這樣寫,完全不影響程式的功能:

#include<cstdio>
int main()
{
    char a;
    scanf("%c",&a);
    if(a=='a')
        printf("Yes\n");
    else
    {
        if(a=='e')
            printf("Yes\n");
        else
        {
            if(a=='i')
                printf("Yes\n");
            else
            {
                if(a=='o')
                    printf("Yes\n");
                else
                {
                    if(a=='u')
                        printf("Yes\n");
                    else
                        printf("No\n");
                }
            }
        }
    }
    return 0;
}

另外,一個「if」和一個「else」是配對起來的,不可分離
因此,我們甚至也可以省略將它們包起來的大括號!
廣泛的說,如果大括號裡面包起來的程式碼是不可分離的
那麼這個大括號就可以省略

這樣一來,程式碼又可以簡化成以下這樣了:

2016年5月4日 星期三

給新手的C++教學 (上冊) - 6. 陣列 (Array)

回到「給新手的C++教學 (上冊)」

上一章

不知你有沒有想要實現過以下這件事,卻遇到阻礙呢?
輸入一個整數n,然後輸入n個數字
最後把這n個數字的順序顛倒,然後輸出

例如:輸入「4 24 5 105 411」,輸出為「411 105 5 24 」(注意:每個數字後面都有空格,最後一個數字也一樣)

你可能有想過要做類似以下的事情:
如果n是1就宣告 a,輸入 a,輸出 a (「宣告」是「定義變數」的專業說法)
如果n是2就宣告 a、b,輸入 a、b,輸出 b、a
如果n是3就宣告 a、b、c,輸入 a、b、c,輸出 c、b、a
如果n是4就宣告 a、b、c、d,輸入 a、b、c、d,輸出 d、c、b、a
......
然後你就會發現沒完沒了XD

事實上,我們可以直接指定一個整數n,讓電腦一次幫我們宣告n個變數!(並非任何情況都可行,見註7)
這就是「陣列 (Array)」的好用之處

用法如下 (假設你想宣告n個int變數、陣列的名稱取作「array_name」):
int array_name[n];

這樣一來電腦就幫你把n個變數命名為array_name[0]、array_name[1]、array_name[2]、......、array_name[n-1]了!
(心理偷偷的想:耶~小中大括號都用到了耶 \(^o^)/ )

請注意,第1個變數是array_name[0] (而不是array_name[1]),第n個變數是array_name[n-1] (而不是array_name[n])
不知你在第一次看到本教學時,有沒有注意到有一章叫做「0. 目錄 (Catagories)
這就是暗示了
中括號 (「[」和「]」) 裡面的數字,我們叫做「索引值 (Index)」
有別於數學上常見的正整數系統
陣列的「索引值」是從「0」開始的
也就是說:
索引值為0時代表第1個變數
索引值為1時代表第2個變數
索引值為2時代表第3個變數
索引值為3時代表第4個變數
索引值為4時代表第5個變數
......
以此類推
至於原因,之後的進階章節會講到 (建議你不要現在就直接看它),目前你只要記住有這個現象即可

因此
「輸入一個整數n,然後輸入n個數字
最後把這n個數字的順序顛倒,然後輸出」
這個問題就迎刃而解了:

#include<cstdio>
int main()
{
    int n;
    scanf("%d",&n);
    int a[n];
    int i=0;
    while(i<n)
    {
        scanf("%d",&a[i]);
        i=i+1;
    }
    i=n-1;
    while(i>=0)
    {
        printf("%d ",a[i]);
        i=i-1;
    }
    printf("\n");
}
 

←「i」要從0開始跑,因此先把i設定成0
←「i」會從0跑到n-1

    (這樣會讓程式照順序輸入a[0]~a[n-1])


←「i」要從n-1開始跑,因此先把i設定成n-1
←「i」會從n-1往回跑到0

    (這樣會讓程式倒序輸出a[n-1]~a[0])

那個「printf("\n");」可加可不加,因為題目沒有強制要求輸出格式
但這不代表「加」和「不加」的效果相同,建議讀者測試看看兩種情況的差異

好了,陣列講完了(?)

2016年5月3日 星期二

給新手的C++教學 (上冊) - 5. 迴圈 (Loop)

回到「給新手的C++教學 (上冊)」

上一章

有時候,你希望某部分的程式碼重複執行3次
利用前四章所學,你可能會選擇把程式碼複製成3倍

但是,如果你希望這部分的程式碼執行500次呢?
如果你可以很有有耐心的進行「複製、貼上」的動作,這可能還不成問題
如果你希望這部分的程式碼是永遠的重複執行下去,直到我們手動把程式關掉呢?
亦或者你可以做到「輸入一個數字,這個數字是多少,程式就會重複執行多少次」嗎?

別擔心,以上的問題可以用一個很輕鬆的方法一次搞定!
換句話說,我們又有新朋友要認識啦~

它就是「while (當......的時候)」
用法如下:

while(繼續重複執行的條件)
{
    需要被重複執行的程式碼
}

因此,就算你不是高斯,你也可以輕鬆地寫出一個程式來計算「1+2+3+......+100」的結果!

#include<cstdio>
int main()
{
    int answer=0;
    int a=1;
    while(a<=100)
    {
        answer=answer+a;
        a=a+1;
    }
    printf("%d\n",answer);
    return 0;
}

程式輸出「5050」了!
你可能會對「=」的用途感到陌生 (雖然說之前有用過「int a=1;」之類的東西)
千萬別和「==」搞混了
「=」的作用是把左邊變數的值「設定成」右邊的數字
「==」是「判斷」左邊的數字和右邊的數字有沒有相等
雖然奇怪,但是習慣了就好,以後會很常用到的 ^_^

這種會被重複執行的程式碼,我們稱作「迴圈 (loop)」
還有另一種迴圈叫做「for」,雖然說「while」迴圈已經可以實現「for」迴圈的所有功能
但是「for」迴圈的獨特寫法,讓我們能夠更容易了解這個迴圈執行的事情
之後的進階章節將介紹這種神奇迴圈的用法 (但還是建議先照著順序讀完本教學)

當while中「繼續重複執行的條件」永遠成立時,程式就會永遠的重複執行下去直到天荒地老
這種情況我們稱之為「無窮迴圈 (infinite loop)」
當然,這不會太常用到,畢竟我們通常會希望程式會自己判斷甚麼時候要自己結束,而不是依賴使用者自己去按右上角的「X」按鈕來關閉程式
當你學會了怎麼製作「表單 (Form)」後,你可能會發現,當你的程式進入「無窮迴圈」時,有時候會導致程式「停止回應」(雖然說導致程式「停止回應」的原因不一定是如此)
因為這時程式已經不會再理會使用者的操作,而是專注於重複執行某一段程式碼
使用「多線程 (multithreading)」技術可以避免程式因此停止回應,但這已經遠遠超出本教學的範圍
「表單就是外觀有設計過的程式,而不是單純的「輸入和輸出文字」
相對於「表單」,這種看起來只有黑色背景、上面只會顯示文字的程式,我們稱作「終端機 (Terminal)」
這種程式比較容易製作,也就是我們現在使用C++寫的程式
當然,用C++也可以寫出「表單」

以下程式碼可以讓你體驗一下「無窮迴圈」:

2016年5月1日 星期日

給新手的C++教學 (上冊) - 4. 條件判斷 (Decision making)

回到「給新手的C++教學 (上冊)」

上一章

利用前三章提到的知識,我們已經可以寫出自己的計算機了!
但是,其實我們的程式還可以變得更強!
在本章,我們將賦予程式「判斷、決策」的能力,讓程式也可以像人一樣思考!

先來講個簡單的例子:
輸入一個數字,如果這個數字是2的話輸出「Yes」,不是的話輸出「No」

這裡請出我們的新朋友,「if (如果)」
用法如下:

if(條件)
{
    條件成立時要執行的程式碼
}

所以,程式碼可以這樣寫:

#include<cstdio>
int main()
{
    int n;
    scanf("%d",&n);
    if(n==2)
    {
        printf("Yes\n");
    }
    if(n!=2)
    {
        printf("No\n");
    }
}

趕快試試看吧! :)

你可能會發現另外兩個新朋友:「==」和「!=」
其中
「==」的作用是判斷左邊是不是「等於」右邊
「!=」的作用是判斷左邊是不是「不等於」右邊
類似的用法還有:
「<」的作用是判斷左邊是不是「小於」右邊
「>」的作用是判斷左邊是不是「大於」右邊
「<=」的作用是判斷左邊是不是「小於或等於」右邊
「>=」的作用是判斷左邊是不是「大於或等於」右邊

你可能還會發現:『「==」成立』不就是『「!=」不成立』嗎?
只要其中一方成立,另一方就會不成立
反之亦然
只要其中一方不成立,另一方就會成立

給新手的C++教學 (上冊) - A. 補充資料 (Additional materials)

回到「給新手的C++教學 (上冊)」

上一章 (這要怎麼定義上一章啦喂)

本教學以「容易理解」為目標,因此對某些觀念進行了簡化
以下提供更正確、更詳細的資訊供讀者們參考
但還是建議新手們先看懂教學內文的解說
(我們學物理時也是先學錯誤但簡單的牛頓力學,沒有一開始就在教量子力學的對吧?)

(注意:註釋的編號並不代表在教學中出現的順序)

註1:(感謝pr3pony)
int 在標準中只規定至少要 2 bytes
雖然幾乎所有編譯器實作依據的標準都是 ILP32 或 LP64
也就是常見的 4 bytes

註2:(感謝pr3pony)
float 的底數其實是 2 不是 10
因此事實上在儲存 float 前,並沒有「轉成二進位」的這個操作
一切都是直接以「二進位」的模式處理
並沒有牽涉到任何「二進位和十進位互相轉換」的操作 (除非要輸出給我們看)
因此,「24005」應該會被轉換成「$(1.01110111000101)_2*2^{14}$」(二進位版的科學記號)
其中「$(1.01110111000101)_2=(1.46514892578125)_{10}=1.46514892578125=\frac{24005}{2^{14}}$」
詳細資料

註3:(感謝pr3pony)
其實 C++ 並無規定負數的實作方法
常見的方法有三種:two's complementone's-complementsign-magnitude
第三篇提到的方法屬於「two's complement」(感覺也是最常見的方法(?) )

註4
電腦學過C++,很聰明地解決了這個問題
電腦會在字串的後面補上一個特殊字元「'\0'」,這個特殊字元我們稱作「結束字元」,對應到的數字是「0」
這樣就可以知道這個字串的結尾在哪裡了
p.s. 「結束字元 ('\0')」也是一種「隱藏字元」
關於結束字元的中文資料(維基百科)
原文詳細資料

註5:(感謝李旺陽學長)
這個規則是C++被定義明確的標準規範
詳細資料

註6
事實上,以現代的觀點來看,「float」的誤差太大
因此一般計算我們會習慣使用增強版float--「double」
除非記憶體不足或使用到GPU運算,不然float很少會被用到
但是因float的輸出入單純許多,本教學以「float」作為新手們學習浮點數的進入管道

註7:(感謝uzk)
實際上,在C++的標準裡面
「int a[n];」裡面的「n」只能是常數 (而非變數)
這裡我們能夠使用一個變數來當作陣列的長度
是因為我們的編譯器是GCC
當使用的編譯器非GCC時 (雖然這種情況較少見),宣告陣列時不能使用變數當作長度

註8:(感謝李旺陽學長)
宣告的部分跟語法解析有關
有逗點的用的是這條
decl-specifier-seq init-declarator-list;
重點在 * (or & && etc) 是一個 Declarators 不是 Specifiers
 int * p ;
被解析為
Specifiers : int
Declarators : *p (Pointer declaration)
int * p , q;
被解析為
Specifiers : int
Declarators : *p (Pointer declaration) , q ((int var) Names declaration)
以哲學觀點

註9 (全範圍)
其實,C++在「#include<cstdio>」之後
一定會將「printf」放入「std」命名空間
卻不一定會將「printf」放入全域命名空間
(C則是完全相反)
因此,最好的寫法是把全部的「printf」改成「std::printf」
或者每次include完之後加上一行「using namespace std;」
資料來源

註10:(感謝李旺陽學長)
C++小數的捨去有更精確的定義是「Round towards zero (向0靠攏)」
超級超級超級詳細的資料 (第99頁 (頁碼85),Floating-integral conversions)

註11:(感謝奕均的留言)
「\」後面接甚麼會發生甚麼事
來解答囉~
「\a」聲音 (例如:printf("123\a456");)
「\b」退格鍵 (例如:printf("123\b456");)
「\e」ASCII碼是27 (16進位:1b),在黑色視窗會顯示一個向左的箭頭,我也不知道為甚麼XD
「\f」ASCII碼是12 (16進位:0c),在黑色視窗會顯示一個女生的符號,我也不知道為甚麼XD
「\n」你知道的
「\r」類似鍵盤上的「Home」鍵 (例如:printf("1234\r56");)
「\t」類似鍵盤上的「Tab」鍵 (例如:printf("123\t456");)
「\u」後面加4位數的16進位數字,會變成該Unicode碼對應到的字元 (例如:printf("\u001b");)
「\v」ASCII碼是11 (16進位:0b),在黑色視窗會顯示一個男生的符號,我也不知道為甚麼XD
「\x」後面加2位數的16進位數字,會變成該ASCII碼 (或Unicode碼) 對應到的字元 (例如:printf("\x1b");)
「\E」和「\e」的效果一樣
「\U」後面加8位數的16進位數字,會變成該Unicode碼對應到的字元 (例如:printf("\U0000001b");)
「\%」和「%」的效果一樣
「\(」和「(」的效果一樣
「\[」和「[」的效果一樣
「\{」和「{」的效果一樣
「\\」會輸出「\」 (例如:printf("123\\456");)
「\'」和「'」的效果一樣
「\"」會輸出「"」 (例如:printf("123\"456");)
「\?」和「?」的效果一樣

注意:
「\n」雖然說類似鍵盤上的「Enter」鍵,但其實在非常非常特殊的情況下,「\n」並不等於鍵盤上的「Enter」鍵,反而比較像「↓」方向鍵 (例如:printf("123\r78\n56");)

註12
這裡介紹的for迴圈功能僅限C++
C語言也有for迴圈,但功能受限,並不像C++的for迴圈這麼好用

註13
可能會有人覺得奇怪,「char」不是用來表示「一個字元」的嗎?為甚麼會被歸類在「整數」呢?
事實上,「char」的儲存和運作方式跟其他整數型別一模一樣
只是「char」的「數字範圍」很適合用來表示英文字母、數字和一些符號等等的字元而已,所以「char」就莫名其妙被用來「表示字元」了XD

註14
這樣的struct定義方式無法在 C (而不是C++) 使用
C的struct必須使用更迂迴的方式來定義:

typedef struct
{
    float a,b,c;
}Line;

這相當於C++這種定義struct的方式:

struct Line
{
    float a,b,c;
};



下一章 (這要怎麼定義下一章啦喂)

感謝:pr3pony、李旺陽學長、uzk、奕均的留言
(版權所有 All copyright reserved)