C/C++笔试面试(3)

1.下面C++代码输出结果是什么?

 int i=1;

 void main()

{

int i=i;

}


答案:main()里的i是一个未定义的值。



2.下面程序的结果是多少?

#include<iostream>

using namespace std;

int main()

{

int x=2,y,z;

x*=(y=z=5);cout<<x<<endl;

z=3;

x==(y=z);cout<<x<<endl;

x=(y==z);cout<<x<<endl;

x=(y&z);cout<<x<<endl;

x=(y&&z);cout<<x<<endl;

y=4;

x=(y|z);cout<<x<<endl;

x=(y||z);cout<<x<<endl;

return 0;

}


答案:10 10 1 3 1 7 1

表达式详细解释x值
x*=(y=z=5)5赋值给z,z再赋值给y,x=x*y10
x==(y=z)z赋值给y,然后再看想,x,y是否相等。不管相等与否x值不变10
x=(y==z)首先判断y、z是否相等,相等则返回一个布尔值11
x=(y&z)y、z按位与运算3
x=(y&&z)&&是指如果y为真,z为真,则(y&&z)为真,返回一个布尔值11
x=(y|z)按位或运算7
x=(y||z)||表示有一个为真,则y||z为真,返回一个布尔值11

&与运算

y0011
z0011
y&z0011

|或运算

y0100
z0011
y|z0111

^异或运算

y1100
z1001
y^z0101


移位运算>> <<

<<1左移一位表示乘以2
>>1右移一位表示除以2




3.以下代码的结果是多少?

#include <iostream>

using namespace std;

int func(int x)

{

int count=0;

while(x)

{

count++;

x=x&(x-1);

        }

return count;

}

int main()

{

count<<func(9999)<<endl;

return 0;

}

答案:8

详细解析:func函数返回值是形参x转换成二进制后包含1的个数,9999的二进制是10011100001111


拓展题:用一个表达式,判断一个数x是否是2^N次方(2,4,8……),不可用循环语句


解析:2、4、6、8转化成二进制是10、100、1000、10000如果x减1后与x做与运算,答案若是0,则是2^N次方

答案:!(x&(x-1))



4.关于sizeof的一系列题目


4.1下面代码的输出结果是什么?(一维数组、结构体、指针)

#include<iostream>

#include<stdio.h>

#include<string.h>

using namespace std;

struct{

short a1;

short a2;

short a3;

}A;

struct{

long a1;

short a2;

}B;

int main()

{

char* ss1="0123456789";

char ss2[]="0123456789";

char ss3[100]="0123456789";

int ss4[100];

char q1[]="abc";

char q2[]="a\n";

char* q3="a\n";

char *str1=(char *)malloc(100);

void *str2=(void *)malloc(100);

cout<<sizeof(ss1);

cout<<sizeof(ss2);

cout<<sizeof(ss3);

cout<<sizeof(ss4);

cout<<sizeof(q1);

cout<<sizeof(q2);

cout<<sizeof(q3);

cout<<sizeof(A);

cout<<sizeof(B);

cout<<sizeof(str1);

cout<<sizeof(str2);

return 0;   

}


答案:4,11,100,400,4,3,4,6,8,4,4

xxx详细解释sizeof(xxx)
ss1字符指针,指针大小就是一个定值,就是4字节4
ss2最初未定大小的字符数组,10个字节再加上隐含的"\0"(10+1)11
ss3字符数组开始预分配100,大小1*100100
ss4整形数组开始预分配100,大小4*100400
q1类似ss2 3+14
q2同上3
q3字符指针就是定值为44
A关于结构大小参看博客26
B同上8
str1字符指针就是定值为4
4
str2字符指针就是定值为4
4

4.2关于sizeof和strlen差异的题目。

(1)char ss[100]="0123456789";

   sizeof(ss)=1*100

   strlen(ss)=10;//它的内部实现是用一个循环计算字符串的长度,直到"\0"为止。

(2)int ss[100]="0123456789";

   sizeof(ss)=4*100

   strlen(ss)报错,注意strlen的参数只能是char*


4.3下面代码输出结果是多少?

char var[10];

int test(char var[])

{

return sizeof(var);

};

A:10B:9C:11D:4

答案:D

解析:因为var[]等价于*var,已经退化成一个指针了,大小为4

拓展:数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如fun(char[8])、fun(char [])都等价于fun(char *);;对函数使用sizeof,在编译阶段会被函数返回类型取代如:

int f1(){return 0;}

