2010-01-07 66 views
12

我有下面的代碼片斷:差(* ++的argv)[0]和同時(C = * ++的argv [0])

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

    char line[MAXLINE]; 
    long lineno = 0; 
    int c, except = 0, number = 0, found = 0; 

    while(--argc > 0 && (*++argv)[0] == '-') //These two lines 
     while(c = *++argv[0])     //These two lines 
      switch(c) { 
      case 'x': 
        except = 1; 
        break; 
      case 'n': 
        number = 1; 
        break; 
      default: 
        printf("find: illegal option %c\n", c); 
        argc = 0; 
        found = -1; 
        break; 
      } 

    ... 
} 

含下列表達式:

while(--argc > 0 && (*++argv)[0] == '-') 

是否在括號(*++argv)[0]while(c = *++argv[0])不同,不帶括號這體現在哪裏?

如果是這樣,怎麼樣? (*++argv)表示指向下一個參數的指針,並且*++argv[0]是否指向指向當前char數組中指向的下一個字符的指針?

+0

我也對一件事感興趣: while(c = * ++ argv [0]) 這個表達式。這是否意味着:while(c = * ++ argv [0]!= 0),我的意思是* ++ argv [0]返回一個空指針給c,如果它沒有找到一個字符? – Tool 2010-01-07 14:38:14

+0

是 - 在下面回答。 – 2010-01-07 14:55:54

+0

正如我的回答中所指出的,請參閱K&R在此代碼中的勘誤表條目:http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html – 2010-01-07 15:27:58

回答

36

首先,K & R 1具有在此特定代碼段的勘誤:

117(§5.10):在找到例如,程序增量argv[0]。這並不是專門禁止的,但也不是特別允許的。

現在解釋。

假設您的程序名爲prog,並且您執行它:prog -ab -c Hello World。您希望能夠解析參數,說明指定了選項abc,並且HelloWorld是非選項參數。

argv類型char ** —請記住,函數中的數組參數與指針相同。在程序調用,事情是這樣的:

    +---+   +---+---+---+---+---+ 
argv ---------->| 0 |-------->| p | r | o | g | 0 | 
       +---+   +---+---+---+---+---+ 
       | 1 |-------->| - | a | b | 0 | 
       +---+   +---+---+---+---+ 
       | 2 |-------->| - | c | 0 | 
       +---+   +---+---+---+---+---+---+ 
       | 3 |-------->| H | e | l | l | o | 0 | 
       +---+   +---+---+---+---+---+---+ 
       | 4 |-------->| W | o | r | l | d | 0 | 
       +---+   +---+---+---+---+---+---+ 
       | 5 |-------->NULL 
       +---+ 

這裏,argc是5,argv[argc]NULL。開始時,argv[0]是包含字符串"prog"char *

(*++argv)[0]中,由於括號的存在,argv先遞增,然後解除引用。增量的作用是將該「argv ---------->」箭頭「向下一塊」移動到指向1。取消引用的效果是獲取指向第一個命令行參數-ab的指針。最後,我們取這個字符串的第一個字符([0](*++argv)[0]),並測試它是否爲'-',因爲這表示選項的開始。

對於第二個構造,我們實際上想要走下由當前argv[0]指針指向的字符串。所以,我們需要把argv[0]爲指針,忽視了它的第一個字符(即'-'因爲我們剛剛測試過),並期待在其他字符:

++(argv[0])將增加argv[0],得到一個指向第一個非-字符,並提領它會給我們這個角色的價值。所以我們得到*++(argv[0])。但是因爲在C中,[]++結合的更緊密,所以我們實際上可以擺脫括號並得到我們的表達式*++argv[0]。我們想要繼續處理這個字符,直到它是0(上圖中每行中的最後一個字符框)。

表達

分配給c當前選項的價值,並且具有值cwhile(c)while(c != 0)的簡寫形式,因此while(c = *++argv[0])行基本上將當前選項的值分配給c並對其進行測試以查看是否已達到當前命令行參數的末尾。

