• 互联网公司笔试常见陷阱


            笔者经历了2014年阿里、腾讯的实习生招聘,有些题目,做完了,还以为自己对了,回来编程序跑一下,才知道是陷阱。觉得有必要总结一下哈,在此感谢一下参与讨论的筒子们,小芳,静儿

    陷阱分类:

    (1)指针与字符串

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

    void f(char **p)
    {
    	*p += 2;
    }
    void main()
    {
    	char *a[] = { “123”,”abc”,”456”};
    	f(a);
    	printf(“%s
    ”,*a);
    }

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

     

    void fun1(char **p)
    {
        *p+=2;
        cout<<(int)(*p)<<endl;//输出*p保存的地址
    }
    
    void fun2(char *p)
    {
        p+=2;
    }
    
    int main()
    {   
        char *r[]={"123","234","456"};
        fun1(r);
        cout<<int(*r)<<endl; //输出*r保存的地址
         char *r1="1234";
        fun2(r1);
        cout<<*r<<endl<<r1; 
        return 0;
    }
    
    

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

    图2

    void fun1(char **p)
    {
    	p++;
    	*p+=2;
    }	
    int main()
    {	
    	char *r[]={"123","234","456"};
    	fun11(r);
    	cout<<*r<<endl<<*(r+1);
    	system("pause");
    	return 0;
    }

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


    图3

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

    void f1(char *p)
    {
    	p++;
    	*p='a';
    }
    int main()
    {
    	char a[sizeof("hello")];
    	strcpy(a,"hello");
    	char *a1=a;
    	f1(a);
    	cout<<a<<endl;
    	return 0;
    }

    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的结果。

    void f1(char *p)
    {
    	p++;
    	*p='a';
    }
    void f2(char *&p)
    {
    	p++;
    	*p='a';
    }
    int main()
    {
    	char a[sizeof("hello")];
    	strcpy(a,"hello");
    	char *a1=a;
    	f1(a);
    	cout<<a<<endl;
    	strcpy(a,"hello");
    	a1=a;
    	f2(a1);
    	cout<<a1<<endl;
    	system("pause");
    	return 0;
    }

    图5

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

    int main()
    {
    	char *a="hello";
    	f1(a);
    	cout<<a<<endl;
    	return 0;
    }

    无输出错误为图6:

    图6

     

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

    char* getMem(void)
    {      
    	Char * p = “hello world ”;
    	P[5] = 0x0;
    	Return p;
    }
    void test(void) 
    {      
    	char *s = 0x0;
    	s = getMem();
    	Printf(s);
    }

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

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

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

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

    class Base
    {
    public:
    	virtual int foo(int x){return x*10;}
    	int foo(char x[14]){return sizeof(x)+10;}
    };
    class Derived:public Base
    {
    	int foo(int x){return x*20;}
    	virtual int foo(char x[10]){return sizeof (x)+20;}
    };
    int main(void)
    {
    	Derived  stDerived;
    	Base * pstBase=& stDerived;
    	char x[10];
    	printf(“%d
    ”,pstBase->foo(100)+pstBase->foo(x));
    	return 0;
    }

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

    class Base
    {
    public:
    	Base(){cout << "Base Construction"<<endl;}
    	~Base(){cout << "Base Destruction"<<endl;}//(2)
    };
    class Derived:public Base
    {
    public:
    	Derived(){ cout << "Derived Construction"<<endl;}
    	~Derived(){cout << "Derived Destruction"<<endl;}(1)
    };
    int main()
    {	
    	Base *base = new Derived();
    	delete base;
    	return 0;
    }
    

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

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

    图7

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

    int main()
    {	
    	Base *base = new Derived();
    	delete base;
    	Derived *base1 = new Derived();
    	delete base1;
    	return 0;
    }
    

     

    图8

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

    class Base
    {
    public:
    	Base(){cout << "Base Construction"<<endl;}
    	virtual ~Base(){cout << "Base Destruction"<<endl;}//(2)
    };

    图9

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

    class Derived:public Base
    {
    public:
    	Derived(){ cout << "Derived Construction"<<endl;}
    	virtual ~Derived()
    	{cout << "Derived Destruction"<<endl;}
    };
    

    图10 

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

    class Base
    {
    public:
    	Base(){cout << "Base Construction"<<endl;}
    	~Base(){cout << "Base Destruction"<<endl;}
    	virtual void foo(){cout<<"Base foo"<<endl;}
    };
    class Derived:public Base
    {
    public:
    	Derived(){ cout << "Derived Construction"<<endl;}
    	virtual ~Derived(){cout << "Derived Destruction"<<endl;}
    };

    图11


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

    class Base
    {
    public:
    	int bar(char x)
    	{
    		return (int)(x);
    	}
    	virtual int bar(int x)
    	{
    		return 2*x;
    	}
    };
    class Derive:public Base
    { 
    public:
    	virtual	int bar(char x)
    	{
    		return (int)(-x);
    	}
    	int bar(int x)
    	{
    		return x/2;
    	}
    };
    class Derive2:public Derive
    { 
    public:
    	int bar(char x)
    	{
    		return (int)(-2*x);
    	}
    	int bar(int x)
    	{
    		return x/4;
    	}
    };

    运行结果为图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实习生笔试

    unsigned long long  cnt=0;
    int f(int x)
    {
    	int s=0;
    	cnt++;
    	while(x--)
    		s+=f(x);
    	return max(s,1);
    }
    


    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,反汇编,有点长,不分析了哈。

    	int n=10;
    	cout<<n<<" "<<n++<<" "<<n++<<endl;
    	cout<<n<<" "<<n++<<" "<<n++<<" "<<++n<<" "<<++n<<endl;

    图17


    (6)函数参数执行顺序

    void canshutest(int a,int b)
    {
    	cout<<a<<endl<<b<<endl;
    }
    
    int f1(int a)
    {
      cout<<"a="<<a<<endl;
      return a;
    }
    
    int f2(int b)
    {
    	cout<<"b="<<b<<endl;
    	return b;
    }
    int main()
    {	
    	int n=10;
    	canshutest(f1(++n),f2(++n));	
    	canshutest(n++,n++);
    	canshutest(++n,++n);
    	return 0;
    }


    图18

    图19说明如下:

    将变量n放入寄存器eax

    然后eax+1

    再将eax放入变量n

    变量n再赋给ecx

    ecx+1

    ecx再赋给变量n

    然后变量n赋给寄存器edx

    edx压栈

    调用f2

    图19

     

    图20

     

    图21

     

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

    (7)函数返回值

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

    int test(char a,char b)
    {
    	if (a)
    		return b;
    }
    int main()
    {
    	int a='0',b='1',c='2';
    	printf("%c
    ",test(test(a,b),test(b,c)));
    	system("pause");
    }
    

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

     

    int test(char a,char b)
    {
    	if (a)
    		return b;
    }
    

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

  • 相关阅读:
    dubbo+zookeeper报错:com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method
    CoreException: Could not get the value for parameter compilerId for plugin execution default-compile: PluginResolutionException: Plugin org.apache.maven.plugins:maven-compiler-plugin:3.1
    Spring容器加载配置文件
    Java基础(一)字符串之如何删除指定的字符
    Java基础(二)数组之如何排序数组并插入元素
    Java基础(一)字符串之如何比较字符串
    Spring的事务管理
    Java使用split()截取字符串
    JavaWeb过滤器实现页面跳转至登录页面
    jQuery获取session中的值
  • 原文地址:https://www.cnblogs.com/chhuach2005/p/3961705.html
Copyright © 2020-2023  润新知