首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言經典程式設計實例集錦(八):學生資料管理、鏈表操作與趣味算法

     編輯:關於C語言

前言

本文繼續《C語言程式開發經典實例》系列,精選了第 71 至 80 號共十個經典範例。涵蓋結構體陣列處理、單向鏈表的建立與反轉、兩表串接、指標函數應用、指標的指標操作、邏輯謎題求解、分數區間獎金計算,以及著名的「五猴分桃」數學難題。每個範例均附完整原始碼與詳細註解,適合初學者鞏固語法,也供進階開發者參考演算法思路。

範例 71:學生資料的輸入與輸出

問題描述

編寫 input() 與 output() 兩個函式,分別完成 5 位學生學號、姓名及三科成績的鍵盤輸入與格式化輸出。

核心設計

  • 定義結構體 student,包含字元陣列 num[6]、name[8] 及整數陣列 score[4](索引 1~3 存三科分數)。
  • input() 採雙層迴圈逐筆讀取,scanf("%s") 讀字串,scanf("%d") 讀整數。
  • print() 使用 %-6s、%-10s、%-8d 靠左對齊輸出,形成整齊表格。

程式碼精要

#define N 5
struct student {
    char num[6];
    char name[8];
    int score[4];
} stu[N];

void input(struct student stu[]) {
    int i, j;
    for (i = 0; i < N; i++) {
        printf("\n please input %d of %d\n", i+1, N);
        printf("num: ");  scanf("%s", stu[i].num);
        printf("name: "); scanf("%s", stu[i].name);
        for (j = 0; j < 3; j++) {
            printf("score %d: ", j+1);
            scanf("%d", &stu[i].score[j]);
        }
    }
}

void print(struct student stu[]) {
    int i, j;
    printf("\nNo.     Name         Sco1    Sco2    Sco3\n");
    for (i = 0; i < N; i++) {
        printf("%-6s%-10s", stu[i].num, stu[i].name);
        for (j = 0; j < 3; j++)
            printf("%-8d", stu[i].score[j]);
        printf("\n");
    }
}

int main() {
    input(stu);
    print(stu);
    return 0;
}

範例 72:建立單向鏈表

演算法邏輯

  1. 動態配置首節點,head 指向鏈表頭。
  2. 迴圈讀入 5 個整數,每次配置新節點並串接至尾端。
  3. 最後一個節點的 next 設為 NULL。
  4. 遍歷列印驗證。

常見錯誤提醒

原始碼中 ptr=head; 應在 malloc 之後,否則會丟失首節點位址;列印迴圈裡的 tr=ptr->next; 疑為筆誤,應為 ptr=ptr->next;。

範例 73:反向輸出鏈表

巧思:頭插法天然逆序

每讀一筆資料,即配置新節點插在現有鏈表頭部(head->next = ptr; ptr = head;),輸入順序 1→2→3→4→5,鏈表實際順序即為 5→4→3→2→1,遍歷即得反向輸出,無需額外反轉演算法。

範例 74:兩個鏈表的串接與選擇排序

模組化設計亮點

  • create_list():由陣列建立鏈表,回傳頭指標。
  • concatenate():尋找第一個鏈表尾節點,將其 next 指向第二個鏈表頭。
  • selection_sort():在鏈表上實作選擇排序,配合 delete_node() 刪除已排序的最小節點並輸出。

此範例展示如何將複雜操作拆解為可重用函式,是結構化程式設計的優良示範。

範例 75:邏輯推理趣題——誰說了真話?

題目重述

四人各說一句話,只有其中一人說真話,其餘說謊。利用布林邏輯累加真話計數 n,當 n==3 時輸出對應字元(ASCII 65='A' 起),揭曉說真話者。

核心程式碼

int main() {
    int i, n;
    for (i = 1; i < 5; i++) {
        n = 0;
        if (i != 1) n++;
        if (i == 3) n++;
        if (i == 4) n++;
        if (i != 4) n++;
        if (n == 3)
            printf("說真話的是: %c\n", 64 + i);
    }
    return 0;
}

執行結果輸出 C,即第三人說真話。

範例 76:指標函數實作調和級數求和

需求

輸入 n,若為偶數計算 1/2+1/4+...+1/n,奇數計算 1/1+1/3+...+1/n。要求使用函數指標回呼機制。

關鍵技術

  • 宣告函數指標型別:float (*fp)(int)。
  • dcall(fp, n) 作為通用呼叫介面,執行 return (*fp)(n);。
  • peven()、podd() 分別實作偶數、奇數項求和,注意 1/(float)i 強制浮點除法。

範例 77:指向指標的指標填空練習

題目

已知 char *s[] = {"man","woman","girl","boy","sister"}; 及 char **q;,請在迴圈填入敘述使其依序列印五個字串。

答案與解析

for (k = 0; k < 5; k++) {
    q = &s[k];   // 或 q = s + k;
    printf("%s\n", *q);
}

s[k] 型別為 char*,取址得 char** 指派給 q,解參考 *q 即得字串首址。

範例 78:尋找最年長者——找出程式錯誤

原始碼缺陷分析

if (m < p->age)
    q = p++;   // 錯誤:後置++ 導致 q 指向舊位址,m 卻取新位址的 age
m = q->age;

正確寫法

if (m < p->age) {
    m = p->age;
    q = p;
}
p++;

或直接用索引 person[i] 避免指標運算錯誤。

範例 79:字串排序——指標交換陷阱

錯誤示範

swap() 內部宣告 char *p[20]; 做暫存,但 strcpy(p, p1); 將字串複製到未初始化的指標陣列,導致未定義行為。

修正版

void swap(char **p1, char **p2) {
    char *tmp = *p1;
    *p1 = *p2;
    *p2 = tmp;
}

主程式改呼叫 swap(&str1, &str2);,真正交換指標指向,而非搬移字串內容,效率更高且安全。

範例 80:經典數學難題——五猴分桃

問題模型

設原始桃子數為 x,每猴操作:x = (x-1)/5 * 4,需滿足 5 次運算後皆為整數。反向推導:若第 5 猴操作前剩 y,則 y = 4*k,上一輪剩 5*k+1。程式從 4 開始以 4 為步長試探,模擬 5 輪逆運算,首個通過即為最小解。

優化版邏輯

int main() {
    long x = 4;
    while (1) {
        long cur = x;
        int ok = 1;
        for (int i = 0; i < 5; i++) {
            if (cur % 4 != 0) { ok = 0; break; }
            cur = cur / 4 * 5 + 1;  // 逆推上一輪剩餘
        }
        if (ok) { printf("最少桃子數: %ld\n", cur); break; }
        x += 4;
    }
    return 0;
}

答案為 3121 顆。

總結與延伸

本集錦涵蓋資料結構、指標進階、函數指標、邏輯推理、數學建模等核心能力。建議讀者:

  1. 手動輸入並編譯執行每個範例,觀察輸出差異。
  2. 嘗試修改資料規模(如學生人數、鏈表長度)驗證健壯性。
  3. 將範例 79 的 swap 改為泛型 void swap(void**, void**) 練習泛型程式設計。
  4. 自行實作「五猴分桃」的遞迴與數學解析解法比較效能。

下一集將介紹檔案操作、位元運算與巨集進階應用,敬請期待。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved