眾人初觸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為普通變量&a為a之地址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/fputcfgets/fputs
自理悟上說,文件操作與前述輸入輸出水準一致:
惟輸入輸出之對象,由鍵盤與屏幕,變為磁盤上之文件。
十二、一幅完整之圖
以上內容乃一條逐層展開之路徑:
- 自變量始,學存數據
- 以輸入輸出與程序建交際
- 以運算符理數據
- 以分支與循環控流程
- 以函數拆任務
- 以數組理一批數據
- 以指針理解地址與內存
- 復擴展至結構體、字符串、文件此等更真之應用場景
若視C語言基礎為蓋房,則變量、輸入輸出、分支、循環、函數、數組、指針,即為一層一層往上搭建之結構。
單視之,各知點皆不謂特複雜。然惟將其融會貫通,汝方真由「會寫幾個示例」,進至「始曉編程」。
此亦為何眾人覺C語言難,然真學入之後,又覺其特為基礎。
因其非在教汝「如何拼湊代碼」,而在教汝:
計算機程序究竟是如何工作。