[面试] - 常见重写字符串库函数的面试题 - “一网打尽”
传说常见的一个笔试题:不使用中间变量求const字符串长度。函数接口声明如下:int strlen(const char *p);
思路分析:
在字符串中通常可以利用最后一个结束符’\0’,但此处参数为const,只读,那么我们不能打他的主意。
函数运行过程中不占用内存基本不可能,除非都使用了寄存器。“不使用中间变量”只是说程序员不能显示的申请内存而已,即不能有局部变量或者动态内存申请。
如果函数自动申请栈内存或者使用寄存器存储变量,或者使用立即数寻址即常量,那么就相当于“不使用中间变量”。
从函数原型看,返回值为int,那么在函数内部必定需要一个地方存储这个值,要么是常数要么是寄存器。长度不为1时不能一次就求出来,说明必须有递归调用,这样递归时函数会自动申请栈内存,这样就相当于程序员“不使用中间变量”了。中间返回的值通过寄存器自动保存,最后一次返回时拷贝到int中去。C/C++中也有临时对象的概念,都是程序在运行过程中由编译器在栈中自动申请的对象,对程序员不可见,也相当于“不使用中间变量”
这种问题都是利用常量,或者将变量的申请交给编译器在递归过程中自动在栈中申请,也就是借刀杀人了。
思路分析:
在字符串中通常可以利用最后一个结束符’\0’,但此处参数为const,只读,那么我们不能打他的主意。
函数运行过程中不占用内存基本不可能,除非都使用了寄存器。“不使用中间变量”只是说程序员不能显示的申请内存而已,即不能有局部变量或者动态内存申请。
如果函数自动申请栈内存或者使用寄存器存储变量,或者使用立即数寻址即常量,那么就相当于“不使用中间变量”。
从函数原型看,返回值为int,那么在函数内部必定需要一个地方存储这个值,要么是常数要么是寄存器。长度不为1时不能一次就求出来,说明必须有递归调用,这样递归时函数会自动申请栈内存,这样就相当于程序员“不使用中间变量”了。中间返回的值通过寄存器自动保存,最后一次返回时拷贝到int中去。C/C++中也有临时对象的概念,都是程序在运行过程中由编译器在栈中自动申请的对象,对程序员不可见,也相当于“不使用中间变量”
这种问题都是利用常量,或者将变量的申请交给编译器在递归过程中自动在栈中申请,也就是借刀杀人了。
#include <iostream> #include <cstring> using namespace std; char* strcpy(char *dst, const char *src) { char *cp = dst; while(*cp++ = *src++) // 未考虑重叠,重叠的时候从后向前考虑一样! ; /* Copy src over dst */ return dst; } char* strncpy(char *dst, const char *src, size_t num); char* strcat(char *dst, const char *src) { char *cp = dst; while(*cp) ++cp; /* Find end of dst */ while(*cp++ = *src++) ; /* Copy src to end of dst */ return dst; } size_t strlen(const char *str) { size_t len = 0; while(*str++) ++len; return len; } int strcmp(const char *src1, const char *src2) { int ret = 0 ; while(!(ret = *src1 - *src2) && *src2) ++src1, ++src2; if(ret < 0) ret = -1; else if(ret > 0) ret = 1; return ret; } ///------------------------- /// 方法 1 char* strstr(char* str1, const char* str2) { int len = strlen(str2); if(!len) return str1; while(*str1) { if(*str1 == *str2 && strncmp(str1, str2, len) == 0) { return str1; } ++str1; } return NULL; } /// 方法2 char* strstr2(char *str1, const char* str2) { int i; if(*str2) { while(*str1) { for(i = 0; *(str1+i) == *(str2+i); i++) { if(!*(str2+i+1)) return str1; } ++str1; } return NULL; } return str1; } /// 方法3 strstr3 估计kmp可以okay! /* memcpy example */ void* Memcpy(void *dst, const void *src, size_t size) { char *psrc; char *pdst; if(NULL == dst || NULL == src) return NULL; if(src < dst && src + size > dst) { psrc = (char*)src + size - 1; pdst = (char*)dst + size - 1; while(size--) { *pdst-- = *psrc--; } } else { psrc = (char*)src; pdst = (char*)dst; while(size--) { *pdst++ = *psrc++; } } return dst; } int main() { cout << "Hello world!" << endl; return 0; } /* struct { char name[40]; int age; } person, person_copy; int main () { char myname[] = "Pierre de Fermat"; // using memcpy to copy string: memcpy ( person.name, myname, strlen(myname)+1 ); person.age = 46; // using memcpy to copy structure: memcpy ( &person_copy, &person, sizeof(person) ); printf ("person_copy: %s, %d \n", person_copy.name, person_copy.age ); return 0; } */