眾人初觸C語言,多覺其略顯「剛硬」。

無甚現成封裝,少見語法甘飴,諸事多須親力親為,逐步書就。

然正因如此,C語言尤宜築基。

其鞭策汝思之:變數究為何物,輸入何以需傳址,數組何以與循環相合,函數如何傳參,指針又何以終不可避。

若此等根基確實悟透,爾後無論續研C++、Java、Python,抑或觸及操作系統、嵌入式、數據結構,理解皆益加堅實。

本文即循初學者最易建立認知之序,串聯C語言核心根基,助汝搭起完整學識框架。


一、學C語言,先握三條主脈

初學C語言時,最易之過,乃是將其視作「記誦單詞」。

今日記一if,明日記一for,後日復記scanf、數組、指針。

看似所學甚多,實則腦中一片散沙。

更佳之法,乃先握三條主脈:

其一,數據如何存儲

變量、數組、結構體、字符串,究其本質,皆在解「信息置於何處」。

其二,程序如何控製流程

順序執行、條件分支、循環往復,皆在答「事如何循序漸進」。

其三,程序如何覓得數據

此脈貫穿scanf、函數傳參、數組、指針,乃至文件操作。

但循此三脈而學,眾多看似零散之知,皆自然貫通。


二、變量:程序何以能「記」數據

程序欲理數據,首須能存數據。

而變量,即程序中最基礎之「儲存單元」。

譬如:

int age = 18;

此句代碼意謂:定義一名曰age之整型變量,並將值18存入。

此處有二基礎概念,須先釐清:標識符數據類型

1. 標識符:為數據命名

變量名、函數名、數組名,統稱標識符。

標識符非隨意書就,須合基本規則:

  • 由字母、數字、下劃線構成
  • 不得以數字開頭
  • 不得與關鍵字同名
  • 區分大小寫

譬如:

int score;
int _num;
int age1;

此等寫法皆無誤。

然如下之例即不合法:

int 2a;
int if;

故,習定義變量之首步,實乃學為數據取一合法且明晰之名。

2. 數據類型:定變量能容何物

C語言非「隨取一變量即能容萬物」,各變量皆須先聲明類型。

常見基礎類型有:

int a = 10;       // 整数
float b = 3.14;   // 浮点数
char c = 'A';     // 字符

此意味變量非徒具名,尚有「此匣允容何物」之限。

初學之際務必立此意識,蓋其將影響爾後一切輸入、輸出、運算及內存理解。


三、輸入輸出:程序如何與人交際

程序非僅內部潛算,亦須與人交際。

最常見之交際方式,即為輸入與輸出。

1. 輸出:將結果顯現

C語言中最常見之輸出函數為printf

譬如:

printf("Hello C!\n");

若欲輸出變量,則需用格式控製符:

int age = 18;
printf("%d\n", age);

此處%d表示「按整數格式輸出」。

常見格式說明符有:

  • %d:整數
  • %f:浮點數
  • %c:字符
  • %s:字符串

譬如:

float price = 19.9;
char ch = 'A';

printf("%f\n", price);
printf("%c\n", ch);

printf之要,非在強記符號,而在領悟:

程序輸出數據時,須知按何種類型以釋之。

2. 輸入:為何scanf常帶&

若言printf為「將內容展示而出」,則scanf即為「將用戶輸入讀進」。

譬如:

int age;
scanf("%d", &age);

此行代碼意謂:自鍵盤讀取一整數,並存至變量age中。

或人有疑,何以此處書&age,而非age

其故甚簡:

scanf非欲讀取age當下之值,而是欲將用戶所輸內容「寫入age所在之位」。

故其所須非值,乃地址也。

亦即:

  • age表變量中之值
  • &age表變量在內存中之地址

&,實已引汝入C語言最核心之底層思維:

程序非僅處理值,亦處理值所在之位。


四、運算符與表達式:程序究竟如何「算」

變量已備,輸入輸出已全,繼之程序便要始理數據。

而處理數據,離不開運算符與表達式。

1. 算術運算符

最基本之算術運算符有:

+  -  *  /  %

譬如:

int a = 10;
int b = 3;

printf("%d\n", a + b);
printf("%d\n", a % b);

其間最值新手留意者為/%

整數除法

若兩邊皆為整數:

15 / 4

結果為3,而非3.75

因整數除法僅保留整數部分。

浮點除法

但有一邊為浮點數:

15 / 4.0

結果方成3.75

取模運算

15 % 4

結果為3,表餘數。

%僅能用於整數,然極其實用。