在這個循環結束時,ARGV將指向第一個非選項參數:

    +---+   +---+---+---+---+---+ 
       | 0 |-------->| p | r | o | g | 0 | 
       +---+   +---+---+---+---+---+ 
       | 1 |-------->| - | a | b | 0 | 
       +---+   +---+---+---+---+ 
       | 2 |-------->| - | c | 0 | 
       +---+   +---+---+---+---+---+---+ 
argv ---------->| 3 |-------->| H | e | l | l | o | 0 | 
       +---+   +---+---+---+---+---+---+ 
       | 4 |-------->| W | o | r | l | d | 0 | 
       +---+   +---+---+---+---+---+---+ 
       | 5 |-------->NULL 
       +---+ 

這是否幫助?

+0

非常好的解釋。 – 2010-01-07 16:58:34

+0

+1爲美麗的圖片。 – dreamlax 2010-01-15 06:19:28

+0

@Alok你能解釋一下這一步:: if((strstr(line,* argv)!= NULL)!= except)? – 2014-07-04 22:30:25

5

是的,你是對的。

while(--argc > 0 && (*++argv)[0] == '-') 

由一個掃描(長度的argc的)命令行參數之一的陣列尋找那些開始與-選項前綴。對於每個那些:

while(c = *++argv[0]) 

是掃描通過該組的後面的第一-在當前參數(即,在-tntn開關字符,直到遇到串空終止\0,這會終止而循環,因爲它的計算結果爲假。

這種設計允許兩個

myApp -t -n 

myApp -tn 

這兩個工作,並被理解爲有選項tn

+1

此設計非常簡單且最合理,除了事實修改argc和數組argv的內容,這是一種糟糕的設計,因爲它阻止了這些變量的進一步使用。 – 2010-01-07 15:00:17

5

遞增argv是一個非常糟糕的主意,因爲一旦你這樣做了,很難獲得原始值。使用整數索引更簡單,更清晰,更好 - 畢竟argv是一個數組!

回答你的問題++ argv遞增指針。然後,它將間接應用到它以獲取第一個字符。

+0

實際上,間接方式以 - 之後的第一個字符開始,並且每個週期移到下一個週期,以支持單字符後的選項標誌羣。 – 2010-01-07 14:51:35

+0

我指的是(* ++ argv)[0] ==' - ' – 2010-01-07 14:54:32

2

是的,這兩個表達式不同(儘管只是稍微)。國際海事組織,這個代碼是有點過於聰明的一面。你會更好的東西掉這樣的:

for (int i=1; i<argc; i++) 
    if (argv[i][0] == '-') { 
     size_t len = strlen(argv[i]); 
     for (int j=0; j<len; ++j) 
      switch(argv[i][j]) { 
       case 'x': 
       // ... 

這是非常等效於上面的代碼,但我懷疑任何人(誰知道下在所有)將有什麼困難,搞清楚什麼它確實。

+0

但這段代碼不會檢測選項鍊 - 你需要另一個迭代器來選擇鏈--tore – 2010-01-07 14:41:16

+0

@Alex Brown:我相信我已經解決了這個問題 - 雖然我不確定這是否有任何真正的改進。當一個典型的終端是電傳打字機時,允許'-tn'而不是'-t -n'就意味着相當的數量,但這已經不再值得。 – 2010-01-07 14:55:13

+0

@Jerry這完全是值得的。每個命令行用戶都希望能夠在一個組中提供單字母選項,而對代碼的懶惰意味着違反了這些強烈的期望。 這裏的更深層次的問題是這個功能的自定義編碼,而不是使用getopt或類似的。 – Novelocrat 2010-01-07 15:05:58

4

括號改變表達式的評估順序。

沒有括號*++argv[0]

  1. argv[0]獲取指向當前argv指着字符數據。
  2. ++遞增指向字符數組中下一個字符的指針。
  3. *獲得該字符。

帶括號(*++argv)[0]

  1. ++argv遞增的argv指針指向下一個參數。
  2. *取決於它獲得一個指向字符數據的指針。
  3. [0]獲取字符數組中的第一個字符。