互联网公司笔试常见陷阱


陷阱分类:

(1)指针与字符串

7.   阅读下面代码,程序会打印出来的值是(D------------------------------(腾讯2014实习生笔试)

  1. void f(char **p)  
  2. {  
  3.     *p += 2;  
  4. }  
  5. void main()  
  6. {  
  7.     char *a[] = { “123”,”abc”,”456”};  
  8.     f(a);  
  9.     printf(“%s\r\n”,*a);  
  10. }  

A.123   B.   abc  C.  456  D.  3

 

  1. void fun1(char **p)  
  2. {  
  3.     *p+=2;  
  4.     cout<<(int)(*p)<<endl;//输出*p保存的地址  
  5. }  
  6.   
  7. void fun2(char *p)  
  8. {  
  9.     p+=2;  
  10. }  
  11.   
  12. int main()  
  13. {     
  14.     char *r[]={"123","234","456"};  
  15.     fun1(r);  
  16.     cout<<int(*r)<<endl; //输出*r保存的地址  
  17.      char *r1="1234";  
  18.     fun2(r1);  
  19.     cout<<*r<<endl<<r1;   
  20.     return 0;  
  21. }  

      图1
从上图1的红框中可看出,*p和*r保存的地址相同,也就*p和*r指向同一地址,如图2所示,*p和*r也就是p1

图2

 

  1. void fun1(char **p)  
  2. {  
  3.     p++;  
  4.     *p+=2;  
  5. }     
  6. int main()  
  7. {     
  8.     char *r[]={"123","234","456"};  
  9.     fun11(r);  
  10.     cout<<*r<<endl<<*(r+1);  
  11.     system("pause");  
  12.     return 0;  
  13. }  

       运行结果为图3, 结合上面的程序和图2所示,P++后,p指向p2,*p+=2后,p2指向4,在主函数中,r就是p1,p1未变所以第一行输出123,(r+1)指向p2,p2已被更新,指向4,所以第二行输出4。


图3

8 下面C++程序的输出是(B//---------------------------------------阿里2014实习生笔试

  1. void f1(char *p)  
  2. {  
  3.     p++;  
  4.     *p='a';  
  5. }  
  6. int main()  
  7. {  
  8.     char a[sizeof("hello")];  
  9.     strcpy(a,"hello");  
  10.     char *a1=a;  
  11.     f1(a);  
  12.     cout<<a<<endl;  
  13.     return 0;  
  14. }  

A hello   B hallo  C allo   D以上都不是

         如图4所示程序中的a用图4中的r表示,p其实只是a的一个副本,p++后,p指向e,将e用a覆盖。但r任然指向H。所以cout<<a,结果是hallo。

 

图4

       若将p改成指针的引用,程序如下所示,则p和r是同一变量,p只不过是r的别名,对p操作即是对r操作。所以有图5的结果。

  1. void f1(char *p)  
  2. {  
  3.     p++;  
  4.     *p='a';  
  5. }  
  6. void f2(char *&p)  
  7. {  
  8.     p++;  
  9.     *p='a';  
  10. }  
  11. int main()  
  12. {  
  13.     char a[sizeof("hello")];  
  14.     strcpy(a,"hello");  
  15.     char *a1=a;  
  16.     f1(a);  
  17.     cout<<a<<endl;  
  18.     strcpy(a,"hello");  
  19.     a1=a;  
  20.     f2(a1);  
  21.     cout<<a1<<endl;  
  22.     system("pause");  
  23.     return 0;  
  24. }  

图5

     另外,若主函数改成如下形式,则,运行出错,无输出,因为指针指向的字符串是常量,不可更改。

  1. int main()  
  2. {  
  3.     char *a="hello";  
  4.     f1(a);  
  5.     cout<<a<<endl;  
  6.     return 0;  
  7. }<span style="font-size:18px;"></span>  

无输出错误为图6:

图6

 

9.   现在有以下两个函数,调用test的结果是(B  //-----------------------腾讯2014实习生笔试

  1. char* getMem(void)  
  2. {        
  3.     Char * p = “hello world ”;  
  4.     P[5] = 0x0;  
  5.     Return p;  
  6. }  
  7. void test(void)   
  8. {        
  9.     char *s = 0x0;  
  10.     s = getMem();  
  11.     Printf(s);  
  12. }  

A.  hello   B. 无输出  C.  Hello0world   D.  不确定

 此题也将出现图6的结果,因为指针指向的字符串,是常量。只读不可写。

(2)虚函数与多态性、构造函数与析构函数

9 32位环境下,以上程序的输出结果是(2014//-----------------------腾讯2014实习生笔试

  1. class Base  
  2. {  
  3. public:  
  4.     virtual int foo(int x){return x*10;}  
  5.     int foo(char x[14]){return sizeof(x)+10;}  
  6. };  
  7. class Derived:public Base  
  8. {  
  9.     int foo(int x){return x*20;}  
  10.     virtual int foo(char x[10]){return sizeof (x)+20;}  
  11. };  
  12. int main(void)  
  13. {  
  14.     Derived  stDerived;  
  15.     Base * pstBase=& stDerived;  
  16.     char x[10];  
  17.     printf(“%d\n”,pstBase->foo(100)+pstBase->foo(x));  
  18.     return 0;  
  19. }  

 

--------------------------------------------2014腾讯实习生笔试题

  1. class Base  
  2. {  
  3. public:  
  4.     Base(){cout << "Base Construction"<<endl;}  
  5.     ~Base(){cout << "Base Destruction"<<endl;}//(2)  
  6. };  
  7. class Derived:public Base  
  8. {  
  9. public:  
  10.     Derived(){ cout << "Derived Construction"<<endl;}  
  11.     ~Derived(){cout << "Derived Destruction"<<endl;}(1)  
  12. };  
  13. int main()  
  14. {     
  15.     Base *base = new Derived();  
  16.     delete base;  
  17.     return 0;  
  18. }  

A先调用(1)再调用(2)  B先调用(2)再调用(1     C只调用(2   D只调用(1

程序运行结果为图7,因此只调用了基类析构函数。如果析构函数不被声明成虚函数,则编译器实施静态绑定,在删除基类指针时,只会调用基类的析构函数而不调用派生类析构函数,这样就会造成派生类对象析构不完全。

图7

若主函数改成如下程序,则运行结果为图8,派生类的指针,delete时,先调用派生类析构函数,再调用基类析构函数。

  1. int main()  
  2. {     
  3.     Base *base = new Derived();  
  4.     delete base;  
  5.     Derived *base1 = new Derived();  
  6.     delete base1;  
  7.     return 0;  
  8. }  

 

图8

若将派生类析构函数改为虚函数,则结果为图9,此时,delete基类指针时,先调用派生类析构函数,再调用基类析构函数。

  1. class Base  
  2. {  
  3. public:  
  4.     Base(){cout << "Base Construction"<<endl;}  
  5.     virtual ~Base(){cout << "Base Destruction"<<endl;}//(2)  
  6. };  

图9

           若将派生类的析构函数改为虚函数,基类的函数为一般析构函数,运行时卡在一个地方。说是内存泄露,不是很明白原因。结果为图10.

  1. class Derived:public Base  
  2. {  
  3. public:  
  4.     Derived(){ cout << "Derived Construction"<<endl;}  
  5.     virtual ~Derived()  
  6.     {cout << "Derived Destruction"<<endl;}  
  7. };  

图10 

         但若再基类加一个虚函数。运行又不卡住,不知是何原因,望求高人指点。结果为图11

  1. class Base  
  2. {  
  3. public:  
  4.     Base(){cout << "Base Construction"<<endl;}  
  5.     ~Base(){cout << "Base Destruction"<<endl;}  
  6.     virtual void foo(){cout<<"Base foo"<<endl;}  
  7. };  
  8. class Derived:public Base  
  9. {  
  10. public:  
  11.     Derived(){ cout << "Derived Construction"<<endl;}  
  12.     virtual ~Derived(){cout << "Derived Destruction"<<endl;}  
  13. };  

图11


-------------------------------------阿里笔试题

  1. class Base  
  2. {  
  3. public:  
  4.     int bar(char x)  
  5.     {  
  6.         return (int)(x);  
  7.     }  
  8.     virtual int bar(int x)  
  9.     {  
  10.         return 2*x;  
  11.     }  
  12. };  
  13. class Derive:public Base  
  14. {   
  15. public:  
  16.     virtual int bar(char x)  
  17.     {  
  18.         return (int)(-x);  
  19.     }  
  20.     int bar(int x)  
  21.     {  
  22.         return x/2;  
  23.     }  
  24. };  
  25. class Derive2:public Derive  
  26. {   
  27. public:  
  28.     int bar(char x)  
  29.     {  
  30.         return (int)(-2*x);  
  31.     }  
  32.     int bar(int x)  
  33.     {  
  34.         return x/4;  
  35.     }  
  36. };  

运行结果为图12,是不是有些出乎意料啊,哈哈

图12

(3)变量所占字节数及存储位置

13.请看一下这一段C++代码,如果编译后程序在windows下运行,则一下说话正确的是(AC)-------------腾讯2014实习生笔试

Char*p1 = “123456”;

Char*p2 = (char*)malloc(10);

A.  P1 p2都存在栈中

B.   P2指向的10个字节内存在栈中

C.  堆和栈在内存中的生长方向是相反的

D.  “123456”6个字符存储在栈

 看了图12,你就懂了。。。。

图13

8.   Char p1[] = “Tencent”, void *p2 = malloc((10)32位机器上sizeof(p1)sizeof(p2)对应的值是(C)  //--------腾讯2014实习生笔试

A.  80   B.   410   C.  8 D.  44

 

2 . 64位系统上,定义的变量int *a[2][3]占据(D)字节  //-------------------阿里2014实习生笔试

A 4    B 12    C 24   D 48

 

(4)时间复杂度

2.   假设函数f1的时间复杂度O(n),那么f1*f1的时间复杂度为(A)

//----------------------------腾讯2014实习生笔试

A.  O(n)   B. O(n*n)   C. O(n*log(n))   D.  以上都不对

这个题真的比较坑爹啊,这里的*是f1的结果相称,不是复杂度相乘,f1就调用了2次,哎。。。。>....<

 

11. 在一台主流配置的PC机上,调用f(35)所需要的时间大概是(C)

//---------------------------------------阿里2014实习生笔试

  1. unsigned long long  cnt=0;  
  2. int f(int x)  
  3. {  
  4.     int s=0;  
  5.     cnt++;  
  6.     while(x--)  
  7.         s+=f(x);  
  8.     return max(s,1);  
  9. }  


A 几毫秒   B几秒  C几分钟   D几小时

分析如下:

f(0)=1,f(1)=1+f(0)=2f(0),f(2)=1+f(1)+f(0)=4f(0),f(3)=1+f(2)+f(1)+f(0)=8f(0),f(n)=2^nf(0),f函数执行2^n次,分析结果正如图14所示。图14所示为:cout<<n<<":   "<<cnt<<"  "<<sum<<"  time:  "<<GetTickCount()-start<<endl;

输出依次为:n的取值、f()的执行次数cntsum的值、程序运行时间(单位ms

图14

图15

实际n=35是,执行次数2^35=34359738368,运行时间为1368031ms约22.8分钟,PC配置为CPU 2G 22

目前主流PC配置为主频3.5G 4核。设指令周期2-5f()执行一次,要执行10条指令左右。因为是4核的,1s钟估测运算3.5G条指令。3.5*10^9/10=100s。这样算,大概只需要2分钟,当然,计算机不可能不做其他事。CPU也不可能100%使用,时间肯定大于2分钟。

(5)输出流执行顺序

图16的结果是不是让你震惊啊,输出流是从右向左运算的。和函数调用参数的运算顺序相同也是从右向左运算的。

 

图16

下面代码的输出,也让人奇怪,后加很好理解,输出流从右向左运算。前加就有点莫名其妙了。结果为图17,反汇编,有点长,不分析了哈。

  1. int n=10;  
  2. cout<<n<<" "<<n++<<" "<<n++<<endl;  
  3. cout<<n<<" "<<n++<<" "<<n++<<" "<<++n<<" "<<++n<<endl;  

图17


(6)函数参数执行顺序

  1. void canshutest(int a,int b)  
  2. {  
  3.     cout<<a<<endl<<b<<endl;  
  4. }  
  5.   
  6. int f1(int a)  
  7. {  
  8.   cout<<"a="<<a<<endl;  
  9.   return a;  
  10. }  
  11.   
  12. int f2(int b)  
  13. {  
  14.     cout<<"b="<<b<<endl;  
  15.     return b;  
  16. }  
  17. int main()  
  18. {     
  19.     int n=10;  
  20.     canshutest(f1(++n),f2(++n));      
  21.     canshutest(n++,n++);  
  22.     canshutest(++n,++n);  
  23.     return 0;  
  24. }  


图18

图19说明如下:

将变量n放入寄存器eax

然后eax+1

再将eax放入变量n

变量n再赋给ecx

ecx+1

ecx再赋给变量n

然后变量n赋给寄存器edx

edx压栈

调用f2

图19

 

图20

 

图21

 

看完以上3张图片,自然就明白了

(7)函数返回值

有以下程序,其执行结果是(B

  1. int test(char a,char b)  
  2. {  
  3.     if (a)  
  4.         return b;  
  5. }  
  6. int main()  
  7. {  
  8.     int a='0',b='1',c='2';  
  9.     printf("%c\n",test(test(a,b),test(b,c)));  
  10.     system("pause");  
  11. }  

A 函数调用出错   B 2   C 0   D 1

 

  1. int test(char a,char b)  
  2. {  
  3.     if (a)  
  4.         return b;  
  5. }  

虽然编译是给出警告,若a0时,函数返回0;并非出错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值