【小白到大牛之路9】交換機後臺管理系統之函數優化

項目需求

項目8的實現,main函數太臃腫,不便於閱讀和維護。ide

項目實現

用函數來優化。函數

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

FILE *file; 

void init(void) {
    //打開文件
    file = fopen("users.txt", "r");   
    if (!file) {   //等效於 file == NULL  
        printf("文件打開失敗");
        //return 1;
        exit(1);
    }
}

void login(void) {
    char name[32];
    char password[16];
    char line[128];
    char name_tmp[32];
    char password_tmp[16];
    char *ret;

    //輸入用戶名和密碼
    while (1) {
        system("cls");

        // 輸入用戶名和密碼
        printf("請輸入用戶名:");
        scanf("%s", name);
        printf("請輸入密碼:");
        scanf("%s", password);

        //從文件中讀取帳號,並進行判斷!
        while (1) {
            //讀一行
            ret = fgets(line, sizeof(line), file); //line:  "admin 123456\n"
            if (!ret) {
                break;
            }           
            sscanf(line, "%s %s", name_tmp, password_tmp);
            if (!strcmp(name, name_tmp) && !strcmp(password, password_tmp)) {
                break;
            }
        }

        if (ret) {  //用戶名和密碼匹配成功
            break;
        } else {
            printf("用戶名或密碼錯誤!\n");  
            system("pause");
            system("cls");

            fseek(file, 0, SEEK_SET); //把文件內部的位置指針設置到文件頭
        }
    }
}

void create_user(void) {
    system("cls");
    printf("\n\n---建立帳號---\n\n");
    printf("待實現...\n\n");
    printf("\n\n按任意鍵返回主菜單");
    fflush(stdin);
    getchar();
}

void ip_admin(void) {
    system("cls");
    printf("\n\n---IP管理---\n\n");
    printf("待實現...\n\n");
    printf("\n\n按任意鍵返回主菜單");
    fflush(stdin);
    getchar();
}

void logout(void) {
    system("cls");
    fclose(file);
    exit(0);
}

void input_error(void) {
    system("cls");
    printf("\n\n輸入錯誤!\n\n");
    printf("\n\n按任意鍵後,請從新輸入\n\n");
    fflush(stdin);
    getchar();
}

void show_memu(void) {
    system("cls");
    // 打印功能菜單
    printf("---交換機後臺管理---\n");
    printf("1. 建立帳號\n");
    printf("2. IP管理\n");
    printf("3. 退出\n");
    printf("請選擇: ");
}

int main(void) {
    char n; //用戶選擇的菜單編號

    init(); //初始化
    login(); //登陸

    while (1) {
        show_memu();

        fflush(stdin);
        scanf("%c", &n);
        switch (n) {
        case '1':
            create_user();
            break;
        case '2':
            ip_admin(); 
            break;
        case '3':
            logout();
            break;
        default:
            input_error();
            break;
        }
    }

    return 0;
}

項目精講

1.爲何要使用函數

已經有main函數,爲何還要自定義函數?
1)「避免重複製造輪子」,提升開發效率性能

2)便於維護優化

2.函數的聲明、定義和使用

函數的設計方法:
1)先肯定函數的功能
2)肯定函數的參數
是否須要參數,參數的個數,參數的類型
3)肯定函數的返回值
是否須要返回值,返回值的類型設計

函數的聲明3d

函數的使用指針

3.函數的值傳遞

調用函數時,形參被賦值爲對應的實參,
實參自己不會受到函數的影響!
【小白到大牛之路9】交換機後臺管理系統之函數優化code

4.函數的棧空間

要避免棧空間溢出。
當調用一個函數時,就會在棧空間,爲這個函數,分配一塊內存區域,
這塊內存區域,專門給這個函數使用。
這塊內存區域,就叫作「棧幀」。blog

【小白到大牛之路9】交換機後臺管理系統之函數優化
【小白到大牛之路9】交換機後臺管理系統之函數優化

demo1遞歸

#include <stdio.h>
#include <string.h>

void test(void) {
    //運行時將由於棧幀空間溢出,而崩潰
    char buff[1024*1024*2];
    memset(buff, 0, sizeof(buff));
}

