簡體   English   中英

C 中的命令行參數“argv”的類型是什么?

[英]What is the type of command-line argument `argv` in C?

我正在閱讀 C Primer Plus 中關於命令行參數argv的部分,但我很難理解這句話。

它說,

該程序將命令行字符串存儲在 memory 中,並將每個字符串的地址存儲在指針數組中。 該數組的地址存儲在第二個參數中。 按照慣例,這個指向指針的指針稱為argv ,用於參數值。

這是否意味着命令行字符串作為指向char數組的指針數組存儲在 memory 中?

argv的類型為char ** 它不是一個數組 它是指向char指針。 命令行參數存儲在存儲器中,每個存儲器位置的地址存儲在一個數組中。 這個數組是一個指向char的指針數組。 argv指向此數組的第一個元素。

Some
                  array

                 +-------+        +------+------+-------------+------+
argv ----------> |       |        |      |      |             |      |
                 | 0x100 +------> |      |      | . . . . . . |      |  Program Name1
         0x900   |       |        |      |      |             |      |
                 |       |        +------+------+-------------+------+
                 +-------+         0x100  0x101
                 |       |        +------+------+-------------+------+
                 | 0x205 |        |      |      |             |      |
         0x904   |       +------> |      |      | . . . . . . |      |  Arg1
                 |       |  .     |      |      |             |      |
                 +-------+        +------+------+-------------+------+
                 |  .    |  .      0x205  0x206
                 |  .    |
                 |  .    |  .
                 |  .    |
                 +-------+  .     +------+------+-------------+------+
                 |       |        |      |      |             |      |
                 | 0x501 +------> |      |      | . . . . . . |      |  Argargc-1
                 |       |        |      |      |             |      |
                 +-------+        +------+------+-------------+------+
                 |       |         0x501  0x502
                 | NULL  |
                 |       |
                 +-------+


0xXXX Represents memory address

1.在大多數情況下, argv[0]表示程序名稱,但如果主機環境中沒有程序名稱,則argv[0][0]表示空字符。

直接引用C11 ,章節§5.1.2.2.1/ p2,程序啟動, (強調我的)

int main(int argc, char *argv[]) { /* ... */ }

[...]如果argc的值大於零, 則數組成員argv[0]argv[argc-1]包含指向字符串的指針 ,[...]

[...]和argv數組指向的字符串[...]

因此,基本上, argv是一個指針,指向串音符的陣列的第一個元素。 這可以通過替代形式更清楚,

int main(int argc, char **argv) { /* ... */ }

你可以將它改為指向指向以null結尾的char數組的第一個元素的指針數組的第一個元素的指針,但我更喜歡堅持使用字符串。


注意:

在上面的答案中闡明“指向數組第一個元素的指針”的用法,遵循§6.3.2.1/ p3

除非它是sizeof運算符, _Alignof運算符或一元&運算符的操作數,或者是用於初始化數組的字符串文字,否則將具有類型''數組類型''的表達式轉換為表達式輸入''指向類型'的指針 ,指向數組對象的初始元素,而不是左值。 [...]

這個線程是這樣的火車殘骸。 情況如下:

  • 有一個數組有argc+1 char *類型的元素。
  • argv指向該數組的第一個元素。
  • 還有argc其他類型為char和各種長度的數組,包含表示命令行參數的空終止字符串。
  • 指針數組的元素每個都指向一個char數組的第一個char ; 除了指針數組的最后一個元素,它是一個空指針。

有時候人們會寫“指向X數組的指針”來表示“指向X數組的第一個元素的指針”。 您必須使用上下文和類型來確定它們是否確實意味着它。

對,就是這樣。

argvchar**char*[] ,或者只是char *指針的數組。

所以argv [0]是一個char* (一個字符串),而argv[0][0]是一個char

是。

argv的類型是char** ,即指向char指針。 基本上,如果你認為char*是一個字符串,那么argv是一個指向字符串數組的指針。

