今天偶然看到了一個實作strlen函數的方法,也實際練習了一下,挺有意義的,其實作的一些思想值得學習,記錄一下吧。我這裡除了寫兩個比較巧妙的遞歸實作之外,也寫了另外一種正常的方式。
傳說常見的一個筆試題:不使用中間變量求const字元串長度,即實作求字元串長度庫函數strlen函數。函數接口聲明如下:int
strlen(const char *p);
思路分析:
在字元串中通常可以利用最後一個結束符’\0’,但此處參數為const,隻讀,那麼我們不能打他的主意。
函數運作過程中不占用記憶體基本不可能,除非都使用了寄存器。“不使用中間變量”隻是說程式員不能顯示的申請記憶體而已,即不能有局部變量或者動态記憶體申請。
如果函數自動申請棧記憶體或者使用寄存器存儲變量,或者使用立即數尋址即常量,那麼就相當于“不使用中間變量”。
從函數原型看,傳回值為int,那麼在函數内部必定需要一個地方存儲這個值,要麼是常數要麼是寄存器。長度不為1時不能一次就求出來,說明必須有遞歸調用,這樣遞歸時函數會自動申請棧記憶體,這樣就相當于程式員“不使用中間變量”了。中間傳回的值通過寄存器自動儲存,最後一次傳回時拷貝到int中去。C/C++中也有臨時對象的概念,都是程式在運作過程中由編譯器在棧中自動申請的對象,對程式員不可見,也相當于“不使用中間變量”
另外一個不申請任何變量的典型題目是:反轉字元串
這種問題都是利用常量,或者将變量的申請交給編譯器在遞歸過程中自動在棧中申請,也就是借刀殺人了。
無代碼,無真相;簡單的源碼如下:
#include
#include
#include
int myStrlen(const char *str);
int myStrlen1(const char *str);
int myStrlen2(const char *str);
int main()
{
char
*str=NULL;
str = "Hello
Jay!";
printf("original strlen():%d\n",strlen(str));
printf("myStrlen():%d\n",myStrlen(str));
printf("myStrlen1():%d\n",myStrlen1(str));
printf("myStrlen2():%d\n",myStrlen2(str));
}
int myStrlen(const char
*str)
{
if ( (str ==
NULL) || (*str == '\0') ) {
return 0;
}
else
{
return myStrlen(str+1)+1;
}
}
int myStrlen1(const char *str)
{
assert(str
!= NULL);
return *str
? (myStrlen1(++str) + 1) : 0;
}
int myStrlen2(const char *str)
{
if(str==NULL) return 0;
int len =
0;
for(; *str++
!= '\0'; )
{
len++;
}
return
len;
}