判斷奇偶、拆分數字、處理周期規律時,常需用之。

2. 復合賦值

除:

a = a + 3;

亦可書作:

a += 3;

類似者尚有:

a -= 3;
a *= 3;
a /= 3;
a %= 3;

此等寫法於循環及數組處理中尤為常見。

3. 邏輯運算

邏輯運算符用於組合多個條件:

  • !:非
  • &&:與
  • ||:或

譬如:

if (age >= 18 && age <= 60)
{
    printf("符合条件\n");
}

故程序非僅能判一個條件,其尚可合多個條件,共作決策。


五、分支:使程序學「作抉擇」

現實問題中,諸事非皆順序而行,而常為「若合某條件,則行A;否則行B」。

此即分支結構之效用。

1. if:最基礎之條件判斷

譬如:

if (x > 0)
{
    printf("x是一个正数");
}
else
{
    printf("x不是一个正数");
}

此類代碼幾為自然語言之直譯:

  • 若條件成立,則執行前一段代碼塊
  • 否則,則執行後一段代碼塊

2. 多分支判斷

若情狀更多,可用else if繼續擴展:

if (score >= 90)
    printf("A");
else if (score >= 80)
    printf("B");
else if (score >= 70)
    printf("C");
else if (score >= 60)
    printf("D");
else
    printf("E");

此結構特宜處理「分段規則」,如成績分級、費用計算、年齡劃分等。

3. switch:處理固定值更顯清朗

若判斷條件為「某變量等於何固定值」,switch會更整飭:

switch (grade)
{
case 'A':
    printf("优秀");
    break;
case 'B':
    printf("良好");
    break;
default:
    printf("其他");
}

此處至關緊要者為break

若忘書之,程序將繼續下行執行,現「貫穿」之效。


六、循環:使程序學重復行事

若分支為「作選擇」,則循環即為「重復為」。

計算機最擅之事之一,即是將同一套規則精準執行數遍。

而循環,正是此能力之體現。

1. while:條件成立則持續執行

int i = 1;
while (i <= 5)
{
    printf("%d\n", i);
    i++;
}

此段代碼將輸出1至5。

while之特點為:先判斷,再執行。

故若條件啟始即假,循環可能一次皆不執行。

2. do...while:至少先執行一回

int i = 1;
do
{
    printf("%d\n", i);
    i++;
} while (i <= 5);

while不同,do...while為先執行一次,復判斷條件。

3. for:最常用之計數循環

for (int i = 1; i <= 5; i++)
{
    printf("%d\n", i);
}

for將初始化、條件判斷及更新書於一行,結構更緊湊,故於實際編程中極其常見。

4. 循環之真正價值

初學時最常見之循環任務包括:

  • 求和
  • 統計個數
  • 覓最大值與最小值
  • 遍歷數組
  • 輸出某範圍內滿足條件之數

故循環非單純之語法模板,而為一種至關重要之編程思維:

將問題拆解為「重復執行同一套步驟」之過程。


七、函數:將一段功能單獨封裝

當程序日益加長,所有代碼皆書於main之內便顯繁雜。

此時便需函數。

函數可解為:

一段專用於完成某任務之代碼塊,且可被重復調用。

譬如:

int add(int a, int b)
{
    int c = a + b;
    return c;
}

調用時書為:

int sum = add(10, 20);
printf("%d", sum);

1. 函數何以重要

函數最核心之價值有二:

  • 將複雜程序拆開,使結構更清晰
  • 將重復邏輯封裝,免卻反復書寫同樣代碼

2. 參數與返回值

函數中之參數,是將數據傳入。

返回值,是將結果帶出。

此二概念看似簡易,然其幾定函數全部意義。

3. 值傳遞與地址傳遞

此乃學函數時至為關鍵一步。

普通參數傳遞,本質上是將值復製一份予函數。

函數內部縱使修改參數,亦未必影響外部變量。

若傳入者為地址,情狀則異。

函數可藉此地址,直接操作外部變量所在之那塊內存。

此亦為何函數、scanf與指針之間,有極強之關聯。

4. 數組作為函數參數

數組傳參尤值留意。

因數組作為參數傳入函數時,本質上傳入者為首元素地址。

此意味函數內部對數組元素之修改,常直接影響原數組。

此事於理解「地址傳遞」至為重要。


八、數組:當一變量不敷用時

若程序僅理一數,一變量已足。

然若欲理10個成績、5個坐標、一班之分數列表,單一變量顯然不足。

此時便要用數組。

1. 一維數組:一組同類型之數據

int arr[5] = {1, 2, 3, 4, 5};

