2012-06-10 116 views
2
#include <stdio.h> 
#include <stdlib.h> 

void reprint(char *a[]) { 
    if(*a) { 
      printf("%d ",a); 
      reprint(a+1); 
      printf("%s ",*a); 
    } 
} 

int main() { 
    char *coll[] = {"C", "Objective", "like", "don't", "I", NULL}; 
    reprint(coll); 
    printf("\n"); 
    return EXIT_SUCCESS; 
} 

正如更有經驗的人會知道,這反向打印數組。我不太明白!有人可以爲我解釋這個遞歸函數嗎?

我需要幫助瞭解什麼是reprint(char *a[])。我理解指針算術的程度,但是從插入printf s,我已經確定函數遞增到數組末尾,然後返回到開始處,僅在下降時打印。但是,我不明白它是如何做到這一點的;我通過查看實際代碼所能理解的是,如果*a不是NULL,那麼請在下一個索引再次調用reprint。

+0

'printf(「%d」,a);'是未定義的行爲,因爲'a'是一個指針而不是int – user411313

+0

@ user411313 - 是的,這是一個意外,要成爲* a –

+0

@capncoolio並不能真正解決user411313發出的問題,但可以使用%p打印指針。 – fvu

回答

1

瞭解這種遞歸類型的關鍵是瞭解堆棧如何工作。第一:每次reprint()用(a + 1)調用自己,然後將a + 1壓入堆棧。這意味着被調用的reprint()獲取char **的一個副本作爲參數。呼叫轉載的'a'沒有被觸及。就像你說的那樣,直到通過的char **爲NULL,即數組中的最後一個元素爲止。然後測試'if(* a)'變成錯誤,重印將不會被調用更深。

請注意,在這一點上,所有5次重印的調用都是'等待'它的返回,所以在遞歸調用重印後沒有printf的調用尚未被調用。另請注意,所有5個呼叫都有自己的'a'指針。這是至關重要的。

現在,由於轉載的最後一次調用不再調用重新打印,它只會返回。第二次到最後一次重印,其中一個'a'指向字符串「I」,然後可以繼續調用重印後的下一個語句,即「I」的printf。一旦完成,此功能也會返回。第三次到最後一次轉載,一個'a'指向字符串「不」,然後也可以繼續並打印「不要」,等等......

+0

所以我看到的方式是[鏈接](http://tinypic.com/r/2z9f9so/6) 我是否正確? –

+0

準確地說,你明白了。 – Pat

+0

非常感謝! –

6

理解函數輸出的關鍵是它將在遞歸之前打印指針,並在遞歸之後打印實際字符串。這就是讓你有兩次經歷的印象。

也許這聽起來很愚蠢,但手動執行程序(或使用調試器)。一旦它進入重印功能,它會在printf("%d ",a);之後打到自己的電話,所以它會首先「爬」到NULL。只有這樣纔會遇到printf("%s ",*a);系列。

修改你的程序是這樣的,它應該可以幫助你理解發生了什麼。

#include <stdio.h> 
#include <stdlib.h> 

static int callcounter = 1; 

void reprint(char *a[]) { 
    printf ("Entering reprint for the %d time\n",callcounter++); 
    if(*a) { 
      printf("%p ",a); 
      reprint(a+1); 
      printf("%s ",*a); 
    } 
    printf ("Exiting reprint\n"); 
} 

int main() { 
    char *coll[] = {"C", "Objective", "like", "don't", "I", NULL}; 
    reprint(coll); 
    printf("\n"); 
    return EXIT_SUCCESS; 
} 
+0

謝謝!這有很大的幫助:D –

1

遞歸使用堆棧。堆棧是具有LIFO行爲的數據結構。 reprint在實際打印單詞前將被調用6次。

+0

後進先出? –

+0

@capncoolio是 –

3

對函數的遞歸調用留下指向堆棧上函數的其餘部分的指針。 Yoy可能會認爲它是在遞歸調用完成之後要做的事情列表。

最初,這個堆棧可能被認爲是空的。調用序列後,你會得到一個堆棧看起來像這樣:

1st call: reprint ("C", "objective", "like", "don't", "I", NULL); 
    2nd call: reprint ("objective", "like", "don't", "I", NULL);printf("C"); 
    3rd call: reprint ("like", "don't", "I", NULL);printf("objective"); 
                printf("C"); 
    ... 
    6th call: reprint(NULL); printf("I");printf("don't");printf("like"); 
          printf("objective");printf("C"); 

現在堆棧自身鬆開每串正在以正確的順序輸出。

+0

非常感謝,您的意見非常寶貴。這讓我相當難過,成爲新手! –

0

while * a!= 0(NULL) 一個調用重印是發送一個+ 1,這意味着在字符數組中的下一個地方, ,直到最後一個元素(NULL)被調用, 函數只是回到它的返回地址,這是line: printf(「%s」,* a); 並且在這個框架中* a是「I」, 然後函數完成執行並且再次返回到它的'返回地址的同一行,在這個激活框架中* a是「不」,等等返回地址是printf(「\ n」); 執行然後結束主線

相關問題