基於這個新想法,我們設計以下的函數原型
My_Time *myTimeS3(time_t seconds);
函數 myTimeS3() 仍是需要 time() 回傳的秒數值當作參數,而函數名稱前的星號 * ,表示 myTimeS3() 回傳的是指標,所以型號前需要註明什麼型態的指標。
定義如下
My_Time *myTimeS3(time_t seconds) { struct tm *tmPtr = localtime(&seconds); My_Time mt; My_Time *mtPtr = &mt; mt.year = tmPtr->tm_year + 1900; mt.month = tmPtr->tm_mon + 1; mt.day = tmPtr->tm_mday; mt.hour = tmPtr->tm_hour; if (mt.hour < 12 ) { mt.isam = 1; mt.hourt = tmPtr-<tm_hour; } else { mt.isam = 0; mt.hourt = tmPtr-<tm_hour - 12; } mt.min = tmPtr-<tm_min; mt.sec = tmPtr-<tm_sec; return mtPtr; }
嗯,這樣看起來沒錯的,我們依序建立 My_Time 型態的變數 mt ,然後建立指向 mt 的指標變數 mtPtr ,然後將得到的時間轉化為 My_Time 型態,最後回傳指標變數 mtPtr ......
完整的範例程式碼及編譯執行,請繼續參考
咦?為什麼會出現這麼奇怪的結果?
我們不打細究這個奇怪結果,因為我們也無法利用這奇怪的數值。指標變數 mtPtr 所指向的是函數 myTimeS3() 內的結構 mt ,一旦程式執行離開 myTimeS3() ,按理 myTimeS3() 內所有宣告的變數都無法再使用,如果用指標取得記憶體位址讀值,便容易得到垃圾值,也就是記憶體中未定義的殘值。
這樣回傳指標是會發生問題的,因此是個錯誤的設計方式。那如果我們想要如 time.h 的 localtime() 回傳指向 tm 的指標,我們應該怎麼修改呢?其實有幾種方法,我們先來討論利用動態記憶體配置回傳指標。
標準函數庫中 stdlib.h 的函數 malloc() 可以向作業系統要求配置新的記憶體空間,然後回傳該記憶體空間位置的指標,而 malloc() 本身需要新記憶體空間大小的整數值當成參數,通常會用 sizeof 運算子進行計算。sizeof 為關鍵字之一,常用於計算資料型態所需的位元組數。
這樣新函數的原型幾乎沒有多大的變動
My_Time *myTimeS4(time_t seconds);
定義如下
My_Time *myTimeS4(time_t seconds) { struct tm *tmPtr = localtime(&seconds); My_Time *mtPtr = malloc(sizeof(My_Time)); mtPtr->year = tmPtr->tm_year + 1900; mtPtr->month = tmPtr->tm_mon + 1; mtPtr->day = tmPtr->tm_mday; mtPtr->hour = tmPtr->tm_hour; if (mtPtr->hour < 12 ) { mtPtr->isam = 1; mtPtr->hourt = tmPtr->tm_hour; } else { mtPtr->isam = 0; mtPtr->hourt = tmPtr->tm_hour - 12; } mtPtr->min = tmPtr->tm_min; mtPtr->sec = tmPtr->tm_sec; return mtPtr; }
因此 mtPtr 為向作業系統要求配置新記憶體空間的指標,該空間可儲存 My_Time 型態的結構,這個新記憶體空間不屬於函數 myTimeS4() 內宣告的自動變數,因此回傳該指標在 main() 仍可正常運作。
完整的範例程式碼及編譯執行,請繼續參考
問題與討論
- 為什麼 myTimeS3() 內宣告的變數都無法在其他地方使用?
- 想一想,動態記憶體配置還可以運用在哪些地方?
沒有留言:
張貼留言