此表定義一包含5個整數之數組。

數組之本質,可解為:

將一組同類型之數據,依序置於一處。

2. 下標自0始

數組至關緊要之規則之一,即為下標自0始。

arr[0]   // 第一个元素
arr[1]   // 第二个元素

此微末小節,乃初學者最易犯錯之處之一。

3. 數組與循環乃天然搭檔

數組之常見操作,幾皆須與循環搭配使用:

for (int i = 0; i < 5; i++)
{
    printf("%d\n", arr[i]);
}

遍歷、求和、查找、統計,基本皆不離此組合。

4. 二維數組:數組之數組

譬如:

int arr[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
};

二維數組極宜表示表格、矩陣、成績單此類二維數據。


九、指針:理解C語言最關鍵一步

眾人一聞指針便緊張。

其確為C語言中較為抽象之部,然亦是最能體現此語言底層特性之處。

1. 指針為何

一句話先牢記:

指針乃存放地址之變量。

譬如:

int a = 10;
int *p = &a;

此處:

  • a為普通變量
  • &aa之地址
  • p為指針變量
  • p中存者為a之地址

2. p表何意

p存者為a之地址,則:

*p

表藉由此地址,取出對應位置上之值。

譬如:

printf("%d\n", *p);

輸出者即為10

3. 一級指針與二級指針

若一指針變量本身亦有地址,則可繼續定義「指向指針之指針」:

int a = 10;
int *p = &a;
int **pp = &p;

雖看似繞口,然本質上僅是「地址亦可繼續被保存」。

4. 指針與數組關係甚深

譬如:

int arr[5] = {10, 20, 30, 40, 50};

訪問第三個元素時:

arr[2]
*(arr + 2)

於眾多場景中等價。

此說明數組名與地址之間存有極緊密之聯繫,而此正是理解數組、函數傳參及指針運算之關鍵。


十、結構體、字符串與預處理

當前之基礎皆已穩固,C語言便會漸由「練語法」過渡至「表達真實對象」。

1. 結構體:合多個屬性於一體

譬如:

struct Person
{
    char name[10];
    int age;
    float height;
};

此意謂一「人」可同時具有姓名、年齡、身高等多個屬性。

訪問結構體成員時,常用寫法為:

person.age

若為結構體指針,則須書作:

p->age

結構體之重大意義在於,其使程序非僅處理單個值,而是始處理「一個對象」。

2. 字符串

在C語言中,字符串其實非獨立數據類型,而是字符數組。

譬如:

char str[] = "hello";

其本質乃若干字符連續存放,並以\0為結束標記。

領悟此點,於後學字符串長度、字符數組空間、字符串處理函數,皆至為重要。

3. #define:編譯前替換

譬如:

#define PI 3.14

此非變量,而是預處理階段進行之文本替換。

入門階段知此一點即足:

其核心非「存數據」,而是「於編譯前先替換代碼內容」。


十一、文件:使程序與外部數據交際

學至此,程序便非僅與鍵盤、屏幕交際。

其尚可讀取與寫入文件。

1. 文件操作之基本入口

在C語言中,文件常藉由文件指針操作。

譬如:

FILE *fp = fopen("output.txt", "w");

此表以寫入方式開啟一文件。

2. 常見開啟方式

常見模式有:

  • "r":只讀
  • "w":只寫
  • "a":追加
  • "rb" / "wb":二進制方式讀寫
  • +:讀寫結合

開啟方式決定了程序能對文件做何事。

3. 常見文件讀寫函數

譬如:

  • fgetc / fputc
  • fgets / fputs

自理悟上說,文件操作與前述輸入輸出水準一致:

惟輸入輸出之對象,由鍵盤與屏幕,變為磁盤上之文件。


十二、一幅完整之圖

以上內容乃一條逐層展開之路徑:

  • 自變量始,學存數據
  • 以輸入輸出與程序建交際
  • 以運算符理數據
  • 以分支與循環控流程
  • 以函數拆任務
  • 以數組理一批數據
  • 以指針理解地址與內存
  • 復擴展至結構體、字符串、文件此等更真之應用場景

若視C語言基礎為蓋房,則變量、輸入輸出、分支、循環、函數、數組、指針,即為一層一層往上搭建之結構。

單視之,各知點皆不謂特複雜。然惟將其融會貫通,汝方真由「會寫幾個示例」,進至「始曉編程」。

此亦為何眾人覺C語言難,然真學入之後,又覺其特為基礎。

因其非在教汝「如何拼湊代碼」,而在教汝:

計算機程序究竟是如何工作。