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

深入理解 main 函數參數 argc 與 argv 的內部機制

     編輯:關於C語言

對於 C/C++ 程式設計師,int main(int argc, char **argv) 是再熟悉不過的簽名。但你是否真正了解作業系統如何準備這些參數?argv 到底指向哪裡?環境變數又藏在哪?本文透過實驗程式碼,帶你一探究竟。

核心觀念兩點

  1. 參數存放於可修改的一維字元陣列:Shell 輸入的命令列字串被核心複製到進程的使用者空間記憶體中,並非唯讀常數區,因此程式可以修改 argv 指向的字串內容。
  2. argv 是字元指標陣列:char *argv[],元素個數至少為 argc,但實際上核心還會在其後附加環境變數指標(如 HOSTNAME, PATH, TERM 等),以 NULL 指標結尾。

參數分割與結尾處理

核心依據空格將命令列分割為多個參數,將各參數的首地址存入 argv[i]。為了讓 printf("%s", argv[i]) 正常運作,核心會將原本分隔參數的空格替換為 \0(即 *(argv[i]-1) = 0),使每個參數成為獨立的 C 風格字串。

實驗驗證:argv 記憶體佈局與修改

編譯執行以下程式:

/* argcargv.c */
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
    int i;
    for (i = 0; i < argc; i++) {
        printf("%p,%s$\n", argv[i], argv[i]);
    }
    printf("\n");

    // 修改 argv[0]
    strcpy(argv[0], "meilidezhongguo,nihao!");

    for (i = 0; i < argc; i++) {
        printf("%p,%s$\n", argv[i], argv[i]);
    }
    return 0;
}

執行命令:./a.out abc 123 def 456 hello 789 world

輸出結果分析

修改前:

0xbff64758,./a.out$
0xbff64760,abc$
0xbff64764,123$
0xbff64768,def$
0xbff6476c,456$
0xbff64770,hello$
0xbff64776,789$
0xbff6477a,world$
(nil),(null)$
...... (環境變數指標)

觀察位址:argv[0] 到 argv[7] 連續分佈,間隔即為字串長度+1(含結尾 \0)。argv[8] 為 NULL,隨後是環境變數指標。

修改後:

0xbff64758,meilidezhongguo,nihao!$
0xbff64760,hongguo,nihao!$
0xbff64764,guo,nihao!$
0xbff64768,nihao!$
0xbff6476c,o!$
0xbff64770,hello$
0xbff64776,789$
0xbff6477a,world$

strcpy 將較長的字串寫入 argv[0] 起始的緩衝區,導致後續參數的記憶體被覆蓋,印出時顯示為被截斷的尾部。這證明了:

  • argv 指向的記憶體是連續、可寫的。
  • 修改 argv[0] 會影響相鄰參數的內容,實務上極不建議這樣做,除非你確定緩衝區足夠大(如使用 strncpy 限制長度)。

延伸閱讀

  • environ 全域變數(或 main 第三參數 char **envp)正式提供環境變數存取。
  • POSIX 規範保證 argv[argc] == NULL,方便遍歷。

理解 argc/argv 的底層機制,不僅能滿足好奇心,更有助於編寫健壯的命令列解析邏輯,避免緩衝區溢位等安全隱患。

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