C++面试题
转自:http://blog.csdn.net/ljzcome/archive/2006/01/09/574158.aspx
1.是不是一个父类写了一个virtual 函数,如果子类覆盖它的函数不加virtual ,也能实现多态?
virtual修饰符会被隐形继承的。private 也被集成,只事派生类没有访问权限而已virtual可加可不加子类的空间里有父类的所有变量(static除外)同一个函数只存在一个实体(inline除外)子类覆盖它的函数不加virtual ,也能实现多态。在子类的空间里,有父类的私有变量。私有变量不能直接访问。
--------------------------------------------------------------------------
2.输入一个字符串,将其逆序后输出。(使用C++,不建议用伪码)
#include
using namespace std;
void main()
{
char a[50];
memset(a,0,sizeof(a));
int i=0,j;
char t;
cin.getline(a,50,'/n');
for(i=0,j=strlen(a)-1;
i<<>str;
str.replace;
cout<a /= (k+m)*1*(k+m);
=>a = a/9;
=>a = 1;
}
--------------------------------------------------------------------------
5.const 符号常量;(1)const char *p(2)char const *p(3)char * const p说明上面三种描述的区别;
如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。
(1)const char *p一个指向char类型的const对象指针,p不是常量,我们可以修改p的值,使其指向不同的char,但是不能改变它指向非char对象,如:const char *p;char c1='a';char c2='b';p=&c1;//okp=&c2;//ok*p=c1;//error
(2)char const *p
(3)char * const p这两个好象是一样的,此时*p可以修改,而p不能修改。
(4)const char * const p这种是地址及指向对象都不能修改。
--------------------------------------------------------------------------
6.下面是C语言中两种if语句判断方式。请问哪种写法更好?为什么?
int n;
if (n == 10) // 第一种判断方式
if (10 == n) // 第二种判断方式如果少了个=号,编译时就会报错,减少了出错的可能行,可以检测出是否少了
=
--------------------------------------------------------------------------
7.下面的代码有什么问题?
void DoSomeThing(...)
{
char* p;
... p = malloc(1024); // 分配1K的空间
if (NULL == p)
return;
... p = realloc(p, 2048);
// 空间不够,重新分配到2K
if (NULL == p) return;
...
}
A:p = malloc(1024); 应该写成: p = (char *) malloc(1024); 没有释放p的空间,造成内存泄漏。
--------------------------------------------------------------------------
8.下面的代码有什么问题?
并请给出正确的写法。
void DoSomeThing(char* p)
{
char str[16];
int n;
assert(NULL != p);
sscanf(p, "%s%d", str, n);
if (0 == strcmp(str, "something"))
{ ... }
A:sscanf(p, "%s%d", str, n); 这句该写成: sscanf(p, "%s%d", str, &n);
--------------------------------------------------------------------------
9.下面代码有什么错误?
Void test1()
{
char string[10];
char *str1="0123456789";
strcpy(string, str1);
}
数组越界
--------------------------------------------------------------------------
10.下面代码有什么问题?
Void test2()
{
char string[10], str1[10];
for(i=0; i<10;i++)
{
str1[i] ='a';
}
strcpy(string, str1);
}
数组越界,使用strcpy 函数时,是以/n为结束标志,而该串没有"/n"标志,所以造成越界问题。
--------------------------------------------------------------------------
11.下面代码有什么问题?
Void test3(char* str1)
{
char string[10];
if(strlen(str1)<=10)
{
strcpy(string, str1);
}
}
==数组越界
==strcpy拷贝的结束标志是查找字符串中的/0 因此如果字符串中没有遇到/0的话 会一直复制,直到遇到/0,上面的123都因此产生越界的情况 建议使用 strncpy 和 memcpy
--------------------------------------------------------------------------
12.下面代码有什么问题?
#define MAX_SRM 256
DSN get_SRM_no()
{
static int SRM_no;//是不是这里没赋初值?
int I;
for(I=0;I=MAX_SRM)
return (NULL_SRM);
else
return SRM_no;
}
系统会初始化static int变量为0,但该值会一直保存,所谓的不可重入...
--------------------------------------------------------------------------
13.写出运行结果:
{
// test1
char str[] = "world";
cout << sizeof(str) << ": ";
char *p = str;
cout << sizeof(p) << ": ";
char i = 10;
cout << sizeof(i) << ": ";
void *pp = malloc(10);
cout << sizeof(p) << endl;
}
6:4:1:4
--------------------------------------------------------------------------
14.写出运行结果:
{
// test2
union V {
struct X {
unsigned char s1:2;
unsigned char s2:3;
unsigned char s3:3;
} x;
unsigned char c;
} v;
v.c = 100;
printf("%d", v.x.s3);
}
3
--------------------------------------------------------------------------
15.用C++写个程序,如何判断一个操作系统是16位还是32位的?不能用sizeof()函数
A1:16位的系统下,int i = 65536;cout << i; // 输出0;int i = 65535;cout << i; // 输出-1;
32位的系统下,int i = 65536;cout << i; // 输出65536;int i = 65535;cout << i; // 输出65535;
A2:int a = ~0;if( a>65536 ){
cout<<"32 bit"<<<"16 bit"<
void main()
{
int i=60;
int j=50;
i=i+j;
j=i-j;
i=i-j;
printf("i=%d/n",i);
printf("j=%d/n",j);
}
方法二:i^=j;j^=i;i^=j;
方法三:// 用加减实现,而且不会溢出a = a+b-(b=a)
--------------------------------------------------------------------------
18.有关位域的面试题(为什么输出的是一个奇怪的字符)
a.t = 'b';
效果相当于 a.t= 'b' & 0xf;
'b' --> 01100010'b' & 0xf -->>00000010
所以输出Ascii码为2的特殊字符char t:4;
就是4bit的字符变量,同样unsigned short i:8;
就是8bit的无符号短整形变量
--------------------------------------------------------------------------
19.
int i=10, j=10, k=3;
k*=i+j;
k最后的值是?
60
--------------------------------------------------------------------------
20.进程间通信的方式有?
进程间通信的方式有 共享内存, 管道 ,Socket ,消息队列 , DDE等
--------------------------------------------------------------------------
21.struct A{
char t:4;
char k:4;
unsigned short i:8;
unsigned long m;
}
sizeof(A)=?(不考虑边界对齐)
7struct CELL // Declare CELL bit field{ unsigned character : 8; // 00000000 ???????? unsigned foreground : 3; // 00000??? 00000000 unsigned intensity : 1; // 0000?000 00000000 unsigned background : 3; // 0???0000 00000000 unsigned blink : 1; // ?0000000 00000000} screen[25][80]; // Array of bit fields二、位结构 位结构是一种特殊的结构, 在需按位访问一个字节或字的多个位时, 位结构比按位运算符更加方便。 位结构定义的一般形式为: struct位结构名{ 数据类型 变量名: 整型常数; 数据类型 变量名: 整型常数; } 位结构变量; 其中: 数据类型必须是int(unsigned或signed)。 整型常数必须是非负的整数, 范围是0~15, 表示二进制位的个数, 即表示有多少位。 变量名是选择项, 可以不命名, 这样规定是为了排列需要。 例如: 下面定义了一个位结构。 struct{ unsigned incon: 8; /*incon占用低字节的0~7共8位*/ unsigned txcolor: 4;/*txcolor占用高字节的0~3位共4位*/ unsigned bgcolor: 3;/*bgcolor占用高字节的4~6位共3位*/ unsigned blink: 1; /*blink占用高字节的第7位*/ }ch; 位结构成员的访问与结构成员的访问相同。 例如: 访问上例位结构中的bgcolor成员可写成: ch.bgcolor
注意: 1. 位结构中的成员可以定义为unsigned, 也可定义为signed, 但当成员长度为1时, 会被认为是unsigned类型。因为单个位不可能具有符号。 2. 位结构中的成员不能使用数组和指针, 但位结构变量可以是数组和指针,如果是指针, 其成员访问方式同结构指针。
3. 位结构总长度(位数), 是各个位成员定义的位数之和, 可以超过两个字节。
4. 位结构成员可以与其它结构成员一起使用。 例如: struct info{ char name[8]; int age; struct addr address; float pay; unsigned state: 1; unsigned pay: 1; }workers; 上例的结构定义了关于一个工人的信息。其中有两个位结构成员, 每个位结构成员只有一位, 因此只占一个字节但保存了两个信息, 该字节中第一位表示工人的状态, 第二位表示工资是否已发放。由此可见使用位结构可以节省存贮空间。
--------------------------------------------------------------------------
22.下面的函数实现在一个固定的数上加上一个数,有什么错误,
改正int add_n(int n){ static int i=100; i+=n; return i;}
答:因为static使得i的值会保留上次的值。去掉static就可了
--------------------------------------------------------------------------
23.下面的代码有什么问题?
class A
{
public:
A()
{
p=this;
}
~A()
{
if(p!=NULL)
{
delete p;
p=NULL;
}
}
A* p;
};
答:会引起无限递归
--------------------------------------------------------------------------
24.union a {
int a_int1;
double a_double;
int a_int2;
};
typedef struct{
a a1;
char y;
} b;
class c{
double c_double;
b b1;
a a2;
};
输出cout<<(j++) && (i++ == j)) i+=j;
答:i = 5
--------------------------------------------------------------------------
26.unsigned short array[]={1,2,3,4,5,6,7};
int i = 3;
*(array + i) = ?
答:4
--------------------------------------------------------------------------
27.class A{
virtual void func1();
void func2();
}
Class B:
class A{
void func1(){
cout << "fun1 in class B" << endl;
}
virtual void func2(){
cout << "fun2 in class B" << endl;
}
}
A, A中的func1和B中的func2都是虚函数.
B, A中的func1和B中的func2都不是虚函数.
C, A中的func2是虚函数.,B中的func1不是虚函数.
D, A中的func2不是虚函数,B中的func1是虚函数.
答:A
--------------------------------------------------------------------------
28.数据库:抽出部门,平均工资,要求按部门的字符串顺序排序,不能含有"human resource"部门,employee结构如下:employee_id, employee_name, depart_id,depart_name,wage答:select depart_name, avg(wage)from employeewhere depart_name <> 'human resource'group by depart_nameorder by depart_name
--------------------------------------------------------------------------
29.给定如下SQL数据库:Test(num INT(4)) 请用一条SQL语句返回num的最小值,但不许使用统计功能,如MIN,MAX等答:select top 1 numfrom Testorder by num desc
--------------------------------------------------------------------------
30.输出下面程序结果。
#include
class A{
public:
virtual void print(void)
{
cout<<"A::print()"<<<"B::print()"<<<"C::print()"<print();
pb->print();
pc->print();
print(a);
print(b);
print(c);
}
A:A::print()
B::print()
C::print()
A::print()
B::print()
C::print()
A::print()
A::print()
A::print()
--------------------------------------------------------------------------
31.试编写函数判断计算机的字节存储顺序是开序(little endian)还是降序(bigendian)
答:bool IsBigendian(){
unsigned short usData = 0x1122;
unsigned char *pucData = (unsigned char*)&usData;
return (*pucData == 0x22);
}
--------------------------------------------------------------------------
32.简述Critical Section和Mutex的不同点答:对几种同步对象的总结1.Critical SectionA.速度快B.不能用于不同进程C.不能进行资源统计(每次只可以有一个线程对共享资源进行存取)2.MutexA.速度慢B.可用于不同进程C.不能进行资源统计3.SemaphoreA.速度慢B.可用于不同进程C.可进行资源统计(可以让一个或超过一个线程对共享资源进行存取)4.EventA.速度慢B.可用于不同进程C.可进行资源统计
--------------------------------------------------------------------------
33.一个数据库中有两个表:一张表为Customer,含字段ID,Name;一张表为Order,含字段ID,CustomerID(连向Customer中ID的外键),Revenue;写出求每个Customer的Revenue总和的SQL语句。建表create table customer(ID int primary key,Name char(10))gocreate table [order](ID int primary key,CustomerID int foreign key references customer(id) , Revenue float)go--查询select Customer.ID, sum( isnull([Order].Revenue,0) )from customer full join [order]on( [order].customerid=customer.id )group by customer.id
--------------------------------------------------------------------------
34.请指出下列程序中的错误并且修改void GetMemory(char *p){ p=(char *)malloc(100);}void Test(void){ char *str=NULL; GetMemory=(str); strcpy(str,"hello world"); printf(str);}A:错误--参数的值改变后,不会传回GetMemory并不能传递动态内存,Test函数中的 str一直都是 NULL。strcpy(str, "hello world");将使程序崩溃。修改如下:char *GetMemory(){ char *p=(char *)malloc(100); return p;}void Test(void){ char *str=NULL; str=GetMemory(){ strcpy(str,"hello world"); printf(str);}方法二:void GetMemory2(char **p)变为二级指针.void GetMemory2(char **p, int num){ *p = (char *)malloc(sizeof(char) * num);}
--------------------------------------------------------------------------
35.程序改错class mml{ private: static unsigned int x; public: mml(){ x++; } mml(static unsigned int &) {x++;} ~mml{x--;} pulic: virtual mon() {} = 0; static unsigned int mmc(){return x;} ...... };class nnl:public mml{ private: static unsigned int y; public: nnl(){ x++; } nnl(static unsigned int &) {x++;} ~nnl{x--;} public: virtual mon() {}; static unsigned int nnc(){return y;} ...... };代码片断:mml* pp = new nnl;..........delete pp;A:基类的析构函数应该为虚函数virtual ~mml{x--;}
--------------------------------------------------------------------------
36.101个硬币100真、1假,真假区别在于重量。请用无砝码天平称两次给出真币重还是假币重的结论。答:101个先取出2堆,33,33第一次称,如果不相等,说明有一堆重或轻那么把重的那堆拿下来,再放另外35个中的33如果相等,说明假的重,如果不相等,新放上去的还是重的话,说明假的轻(不可能新放上去的轻)第一次称,如果相等的话,这66个肯定都是真的,从这66个中取出35个来,与剩下的没称过的35个比下面就不用说了方法二:第3题也可以拿A(50),B(50)比一下,一样的话拿剩下的一个和真的比一下。如果不一样,就拿其中的一堆。比如A(50)再分成两堆25比一下,一样的话就在B(50)中,不一样就在A(50)中,结合第一次的结果就知道了。
--------------------------------------------------------------------------
37.static变量和static 函数各有什么特点?
答:static变量:在程序运行期内一直有效,如果定义在函数外,则在编译单元内可见,如果在函数内,在在定义的block内可见;
static函数:在编译单元内可见;
--------------------------------------------------------------------------
38.用C 写一个输入的整数,倒着输出整数的函数,要求用递归方法 ;
答:void fun( int a )
{
printf( "%d", a%10 );
a /= 10;
if( a <=0 )
return;
fun( a );
}
--------------------------------------------------------------------------
39.写出程序结果:void Func(char str[100])
{
printf("%d/n", sizeof(str));
}
答:4分析:指针长度
--------------------------------------------------------------------------
40.int id[sizeof(unsigned long)]; 这个对吗?为什么??
答:对这个 sizeof是编译时运算符,编译时就确定了可以看成和机器有关的常量。本文主要包括二个部分,第一部分重点介绍在VC中,怎么样采用sizeof来求结构的大小,以及容易出现的问题,并给出解决问题的方法,第二部分总结出VC中sizeof的主要用法。
1、 sizeof应用在结构上的情况请看下面的结构:
struct MyStruct{
double dda1;
char dda;
int type
};
对结构MyStruct采用sizeof会出现什么结果呢?
sizeof(MyStruct)为多少呢?
也许你会这样求:sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13但是当在VC中测试上面结构的大小时,你会发现sizeof(MyStruct)为16。
你知道为什么在VC中会得出这样一个结果吗?其实,这是VC对变量存储的一个特殊处理。为了提高CPU的存储速度,VC对一些变量的起始地址做了"对齐"处理。在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式(vc6.0,32位系统)。
类型对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
Char偏移量必须为sizeof(char)即1的倍数
int偏移量必须为sizeof(int)即4的倍数
float偏移量必须为sizeof(float)即4的倍数
double偏移量必须为sizeof(double)即8的倍数
Short偏移量必须为sizeof(short)即2的倍数
各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节VC会自动填充。
同时VC为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍?/textarea>
参考的网址分别有:
http://www.51testing.com/?uid-226261-action-viewspace-itemid-129983
http://www.cppblog.com/tx7do/archive/2009/01/06/71280.html
1. int a,b,c,d;
a = 0;
b = 1;
c = 2;
d = 3;
printf("_______%d______\n", a+++b+c+++d++);
答案:6
解析:拆分为 (a++)+b+(c++)+(d++) = 0 + 1 + 2 +3 = 6。因为在一个句子内,而++在变量之后。所以
2. int x = 12;
printf("____%d____", x+=x-=x*x);
答案:-264
解析: 拆分为:x += x-= (x*x)=x += x-= 144;
x += x(x=12-144)
x = x+x
x = -132-132 = -264
3.面向过程和面向对象的区别。
两种方法都是编程中的比较常用的方法,从理论上来说,都能达到用计算机程序来解决实际问题的目的,
只不过是其中所体现出来的思想不一样而已。
面向过程:面向过程的思想是把一个项目、一件事情按照一定的顺序,从头到尾一步一步地做下去,先做
什么,后做什么,一直到结束。这种思想比较好理解,其实这也是一个人做事的方法。
面向对象:面向对象的思想是把一个项目、一件事情分成更小的项目,或者说分成一个个更小的部分,每
一部分负责什么方面的功能,最后再由这些部分组合而成为一个整体。这种思想比较适合多人的分工合作
,就像一个大的机关,分成各个部门,每个部门分别负责某样职能,各个部门可以充分发挥自己的特色,
只要符合一定前提就行了。
举例说明1:比如刚才说的一个大的机关,要做某一个项目,从面向过程的思想来说,应该是这样分析的
,先怎么样,再怎么样,最后怎么样。第一样应该如何完成,第二样应该如何完成等等。等到每一步骤都
完成,项目也就完成了。而面向对象的思想则应该是这样想的,这个项目是由几个部分组成的,我们就做
好分工,成立一个部门来做一个部分的功能,另一个部门来做另一个部分。各个部门可以不用理解其他部
门的事,只要完成自己那一部分的事情就OK了。
举例说明2:又比如我们有一台演出,为简单起见,假设有如下流程:主持人开场——演员一表演——演
员二表演——主持人总结。用面向过程的思想来分析,就是先完成主持人开场,再完成演员一的表演,再
完成演员二的表演,最后完成主持人的总结。而如果用面向对象的思想来分析,就应该是这样的。这个演
出由两大部分组成:主持人、演员。与主持人相关的:开场、总结。与演员相关的:演员编号、所演的节
目。然后这台演出就可以这样策划:需要一个主持人a,需要两个演员b、c。演出的事情可以表示为:a的
开场——> b、c的编号和节目——> a的总结。
4. 已知单向链表的头结点head,写一个函数把这个链表逆序 ( Intel)
解答:
我们假设单向链表的节点如下:
template <typename T>
class list_node
{
public:
list_node *next;
T data;
};
这个题目算是考察数据结构的最基础的题目了,有两种方法可以解此题:
方法一:
void reverse(node *head)
{
if(head == 0 || head->next==0)return;//边界检查
node *pNext=0;
node *pPrev=head;//保存链表头节点
node *pCur=head->next;//取当前节点
while(pCur != 0)
{
pNext = pCur->next;//取下一个节点保存下来
pCur->next = pPrev;//将前节点下一节点置为前节点
pPrev = pCur;//将当前节点保存为前一节点
pCur = pNext;//将当前节点置为下一节点
}
}
这是一般的方法,总之就是用了几个临时变量,然后遍历整个链表,将当前节点的下一节点置为前节点。
方法二:
node* reverse(node* pNode, node*head)
{
if(pNode == NULL||pNode->next == NULL)
{
head=pNode;
return pNode;
}
node *temp = reverse(pNode->next,head);
temp->next=pNode;
return pNode;
}
这个方法是采用了递归算法,也就是在反转当前节点之前先反转其后继节点,说白了其实就是利用函数的调用堆栈构建了一个临时链表罢了,挺废的一个算法,权当作是写着好玩,没有什么实在的意义。
采用此算法需要注意的是,头结点必须要传入的是引用,因为在递归跳出的时候要切断链表,否则链表将会形成一个回环。
5. 双向链表的删除节点
struct dlist
{
int data;//节点数据
struct dlist *front;//指向下一节点
struct dlist *back;//指向前一节点
}
typedef struct dlist dnode;
typedef dnode *dlink;
dlink deletenode(dlink head, dlink ptr)
{
if(ptr->back == NULL)//头节点
{
head = head->front;
head->back = NULL;
}
else
{
if(ptr->front == NULL)//最后节点
{
ptr->back->front = NULL;
}
else//中间节点
{
ptr->back->front = ptr->front;
ptr->front->back = ptr->back;
}
}
free(ptr);
ptr = NULL;
return head;
}
6. 进程间的通信方式?
(1)管道【pipe】,是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程亲缘关系是指父子进程关系。
(2)有名管道[named pipe],有名管道也是一种半双工的通信方式,但允许无亲缘关系的进程间通信。
(3)消息队列【message queue】,消息队列是由消息的链表,存放在内核中并有消息队列标示符标示。消息队列克服了信号传递信息少、管道只能承载无格式字节流及缓冲区大小限制等缺点。
(4)信号【signal】,信号是一种比较复杂的通信方式,用于通知接收进程某个事情已发生。
(5)共享内存【shared memory】,共享内存是映射一段其他进程能够访问的内存,这段内存有一个进程创建,但多个进程可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信方式,如信号量配合使用,来实现进程间的同步和通信。
(6)套接字socket,套接口是一种进程间的通信机制,与其他通信机制不同的是,它可用于不同级其间的进程通信。
(7) 信号量【semophore】,信号量是一个计数器,可以用来控制多个进程对共享资源的访问,它常用来作为一种锁机制,防止某进程在访问共享资源时,其他进程也访问该资源。因此主要作为进程间,以及同一个进程不同线程之间的同步手段。