常見的一個筆試題:不使用中間變量求const字符串長度,即實現求字符串長度庫函數strlen函數。函數接口聲明如下:
1 int strlen(const char *p);
在字符串中通常可以利用最后一個結束符’\0’,但此處參數為const,只讀,那么我們不能打他的主意。
函數運行過程中不占用內存基本不可能,除非都使用了寄存器。“不使用中間變量”只是說程序員不能顯示的申請內存而已,即不能有局部變量或者動態內存申請。
如果函數自動申請棧內存或者使用寄存器存儲變量,或者使用立即數尋址即常量,那么就相當於“不使用中間變量”。
從函數原型看,返回值為int,那么在函數內部必定需要一個地方存儲這個值,要么是常數要么是寄存器。長度不為1時不能一次就求出來,說明必須有遞歸調用,這樣遞歸時函數會自動申請棧內存,這樣就相當於程序員“不使用中間變量”了。中間返回的值通過寄存器自動保存,最后一次返回時拷貝到int中去。C/C++中也有臨時對象的概念,都是程序在運行過程中由編譯器在棧中自動申請的對象,對程序員不可見,也相當於“不使用中間變量”
另外一個不申請任何變量的典型題目是:反轉字符串
這種問題都是利用常量,或者將變量的申請交給編譯器在遞歸過程中自動在棧中申請,也就是借刀殺人了。
無代碼,無真相;簡單的源碼如下:
1 #include "stdafx.h" 2 #include <stdio.h> 3 #include <string.h> 4 #include <assert.h> 5 6 int myStrlen(const char *str); 7 int myStrlen1(const char *str); 8 int myStrlen2(const char *str); 9 10 int main() 11 { 12 char *str=NULL; 13 str = "Hello world!"; 14 printf("original strlen():%d\n",strlen(str)); 15 printf("myStrlen():%d\n",myStrlen(str)); 16 printf("myStrlen1():%d\n",myStrlen1(str)); 17 printf("myStrlen2():%d\n",myStrlen2(str)); 18 } 19 20 int myStrlen(const char *str) /* 不用中間變量,用遞歸實現,很容易看懂 */ 21 { 22 if ( (str == NULL) || (*str == '\0') ) { 23 return 0; 24 } 25 else { 26 return myStrlen(str+1)+1; 27 } 28 } 29 30 int myStrlen1(const char *str) /* 不用中間變量,也是用遞歸實現,寫得更簡潔而已 */ 31 { 32 assert(str != NULL); 33 return *str ? (myStrlen1(++str) + 1) : 0; 34 } 35 36 int myStrlen2(const char *str) /* 使用了一個int型變量 */ 37 { 38 if(str==NULL) return 0; 39 int len = 0; 40 for(; *str++ != '\0'; ) 41 { 42 len++; 43 } 44 return len; 45 }