典例題100例:從基礎語法到鏈表文件讀寫的刷題路線)
簡介這是一份C語言經(jīng)典例題100例的PDF文檔面向C語言初學者和備考復習者系統(tǒng)覆蓋基本數(shù)據(jù)類型、控制結構、函數(shù)、數(shù)組、指針、結構體、文件操作等核心知識點通過100道經(jīng)典實例幫助讀者鞏固語法、理解編程邏輯。每個實例均包含題目描述、程序分析和完整源代碼。例如程序1用三重循環(huán)解決數(shù)字排列問題程序2用多分支if處理利潤提成程序3用sqrt判斷完全平方數(shù)程序4用switch和閏年判斷計算某天是第幾天這些題目能有效訓練循環(huán)嵌套、條件分支、數(shù)學函數(shù)及邏輯思維。文檔共1個PDF文件壓縮包大小2.77MB內(nèi)容精煉便攜方便隨時查閱。目前已有1201人學習下載適合C語言小白自學、教師課堂參考及課后復習拓展。通過對照源代碼與詳細解釋讀者可以深入理解每一步計算過程舉一反三解決類似編程問題是入門C語言不可多得的練習合集。1. 為什么說“C語言經(jīng)典例題100例”是一份可以反復刷的路線圖手頭那份《C語言經(jīng)典例題100例.pdf》是不是已經(jīng)躺在下載目錄里吃灰很多人的學習路徑是看一遍C語言基礎知識的書跟著敲幾個例子然后就開始背代碼。結果到了面試或?qū)懬度胧巾椖繒r鏈表、指針、文件讀寫組合在一起就露怯。這套經(jīng)典題的價值不在于“100”這個數(shù)字而在于它把分散的語法點擰成了一個個必須動手解決的問題從輸入輸出、循環(huán)分支到數(shù)組與字符串函數(shù)再到結構體、鏈表和文件操作。哪怕現(xiàn)在Python很火但計算機第一門專業(yè)課仍然從C講起因為指針和內(nèi)存模型是后面所有系統(tǒng)級編程的地基。這份題適合兩類人一類是剛學完C語言基礎但不知道下一步做什么的入門者另一類是已經(jīng)工作數(shù)年、需要快速恢復對底層語感的后端或嵌入式工程師。我建議不要從頭到尾按順序刷而是先按知識塊把題目拆開再用編譯、調(diào)試工具把每道題跑通。后面的章節(jié)會給你一套可復現(xiàn)的操作路徑。2. 先把100例拆成6個知識塊再按塊補齊C語言基礎與指針2.1 用一張歸類表制定刷題順序避免淹沒在題海里打開PDF后先別急著看第一題。一般情況下這100例并不是按難度嚴格排隊的但題目之間有明顯的高頻考點。常見做法是把它們按考查對象分塊每一塊集中刷比按頁碼順序刷效率高很多。我習慣分成6塊知識塊覆蓋的典型題目方向刷完后的驗證標準基礎語法與輸入輸出整數(shù)求和、判斷閏年、溫度轉(zhuǎn)換能不看參考寫出 scanf/printf 格式控制流程控制與循環(huán)九九乘法表、素數(shù)判斷、水仙花數(shù)能寫出 while 和 do-while 等價的場景數(shù)組與字符串冒泡排序、字符串逆序、字符統(tǒng)計能說清數(shù)組名做參數(shù)時發(fā)生了什么函數(shù)與遞歸階乘、斐波那契、漢諾塔能手動描出遞歸棧的變化指針、結構體與鏈表指針交換、鏈表創(chuàng)建、學生成績排序能改自寫代碼而不崩潰文件與內(nèi)存管理文件復制、成績單存取、動態(tài)內(nèi)存申請能跑通寫入和讀取并檢查錯誤這張表很重要。你可以先把PDF里每道題的標題或者第一行注釋掃描一遍給題目打上這樣的標簽。哪怕只是用數(shù)字在頁邊標上“數(shù)組”“指針”“文件”幾個字也比盲目刷三道相似的判斷素數(shù)題強。順便說一句網(wǎng)上流傳的“C語言必背100代碼”很多就是把這類經(jīng)典題壓縮成模板但背著寫和能自己推導出邊界條件是兩回事。字符串數(shù)組作為參數(shù)這類題目如果沒歸到“數(shù)組與字符串”這一塊很容易在后面的鏈表題里被遺忘。2.2 指針題先分清“改變原值”和“改變指針指向”100例里但凡涉及到指針的題翻來覆去也就那幾個模型。最容易卡住新手的是為什么swap用int a,int b不能交換用int *a,int *b才能交換先看一段最小示例#include stdio.h void swap_wrong(int a, int b) { int t a; a b; b t; } void swap_right(int *a, int *b) { int t *a; *a *b; *b t; } int main() { int x 3, y 5; swap_wrong(x, y); printf(wrong: %d %d\n, x, y); swap_right(x, y); printf(right: %d %d\n, x, y); return 0; }swap_right 的參數(shù)接收的是 x 和 y 的地址函數(shù)內(nèi)部通過*a、*b間接修改了 main 函數(shù)棧上的變量。而 swap_wrong 只交換了形參副本調(diào)用結束后副本生命周期結束主調(diào)方看不到任何變化。所以指針在函數(shù)參數(shù)里的意義是“把地址傳進去讓被調(diào)函數(shù)能改外部變量”。把這個模型記住后續(xù)讀鏈表題里的struct Student **head就不會發(fā)暈需要在函數(shù)里改變 head 指針本身時就要傳入指針的指針。2.3 數(shù)組參數(shù)會退化成指針這是很多運行時問題的根源和指針綁定的另一個經(jīng)典誤區(qū)是“數(shù)組到底是不是指針”。在 main 里寫sizeof(arr) / sizeof(arr[0])能得到元素個數(shù)但一旦把數(shù)組作為參數(shù)傳給函數(shù)函數(shù)里的sizeof(arr)就成了指針大小通常是8字節(jié)于是數(shù)組長度就算錯了。經(jīng)典例題里經(jīng)常要求自己實現(xiàn)一個排序函數(shù)很多人直接在函數(shù)里用sizeof算長度結果排序條件循環(huán)不執(zhí)行。void show_size(int arr[]) { printf(in function: %zu\n, sizeof(arr)); // 指針大小不是數(shù)組大小 } int main() { int arr[4] {1, 2, 3, 4}; printf(in main: %zu\n, sizeof(arr)); // 16byte show_size(arr); return 0; }解決辦法是函數(shù)參數(shù)里同時傳入長度或者用int *arr并搭配長度參數(shù)。100例里凡是要求“輸入n個整數(shù)再處理”的題目幾乎都會用到這個約定數(shù)組名當實參傳的時候?qū)崊⒈緛砭椭皇鞘自氐刂匪员徽{(diào)函數(shù)拿不到數(shù)組邊界。記住這條再寫C語言鏈表或字符串數(shù)組作為參數(shù)時就少踩很多坑。3. 在本地跑通經(jīng)典題從冒泡排序到字符串函數(shù)看最小可編譯流程3.1 用 gcc 一行命令跑通最小程序參數(shù)含義要清楚很多人在PDF上看得懂代碼卻不知道怎么在本地運行。最省事的方式是用gcc編譯單個源文件。假如題目要求實現(xiàn)冒泡排序則先建一個bubble.c然后把代碼貼進去在終端執(zhí)行gcc -Wall -stdc11 -g -o bubble bubble.c ./bubble這里的-Wall是讓編譯器輸出常見警告能幫你發(fā)現(xiàn)變量未使用或類型不匹配刷題時建議始終打開-stdc11是指定C語言標準避免某些老舊教材寫法在新版gcc里出現(xiàn)兼容性問題-g是生成調(diào)試符號后面要用gdb單步驗證時就離不開它-o bubble指定輸出文件名不寫的話默認是a.out。如果是在Windows上的VSCode里配置C語言環(huán)境常見做法也是把gcc作為任務編譯器tasks.json里的command填同一個路徑原理完全一樣。3.2 冒泡排序C語言實現(xiàn)n-1-i這個邊界是怎么來的排序題幾乎每個版本都會出現(xiàn)。給出一版帶提前終止的寫法#include stdio.h void bubble_sort(int arr[], int n) { for (int i 0; i n - 1; i) { int swapped 0; for (int j 0; j n - 1 - i; j) { if (arr[j] arr[j 1]) { int t arr[j]; arr[j] arr[j 1]; arr[j 1] t; swapped 1; } } if (!swapped) break; } } int main() { int arr[] {54, 23, 12, 77, 9}; int n sizeof(arr) / sizeof(arr[0]); bubble_sort(arr, n); for (int i 0; i n; i) { printf(%d%c, arr[i], i n - 1 ? \n : ); } return 0; }外層第 i 輪結束后最大的 i1 個元素已經(jīng)沉到末尾所以內(nèi)層只需要比較到n - 1 - i這是“減少無用比較”的關鍵。swapped用來記錄這一輪是否發(fā)生過交換如果整個序列在一次遍歷后已經(jīng)有序就直接結束。參數(shù)arr[]雖然寫法像個數(shù)組實際傳進來的仍是首地址函數(shù)內(nèi)修改會影響到main里的原數(shù)組。main 里sizeof(arr) / sizeof(arr[0])必須在數(shù)組定義所在的函數(shù)里計算一旦進入bubble_sort就失效這也呼應了上一章的退化問題。如果題目要求輸入動態(tài)數(shù)量的數(shù)字可以把數(shù)組換成C語言long long數(shù)組注意讀取時用%lld排序邏輯不變。3.3 字符串函數(shù)那幾道題strcpy、strstr、字符串逆序一起練字符串在經(jīng)典例題里出現(xiàn)頻率極高。常見的題目有手寫strcpy、查找子串、逆序輸出。先看一個最精簡的字符串逆序?qū)崿F(xiàn)#include stdio.h #include string.h void reverse_str(char s[]) { int left 0; int right strlen(s) - 1; while (left right) { char t s[left]; s[left] s[right]; s[right] t; left; right--; } } int main() { char text[] hello; reverse_str(text); printf(%s\n, text); return 0; }strlen(s)返回的是不含\0的長度所以右邊界是len - 1。雙指針從兩端向中間移動交換字符直到相遇。這里有個容易忽略的點如果定義成char *text hello字符串字面量會被放在只讀區(qū)在reverse_str里寫它會導致段錯誤必須用字符數(shù)組char text[]才能原地修改。C語言字符串函數(shù)里還有strcpy(dest, src)不檢查目標空間大小的坑以及strstr可以查找普通字符串但要注意它是按字節(jié)匹配的如果需要查找的片段里可能含\0就不適合。刷字符串逆序和子串查找題時最好順手把這些邊界條件都驗證一遍。4. 進階題必練鏈表、結構體與文件讀寫把C語言常用語法串起來4.1 結構體、typedef與自引用指針題題都能用文件讀寫題和鏈表題往往共用同一個數(shù)據(jù)結構某個實體比如學生、圖書、商品有若干個字段還需要一個指向下一條記錄的指針。以最常見的“學生信息管理”為例結構體一般這樣聲明#include stdio.h #include stdlib.h #include string.h typedef struct Student { int id; char name[32]; int score; struct Student *next; } Student;typedef的作用是給struct Student起個別名后面寫函數(shù)簽名時不用每次帶struct關鍵字。成員里struct Student *next是指向同一結構體類型的自引用指針這正是鏈表在C語言里能存在的原因。注意這個指針不能用Student *next直接聲明因為Student別名在結構體內(nèi)部還沒有定義完雖然某些編譯器能容忍但標準C里不能這么寫。結構體題還會考察內(nèi)存對齊name[32]加兩個int會讓這個結構體的大小大于328你可以用sizeof(Student)觀察但不建議在刷題階段用#pragma pack去改對齊先理解默認對齊規(guī)則更穩(wěn)妥。4.2 鏈表插入、遍歷和釋放先畫出指針指向再寫代碼鏈表題是100例里的分水嶺。我一般建議先畫圖再寫代碼。頭插法建鏈的代碼很好記但面試更??肌胺崔D(zhuǎn)鏈表”這里給一個用迭代反轉(zhuǎn)的最小實現(xiàn)void reverse_list(Student **head) { Student *prev NULL; Student *curr *head; while (curr ! NULL) { Student *next curr-next; curr-next prev; prev curr; curr next; } *head prev; }curr是當前節(jié)點next先暫存原來的后繼否則把curr-next指向前驅(qū)時原始鏈就斷了。最后把頭指針更新為新鏈表的頭。注意參數(shù)為什么是Student **head函數(shù)內(nèi)部要修改調(diào)用方的頭指針單個*head只能改節(jié)點內(nèi)容改不了head本身。遍歷和釋放鏈表的套路也應當順手寫上釋放時先暫存next再free當前節(jié)點不然先free再訪問next就是訪存了已釋放內(nèi)存。C語言內(nèi)存管理里這類問題是 valgrind 最容易報出來的別等面試時才發(fā)現(xiàn)。4.3 fprintf/fscanf 文件讀寫三條固定步驟少一條都不行結構體和鏈表編完數(shù)據(jù)最終要落盤。文件操作題的標準姿勢是“打開-讀寫-關閉”每一步都要檢查錯誤。void save_students(Student *head) { FILE *fp fopen(students.txt, w); if (fp NULL) { perror(fopen failed); return; } for (Student *p head; p ! NULL; p p-next) { fprintf(fp, %d %s %d\n, p-id, p-name, p-score); } fclose(fp); } void load_students() { FILE *fp fopen(students.txt, r); if (fp NULL) { perror(fopen failed); return; } int id, score; char name[32]; while (fscanf(fp, %d %s %d, id, name, score) 3) { printf(%d %s %d\n, id, name, score); } fclose(fp); }fopen 的w會截斷已有文件r要求文件必須存在a是追加。fprintf 和 fscanf 格式串要嚴格對應讀字符串時%s會自動跳過空白字符但不會讀取帶空格的字符串這正好適合書本上那種簡單的“一行一條”數(shù)據(jù)格式。判斷讀取成功的條件要寫 3因為如果文件提前結束fscanf 返回匹配成功的項數(shù)會小于3循環(huán)體就不會執(zhí)行多余的數(shù)據(jù)。最后fclose不只是釋放資源它還會把緩沖區(qū)剩余內(nèi)容刷到磁盤漏掉它可能導致文件里缺尾塊。如果你刷到虛擬存儲器管理、流量計累計這類偏實踐的題目文件讀寫往往就扮演數(shù)據(jù)記錄的角色與這里的三步走一致。5. 把100例變成自己的驗證集三個能直接用的小技巧5.1 用 assert 宏給每道題加前置條件刷題時快速反饋給排序或查找函數(shù)加一行assert(p ! NULL)能快速暴露空指針。比如在鏈表函數(shù)開頭加#include assert.h void reverse_list(Student **head) { assert(head ! NULL); // head 本身不能為空 if (*head NULL) return; // ... }assert在NDEBUG宏定義后會被整個取消所以不要把它當成最終的錯誤處理。刷題階段它能讓錯誤盡早暴露尤其是那種“偶爾崩潰偶正?!钡囊爸羔槅栴}。5.2 用 valgrind 驗證代碼有沒有內(nèi)存泄漏C語言內(nèi)存管理題里最常見的扣分點是申請了malloc但忘了free。編譯時加-g然后運行gcc -Wall -stdc11 -g -o demo demo.c valgrind --leak-checkfull --error-exitcode1 ./demo看到 “ERROR SUMMARY: 0 errors” 是基本要求。--error-exitcode1可以讓腳本在檢測到錯誤時返回非零碼以后寫自動批改腳本時直接檢查退出碼就行。這個命令對鏈表題尤其重要因為鏈表的 free 順序一錯valgrind 就會報 invalid free 或 definitely lost。5.3 把PDF里的題目轉(zhuǎn)成Markdown卡片按知識塊打標簽既然原始資料是PDF常見做法是用pdftotext先提取文本再整理pdftotext -layout C語言經(jīng)典例題100例.pdf examples.txt sed -n 1,80p examples.txt-layout會盡量保留版面結構后續(xù)再用腳本按“題目編號”切分轉(zhuǎn)成Markdown卡片時順手加上#鏈表、#指針標簽。PDF里的中文如果亂碼別花時間調(diào)編碼直接手敲題目信息也很快因為最終的目的是給每道題建立索引。整理完自己的索引后你會發(fā)現(xiàn)C語言必背的那些代碼塊都變成了按場景歸類的函數(shù)片段面試前翻一遍自己的驗證集比重新啃PDF更有用。本文還有配套的精品資源點擊獲取