argv是一個指向字符的指針數組。

下面的代碼顯示的值argv ,內容argv和執行存儲器上的存儲器轉儲在由內容所指向argv 希望這能說明間接的意義。

#include <stdio.h>
#include <stdarg.h>

print_memory(char * print_me)
{
    char * p;
    for (p = print_me; *p != '\0'; ++p)
    {
        printf ("%p: %c\n", p, *p);
    }

    // Print the '\0' for good measure
    printf ("%p: %c\n", p, *p);

}

int main (int argc, char ** argv) {
    int i;

    // Print argv
    printf ("argv: %p\n", argv);
    printf ("\n");

    // Print the values of argv
    for (i = 0; i < argc; ++i)
    {
        printf ("argv[%d]: %p\n", i, argv[i]);
    }
    // Print the NULL for good measure
    printf ("argv[%d]: %p\n", i, argv[i]);
    printf ("\n");

    // Print the values of the memory pointed at by argv
    for (i = 0; i < argc; ++i)
    {
        print_memory(argv[i]);
    }

    return 0;
}

樣品運行:

$ ./a.out Hello World!
argv: ffbfefd4

argv[0]: ffbff12c
argv[1]: ffbff134
argv[2]: ffbff13a
argv[3]: 0

ffbff12c: .
ffbff12d: /
ffbff12e: a
ffbff12f: .
ffbff130: o
ffbff131: u
ffbff132: t
ffbff133:
ffbff134: H
ffbff135: e
ffbff136: l
ffbff137: l
ffbff138: o
ffbff139:
ffbff13a: W
ffbff13b: o
ffbff13c: r
ffbff13d: l
ffbff13e: d
ffbff13f: !
ffbff140:

$

你有這個大的連續數組,范圍從ffbff12cffbff140 ,它包含命令行參數(這不能保證是標准的連續,但它是如何通常完成的)。 argv只包含指向該數組的指針,因此您可以知道在哪里查找單詞。

argv是指針......指向字符的指針

嚴格來說,要使argv成為數組,必須存在許多屬性。 讓我們考慮其中的一些:

¹/ null 指針不能指向任何數組,因為null 指針保證是不同於任何 object 的地址 因此,以下代碼中的argv不能是數組:

#include <assert.h>
int main(int argc, char *argv[]) {
    if (argv) return main(0, 0);
    assert(argv == 0); // argv is a null pointer, not to be dereferenced
}

²/ 分配給數組是無效的。 例如, char *argv[] = { 0 }; argv++; char *argv[] = { 0 }; argv++; 是違反約束的,但是int main(int argc, char *argv[]) { argv++; } int main(int argc, char *argv[]) { argv++; }編譯並運行良好。 因此,我們必須從這一點得出結論,當聲明為參數時, argv不是數組,而是(可能)指向數組的指針。 (這實際上與第 1 點相同,但來自不同的角度,因為使用 null 指針調用main作為argv實際上是重新分配argv ,這是我們無法對數組執行的操作)。

³/... 正如 C 標准所說:

sizeof 運算符的另一個用途是計算數組中元素的數量:sizeof array / sizeof array[0]

例如:

#include <assert.h>
int main(int argc, char *argv[]) {
    size_t size = argc+1; // including the NULL
    char *control[size];
    assert(sizeof control / sizeof *control == size); // this test passes, because control is actually an array
    assert(sizeof argv   / sizeof *argv    == size); // this test fails for all values of size != 1, indicating that argv isn't an array
}

⁴/ 一元&地址運算符被定義為當應用於數組時,將產生不同類型的相同值,例如:

#include <assert.h>
int main(int argc, char *argv[]) {
    char *control[42];
    assert((void *) control == (void *) &control); // this test passes, because control is actually an array
    assert((void *) argv    == (void *) &argv); // this test fails, indicating that argv isn't an array
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM