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

C語言基礎教程(五):利用全域變數實現函數間參數傳遞

     編輯:C 語言基礎

全域變數:跨函數共享資料的另類選擇

在前幾節中,我們探討了透過函數參數(傳值呼叫)與指標(傳址呼叫)來實現主呼叫函數與被呼叫函數之間的資料交換。雖然這兩種機制是標準做法,但在某些情境下——例如參數眾多、層級較深的呼叫鏈——逐層傳遞參數會顯得繁瑣且易出錯。此時,將需共享的變數宣告為全域變數,便能讓它在整個程式的所有函數中「可見」,相當於隱性地完成了參數的傳遞與回傳。這在早期的 C 語言教學與實務專案中頗為常見。

權衡利弊:便利性與記憶體成本

全域變數的優點顯而易見:免去參數列表的撰寫與維護,程式碼看似簡潔。然而,代價是它們會長期佔用靜態記憶體空間,直到程式結束才會釋放。對於大型陣列或結構體,這可能導致記憶體浪費,甚至超出小型嵌入式系統的限制。好在現代桌面與伺服器環境記憶體充裕,多數教學範例與中小型專案仍能輕鬆負擔。

實戰範例:陣列的跨函數修改

以下程式示範如何在 main 與 disp 之間,透過全域陣列 m 直接交換資料:

#include <stdio.h>
#include <conio.h>   /* getch() 所需 */

void disp(void);          /* 函數原型宣告 */
int m[10];                /* 全域變數:整個程式可見 */

int main(void)
{
    int i;
    printf("In main before calling\n");
    for (i = 0; i < 10; i++) {
        m[i] = i;                 /* 初始化陣列 */
        printf("%3d", m[i]);      /* 輸出呼叫前的值 */
    }

    disp();                       /* 呼叫子函數 */

    printf("\nIn main after calling\n");
    for (i = 0; i < 10; i++)
        printf("%3d", m[i]);      /* 輸出呼叫後的值 */

    getch();
    return 0;
}

void disp(void)
{
    int j;
    printf("\nIn subfunc after calling\n");  /* 子函數內輸出 */
    for (j = 0; j < 10; j++) {
        m[j] = m[j] * 10;         /* 直接修改全域陣列 */
        printf("%3d", m[j]);
    }
}

關鍵細節解析

  • 宣告位置:int m[10]; 置於所有函數之外,故屬外部連結,全程可見。
  • 無需傳參:disp() 參數列為空,仍能直接讀寫 m。
  • 副作用明確:呼叫 disp() 後,main 中的 m 已被乘以 10,體現「隱性回傳」。
  • 迴圈變數修正:原教材範例在 disp 迴圈條件誤寫 i<10,此處已修正為 j<10,並同步修正列印索引。

最佳實務建議

  1. 慎用全域變數:僅在「極少數、確實需全程共享」的資料上使用(如裝置暫存器映射、系統設定旗標)。
  2. 命名規範:建議加前綴 g_(如 g_config)以利辨識。
  3. 封裝存取:提供 get_g_config() / set_g_config() 函數,集中管理鎖機制、邊界檢查與日誌。
  4. 靜態區域替代:若僅需在單一檔案內多函數共享,改用 static 檔案作用域變數,避免汙染全域命名空間。

總結:全域變數是把「雙面刃」,善用可簡化架構,濫用則釀成維護惡夢。現代 C 開發傾向「最小權限原則」——優先以參數傳遞、結構體封裝、模組化介面取代全域狀態,僅在極少數經評估必要的場合引入全域變數。

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