cout<<sizeof(f1())<<endl;//f1返回值为int,因此被认为是int


     4.4(1)int **a[3][4]数组占据多大空间?(二维数组、unsigned、自定义类型)
sizeof(a)=3*4*4=48
(2) unsigned影响只是最高位bit的意义(正负),数据长度不会被改变的。所以:

sizeof(unsigned int)==sizeof(int)

(3)自定义类型的sizeof取值等同于它的类型原型

typedef short WORD;

sizeof(short)==sizeof(WORD)


4.5找出下面程序的错误,并解释它为什么是错的?

#include<iostream>

#include<string>

using namespace std;

int main(int argc,char *argv[])

{

//为输出"TrendMicroSoftUSCN"

string strArr1[]={"Trend","Micro","Soft"};

string *pStrArr1=new string[2];

`pStrArr1[0]="US";

pStrArr1[1]="CN";

for(int i=0;i<sizeof(strArr1)/sizeof(string);i++)

cout<<strArr1[i];

for(int j=0;j<sizeof(pStrArr1)/sizeof(string);j++)

cout<<pStrArr1[j];

return 0;

}

程序运行后输出:TrendMicroSoftUS

原因:sizeof(strArr1)=12;sizeof(pStrArr1)=4即指针大小当然不能正常输出;

应该为:for(int j=0;j<sizeof(pStrArr1)*2/sizeof(string);j++)


4.6类、继承、虚函数等中的sizeof问题

(1)写出下面sizeof的答案。

#include<iostream>

#include<complex>

using namespace std;

class Base

{

public:

Base(){cout<<"Base-ctor"<<endl;}

~Base(){cout<<"Base-dtor"<<endl;}

virtual void f(int){cout<<"Base::f(int)"<<endl;}

virtual void f(double){cout<<"Base::f(double)"<<endl;}

virtual void g(int i=10){cout<<"Base::g()"<<i<<endl;}

void g2(int i=10){cout<<"Base::g2()"<<i<<endl;}

};

class Derived:public Base

{

public:

Derived(){cout<<"Derived-ctor"<<endl;}

~Derived(){cout<<"Derived-dtor"<<endl;}

void f(complex<double>){cout<<"Derived::f(complex)"<<endl;}

virtual void g(int i=20){cout<<"Derived::g()"<<i<<endl;}

};

int main()

{

Base b;

Derived d;

Base* pb=new Derived;

cout<<sizeof(Base)<<endl;//答案:4

cout<<sizeof(Derived)<<endl;//答案:4

}


(2)一个空类占多少空间?多重继承的空类呢?

#include<iostream>

#include<memery.h>

#include<assert.h>

using namespace std;

class A

{

};

class A2

{

};

class B:public A

{

};

class C:public virtual B

{

};

class D:public A,public A2

{

};

int main()

{

cout<<sizeof(A)<<endl;//1

cout<<sizeof(B)<<endl;//1

cout<<sizeof(C)<<endl;//4

cout<<sizeof(D)<<endl;//1

}

空类所占空间是1,单一继承1,多重继承1,虚函数涉及虚指针大小为4

5.下面两段代码输出结果有什么不同?


第1段:

#include<iostream>

using namespace std;

int main()

{

int a,x;

for(a=0,x=0;a<=1&&!x++;a++)

{

a++;

        }

cout<<a<<x<<endl;

return 0;

}


第2段:

#include<iostream>

using namespace std;

int main()

{

int a,x;

for(a=0,x=0;a<=1&&!x++;)

        {

a++;

}

cout<<a<<x<<endl;

return 0;

}


第1段输出结果:21

第2段输出结果:12


详细解析:

执行第1段代码第2段代码
第一步初始化定义a=0,x=0初始化定义a=0,x=0
第二步a小于等于1,x的非为1,符合循环条件a小于等于1,x的非为1,符合循环条件
第三步x++后x自增为1x++后x自增为1
第四步进去循环体,a++,a自增为1进去循环体,a++,a自增为1
第五步执行for(a=0,x=0;a<=1&&!x++;a++)中a++,a自增为2a现在是1符合小于等于1条件,x现在是1,x的非为0,不执行循环体,但x++依然执行自增为2
第六步a现在是2,已经不符合小于等于1条件了“&&”后的“!x++”不执行x还是1不执行循环体打印12



6.面试笔试中两个数a和b的问题

(1)有两个变量a和b,不用“if”,"?:","switch"或其他判断语句,找出两个数中比较大的数。

答案:int max=((a+b)+abs(a-b))/2


(2)将a和b的值进行交换,并且不使用任何中间变量。

答案:a=a^b;

     b=a^b;

     a=a^b;


亦可以这么做不过会有a=a+b超界问题:

a=a+b;

b=a-b;

a=a-b;




7.笔试面试中需要注意的一些常识性问题

(1).在C++程序中调用C编译器编译后函数,为什么要加extern “C”?

答:C++提供了C连接交换指定符号extern “C”解决了名字匹配问题

原因:C++支持函数重载,C不支持函数重载。函数被C++编译后在库中名字与C语言不同。假设某个函数原型为

void foo(int x,int y),该函数被C编译器编译后在库中名字为_foo,而在C++编译器中编译则会产 生像_foo_int_int之类的名字


(2).头文件中的ifndef/define/endif是干什么用的?

答:防止头文件被重复引用。

(3)*(ptr++)+=123;等价于*ptr=*ptr+123;ptr++;


(4)const那些事儿:

可以用const修饰对象、数据成员和成员函数;常数据成员只能由构造函数由初始化列表对其进行初始化;常对象只能调用类的常成员函数,不能调用非常成员函数;

const有什么用途?

答案:(1)可以定义const变量(2)const可以修饰函数参数和返回值,甚至函数定义体。被const修饰的东西都受到了强制保护,可以预防意外变动,能提高程序健壮性。

注意:const常量赋值时必需同时初始化。const double di=10.0;//正确

                                const double  di;//错误没有初始化 

拓展:const与#define相比有什么不同

C++程序中只使用const常量而不使用宏常量C迫使程序员在预处理里使用#define,前者比后者有更多的优点:(1)const有数据类型,而宏常量没有数据类型(2)有的调试工具可以对const常量进行调试,但不能对宏常量进行调试。另外,在const成员函数中,用mutable修饰成员变量名后,就可以修改类的成员变量了。


(5)内联函数和宏的差别是什么?

答案:内联函数和普通函数相比可以加快程序的运行速度,因为不需要中断调用,在编译的时候内联函数可以直接被镶嵌到目标代码中。而宏只是一个简单地替换。

拓展:inline函数一般只用于如下情况:

(1)一个函数不断被重复调用

(2)函数只有简单地几行,且函数内不包含for、while、switch语句


(6)指针和引用的差异。

答案:1.非空区别。声明一个引用,但引用不能为空,必须同时初始化,不可以使用指向空值引用,因此代码效率比使用指针高。

例如:int iv;   int &reiv=iv;//正确!

     int &reiv;//错误用法 声明一个引用必须进行初始化。

     2.合法性区别。使用引用不需要测试合法性。

     3.可修改区别。指针可以被重新赋值指向另一个对象。


(7)C++有了malloc/free,为什么还要用new/delete?

答案:malloc与free是C/C++标准库函数,new/delete是C++运算符。他们都可以申请动态内存和释放内存。对非内部数据类型的对象而言,只用malloc/free无法满足动态对象的要求。

new/delete知多少:

运算符new可以用来动态创建对象和对象数组;使用new创建对象时会调用类的构造函数,也可以用delete析构;

8.面试中预处理问题


8.1用一个宏定义FIND求一个结构体struc里某个变量相对struc的偏移量

{

int a;

char b[20];

double ccc;

}

则:FIND(student,a);//等于0

   FIND(student,b);//等于4


答案:#define FIND(struc,e) (size_t)&(((struc*)0)->e)

解析:其中(struc*)0表示将常量0强制转化为struc*型指针所指向的地址;&(((struc*)0)->e)表示取结构体(struc*)0的成员e的地址,因为该结构体的首地址为0,所以其实就是得到了成员e距离结构体首地址的偏移量。(size_t)是一种数据类型,为了便于不同系统之间移植,最好定义为一种无符号型数据,一般为unsigned int.


8.2写一个标准宏定义MIN,这个宏定义输入两个参数并返回较小的一个。

答案:#define MIN(A,B) ((A)<=(B)?(A):(B))


8.3下面程序的运行结果是什么?

#include<stdio.h>

# define ADD(x) x+x

void main()

{

int m=1,n=2,k=3;

int sum=ADD(m+n)*k;

printf("%d",sum);

}

输出结果:10

注意:宏定义表达式最好都加上括号,只是简单的代码兑换;本代码中ADD(m+n)替换为m+n+m+n,没有括号就是m+n+m+n*k=10










  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值