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

C 語言函數與遞歸:從定義聲明到漢諾塔、斐波那契、動態內存、時間函數綜合實戰

     編輯:關於C語言

C 語言函數與遞歸綜合實戰

第一部分:函數基礎

1. 函數定義與調用

int getInt() { return 10; }
double getDouble() { return 5.5; }

int main() {
    int n = getInt();
    double d = getDouble();
    printf("%d\n%lf\n", n, d);
    return 0;
}

2. 函數聲明(隱式 vs 顯式)

  • 隱式聲明:調用前未聲明,編譯器假設返回 int,**危險**(C99 移除,現代編譯器報警/錯)。
  • 顯式聲明:double f2(int a, int b); 或 double f2(void);(無參數)。參數名可省略,類型必須保留。

3. 參數傳遞:值傳遞 vs 數組/指針

void fun1(int a) { a += 10; }           // 值傳遞,不影響實參
void fun2(int arr[]) { arr[0] += 10; }  // 數組退化為指針,影響實參

**核心**:C 語言**只有值傳遞**。數組傳遞實為首元素地址(指針值),函數內修改指針指向的內存會影響外部。

4. 函數返回與程序終止

  • return:返回調用者,棧幀展開,繼續執行。
  • exit(code):直接終止整個進程,調用註冊的 atexit 處理函數,刷新標準 I/O 緩衝區。**調用後不再返回**。

第二部分:遞歸與遞推

1. 階乘:遞歸 vs 迭代

// 遞歸
int fact_rec(int n) {
    if (n == 1) return 1;
    return n * fact_rec(n - 1);
}

// 迭代(遞推)
int fact_iter(int n) {
    int r = 1;
    for (int i = 2; i <= n; i++) r *= i;
    return r;
}

2. 斐波那契:遞歸指數爆炸 vs 迭代線性

// 遞歸:O(2^n) 極慢
long fib_rec(int n) {
    if (n <= 2) return 1;
    return fib_rec(n-1) + fib_rec(n-2);
}

// 迭代:O(n) 快
long fib_iter(int n) {
    long a = 1, b = 1, c = 1;
    for (int i = 3; i <= n; i++) {
        c = a + b;
        a = b;
        b = c;
    }
    return c;
}

**教訓**:重疊子問題導致遞歸指數複雜度,**動態規劃/迭代優化為線性**。

3. 遞歸經典:漢諾塔

void hanoi(int n, char from, char aux, char to) {
    if (n == 1) {
        printf("%c -> %c\n", from, to);
        return;
    }
    hanoi(n-1, from, to, aux);   // n-1 從 from 借 to 移到 aux
    printf("%c -> %c\n", from, to); // 第 n 個從 from 移到 to
    hanoi(n-1, aux, from, to);   // n-1 從 aux 借 from 移到 to
}

遞歸三步驟:**分解子問題、解決基例、合併結果**。

第三部分:標準庫進階

1. 格式化輸入輸出細節

  • scanf("%*d %d", &a, &b):* 抑制賦值,跳過第一個整數。
  • printf("%10d, %-10d"):寬度 10,左對齊/右對齊。
  • printf("%08d"):不足 8 位左補 0。
  • printf("%0*d", 8, 100):動態寬度補 0。
  • printf("%.2f"):保留 2 位小數。

2. 動態內存管理

int *p = malloc(sizeof(int));
*p = 10;
free(p);

char *s = malloc(1024);
strcpy(s, "heap string");
free(s);

struct Data *d = malloc(sizeof(*d));
d->a = 1; d->b = 2.0;
free(d);

// 數組
int *arr = malloc(10 * sizeof(int));
for (int i=0; i<10; i++) arr[i] = i+1;
free(arr);

**鐵律**:每個 malloc 必配 free,防洩漏。

3. 時間函數

time_t t = time(NULL);
struct tm *lt = localtime(&t);
printf("%d-%02d-%02d %02d:%02d:%02d\n",
    1900+lt->tm_year, lt->tm_mon+1, lt->tm_mday,
    lt->tm_hour, lt->tm_min, lt->tm_sec);

第四部分:文件輸入輸出 (IO)

1. 打開模式

模式含義
r只讀,文件必須存在
w只寫,截斷/創建
a追加寫,創建
r+/w+/a+讀寫,對應 r/w/a 基礎上可讀
+b二進制模式(Windows 區分換行轉換)

2. 格式化文件讀寫

FILE *fp = fopen("data.txt", "w");
fprintf(fp, "%c %d %f %lf\n", 'a', 10, 12.34f, 12345.6789);
fclose(fp);

fp = fopen("data.txt", "r");
char c; int i; float f; double d;
fscanf(fp, "%c %d %f %lf", &c, &i, &f, &d);
fclose(fp);

3. 二進制塊讀寫

struct Student { int id; char name[20]; char addr[200]; };
struct Student s = {10000, "zhangsan", "江蘇南京"};

FILE *fp = fopen("stu.bin", "wb");
fwrite(&s, sizeof(s), 1, fp);
fclose(fp);

fp = fopen("stu.bin", "rb");
struct Student r;
fread(&r, sizeof(r), 1, fp);
fclose(fp);

4. 文件指針定位

fseek(fp, 0, SEEK_SET);   // 文件開頭
fseek(fp, 5, SEEK_CUR);   // 當前位置 +5
fseek(fp, -10, SEEK_END); // 文件末尾 -10
long pos = ftell(fp);     // 獲取位置

5. 文件複製(字符流)

FILE *src = fopen("src.txt", "r");
FILE *dst = fopen("dst.txt", "w");
int ch;
while ((ch = getc(src)) != EOF) putc(ch, dst);
fclose(src); fclose(dst);

第五部分:進階主題

1. 可變參數函數

#include 
int max(int cnt, ...) {
    va_list ap; va_start(ap, cnt);
    int m = va_arg(ap, int);
    for (int i=1; i m) m = v;
    }
    va_end(ap);
    return m;
}
// 調用:max(5, 10, 20, 5, 30, 15) → 30

2. 字符串格式化

char buf[100];
sprintf(buf, "len=%lu, str=%s", strlen("abc"), "abc"); // 寫入字符串
sscanf(buf, "len=%d, str=%s", &len, str);              // 從字符串解析

總結

本文涵蓋 C 語言函數機制(定義、聲明、參數傳遞、返回/退出)、遞歸與遞推核心模式(階乘、斐波那契、漢諾塔)、標準庫進階用法(格式化細節、動態內存、時間、文件 IO、可變參數、字符串格式化)。掌握「值傳遞本質、遞歸基例與分解、malloc/free 配對、文件模式選擇、va_list 參數遍歷」等核心概念,構建扎實的 C 語言工程基礎。

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