int main(void) {
    test();
    return 0;
}

demo2

#include <stdio.h>
#include <string.h>

void test(int n) {
    char buff[1024*256];
    memset(buff, 0, sizeof(buff));

    if (n==0) {
        return;
    } 

    printf("n=%d\n", n);
    test(n-1);
}

int main(void) {
    //test(5);
    //由於每一個棧幀有256K以上, 10個棧幀超出範圍
    test(10);  
    return 0;
}

5.遞歸函數

定義:在函數的內部,直接或者間接的調用本身。

要點:
再定義遞歸函數時,必定要肯定一個「結束條件」!!!

使用場合:
處理一些特別複雜的問題,難以直接解決。
可是,能夠有辦法把這個問題變得更簡單(轉換成一個更簡單的問題)。

盜夢空間
【小白到大牛之路9】交換機後臺管理系統之函數優化
例如:
1)迷宮問題
2)漢諾塔問題

斐波那契數列
1,1, 2, 3, 5, 8, 13, 21, ....
計算第n個數是多少?

f(n)
當n >2時,f(n) = f(n-1) + f(n-2)
當n=1或n=2時, f(n)就是1

int fib(int n) {
int s;

if (n == 1|| n == 2) {
return 1;
}

s = fib(n-1) + fib(n-2);
return s;
}

遞歸函數的缺點:
性能很低!!!

項目練習

1.練習1

獨立完成項目9

2.練習2

定義一個函數,實現1+2+3+...+n

#include <stdio.h>

int sum(int n) {
    int i;
    int s = 0;

    for (i=1; i<=n; i++) {
        s += i;
    }

    return s;
}

int main(void) {
    int value;

    printf("請輸入一個整數: ");
    scanf("%d", &value);
    if (value < 0) {
        printf("須要大於0\n");
        return 1;
    }

    printf("%d\n", sum(value));

    return 0;
}

3.打印金字塔

打印指定類型的金字塔,用自定義函數實現。
效果以下:
【小白到大牛之路9】交換機後臺管理系統之函數優化
代碼:

#include <stdio.h>

void show(char c, int n) {
    int i;
    int j;

    for (i=1; i<=n; i++) {
        for (j=0; j<n-i; j++) {
            printf(" ");
        }
        for (j=0; j<2*i-1; j++) {
            printf("%c", c); 
        }
        printf("\n");
    }
}

int main(void) {
    char c;
    int n;

    printf("請輸入金字塔的組成字符: ");
    scanf("%c", &c);
    if (c == '\n' || c == ' ' || c == '\t') {
        printf("請輸入一個非空白字符\n");
        return 1;
    }

    printf("請輸入金字塔的層數: ");
    scanf("%d", &n);
    if (n < 1) {
        printf("層數須要大於0\n");
        return 1;
    }

    show(c, n);

    return 0;
}

4.用遞歸函數實現練習2

#include <stdio.h>

int sum(int n) {
    int s;

    if (n == 1) {
        return 1;
    }

    s = n + sum(n-1);

    return s;
}

int main(void) {
    int value;

    printf("請輸入一個整數: ");
    scanf("%d", &value);

    if (value < 0) {
        printf("須要大於0\n");
        return 1;
    }

    printf("%d\n", sum(value));

    return 0;
}

5.用遞歸函數實現漢諾塔

#include <stdio.h>

void hanoi(int n, char pillar_start[], char pillar_mid[], char pillar_end[]) {
    if (n == 1) {
        printf("從%s移動到%s\n", pillar_start, pillar_end);
        return;
    }

    hanoi(n-1, pillar_start, pillar_end, pillar_mid); 
    printf("從%s移動到%s\n", pillar_start, pillar_end);
    hanoi(n-1, pillar_mid, pillar_start, pillar_end); 
}

int main(void) {
    char name1[] = "A柱";
    char name2[] = "B柱";
    char name3[] = "C柱";
    int n = 3; //盤子數

    hanoi(3, name1, name2, name3);

    return 0;
}
相關文章
相關標籤/搜索