文章程式碼顯示

2019年9月7日 星期六

《筆記》C語言 - 補充_11: 動態配置記憶體空間 calloc 與 struct 與 指標函數 的結合

這邊我就不做過多的解釋,因此部份已經是很深的 C 語言使用
這邊我直接舉一個例子
下例中,我生成十個學生的原始成績(score),並將所有學生的原始成績都加上五(num) 變為 new_score ( new_score = score + 5)

#include "stdio.h"
#include "stdlib.h"

#define numberStudent 10
#define Num 5

typedef struct _Student{
    int No;
    int score;
    int (*calScore_func)(int, int);/* function pointer 注意括弧的位置,不可更動否則含義不同*/
    int new_score;
}Student, *PTR_Student;

/*function prototype 此函數後續用來提供 Student 內的 (*calScore_func) 註冊使用 */
int calScore(int score, int AddNum);

int main()
{
    PTR_Student studentTemp = NULL;
    
    studentTemp = (PTR_Student)calloc(sizeof(Student)*numberStudent, 1);
    
    if (studentTemp == NULL){ /* 確定記憶體空間足夠配置 */
        printf("Allocate the memory fail.");
        return -1;
    }
    else { printf("Allocate the memory success.\r\n\n"); }
    
    int* memoryBeginAddr = studentTemp; /*儲存一下 calloc 回傳的位址,隨意用一個一般的指標變數儲存即可*/
    
    for (int i = 1; i <= numberStudent; i++){
        studentTemp->No = i;
        studentTemp->score = i*10;
        studentTemp->calScore_func = calScore; /* 註冊 calScore_func 指向函數 calScore*/
        /* PS : 函數的名稱與陣列的名稱相同,事實上都被 C 語言單純的視為一個記憶體位址 */
        studentTemp->new_score = studentTemp->calScore_func(studentTemp->score, Num);
        studentTemp++;
    }
    
    studentTemp = memoryBeginAddr;
    
    for (int i = 1; i <= numberStudent; i++){
        printf("student No. %d, score : %d, new_score : %d\r\n\n", 
                studentTemp->No, studentTemp->score, studentTemp->new_score);
        studentTemp++;
    }
    
    //free(studentTemp); /* 注意 free 的對象應該要是當初 malloc 回傳的位址*/
    free(memoryBeginAddr);
    
    return 0;
}

int calScore(int score, int AddNum){
    
    return (score + AddNum);
}




以前我學到這裡的時候覺得這東西太複雜了,一點實際用處也沒有
但真正去工作後才發現這東西有很大的用處
舉個例子,如果我們要對 No.5 的同學成績做不一樣的處理呢?
在最小幅度改動原本程式碼的前提下(此點尤為重要,因為一個產品的改朝換代是不允許大幅度修改程式的)
我們只需要加一個 if 判斷式就可以直接讓 No.5 同學在成績修改的部份改用另一個算式

#include "stdio.h"
#include "stdlib.h"

#define numberStudent 10
#define Num 5

typedef struct _Student{
    int No;
    int score;
    int (*calScore_func)(int, int);/* function pointer 注意括弧的位置,不可更動否則含義不同*/
    int new_score;
}Student, *PTR_Student;

/* function prototype 此函數後續用來提供 Student 內的 (*calScore_func) 註冊使用 */
int calScore(int score, int AddNum);
/* 新增一個函數,其與 calScore 有著一模一樣的輸入變數型態(皆為兩個 int),但在計算的時候我們動點手腳*/
int calScore_special(int score, int muti_Num);

int main()
{
    PTR_Student studentTemp = NULL;
    
    studentTemp = (PTR_Student)calloc(sizeof(Student)*numberStudent, 1);
    
    if (studentTemp == NULL){ /* 確定記憶體空間足夠配置 */
        printf("Allocate the memory fail.");
        return -1;
    }
    else { printf("Allocate the memory success.\r\n\n"); }
    
    int* memoryBeginAddr = studentTemp; /*儲存一下 calloc 回傳的位址,隨意用一個一般的指標變數儲存即可*/
    
    for (int i = 1; i <= numberStudent; i++){
        studentTemp->No = i;
        studentTemp->score = i*10;
        studentTemp->calScore_func = calScore; /* 註冊 calScore_func 指向函數 calScore*/
        /* PS : 函數的名稱與陣列的名稱相同,事實上都被 C 語言單純的視為一個記憶體位址 */
        if ( i == 5 ) { studentTemp->calScore_func = calScore_special; } /*指向不一樣的函數*/
        studentTemp->new_score = studentTemp->calScore_func(studentTemp->score, Num);/*此行完全不變*/
        studentTemp++;
    }
    
    studentTemp = memoryBeginAddr;
    
    for (int i = 1; i <= numberStudent; i++){
        printf("student No. %d, score : %d, new_score : %d\r\n\n", 
                studentTemp->No, studentTemp->score, studentTemp->new_score);
        studentTemp++;
    }
    
    //free(studentTemp); /* 注意 free 的對象應該要是當初 malloc 回傳的位址*/
    free(memoryBeginAddr);
    
    return 0;
}

int calScore(int score, int AddNum){
    
    return (score + AddNum);
}

int calScore_special(int score, int muti_Num){
    
    return (score * muti_Num);
}





我的 Youtube 頻道,一定要訂閱
我將定期推出程式語言的新手教學影片


↓↓↓ 連結到部落格方針與索引 ↓↓↓

Blog 使用方針與索引