C++面试题库,C++面试笔试题
想去C面试,随便看看。我在网上搜了一下。刚看到的,我整理一下。
1.变量的声明和定义有什么区别?常量:在程序执行过程中不会改变的量,不能改变的量。
变量:在程序执行过程中可以改变的量。
如何定义变量:数据类型变量名=常量;
int num=10//定义(分配存储空间,初始化值不变)
int num//定义声明(分配存储空间,分配垃圾值)
外部整数;//referencing声明,(不分配存储空间,不分配垃圾值)不限于使用本文档。
变量的定义用于为变量分配存储空间,也可以为变量指定初始值。在程序中,变量只有一个定义。
一般来说,对于不需要构建存储空间的语句,我们经常将其描述为“定义”和“声明”。显然,我们这里所指的陈述的范围是狭义的,也就是狭义上的陈述,也就是非定义性质的陈述。
当一个函数被声明时,编译器不会给这个函数分配入口地址。
定义函数时,函数的代码段会放在代码块中。此时,即使内存空间分配给了函数,函数名也映射了函数的入口地址。
声明的最终目的是提前使用,也就是在定义之前。如果不需要提前使用,就没有必要单独申报。对于变量和函数来说都是如此,所以声明不会分配存储空间,只有在定义的时候。
2.编写比较bool int float的指针变量与零值的if语句Bool数据。
If(标志)
如果(!旗帜)
Int数据:
如果(0!=标志)
if(0==标志)
指针数据:
if(NULL==flag)
如果(NUJLL!=标志)
浮动数据:
定义定额0.00001;
if(flag=-NORM flag=NORM)
注意:在比较带有零值的int、指针变量时,要特别注意将零值放在左边,这样当==被误写成=时,编译器就可以报错,否则这样的逻辑错误不容易被发现,可能会导致严重的后果。
3.sizeof和strlen的区别sizeof和strlen是有区别的:
Sizeof是运算符,strlen是库函数。
sizeof的参数可以是数据类型,也可以是变量,而strlen只能是以 \ 0 结尾的字符串。
编译器计算sizeof的结果,必须运行strlen函数来计算它。sizeof计算数据类型在内存中的大小,而strlen计算字符串的实际长度。
数组sizeof的参数不会退化,传递strlen时退化为指针。
注意:有些操作符看起来像函数,而有些函数名看起来像操作符。这样容易混淆的名字一定要区分,否则遇到数组名等特殊数据类型作为参数时很容易出错。最容易与函数混淆的运算符是sizeof。
4.C语言中的关键字static和C中的关键字static有什么区别?在C中,static用于修改局部静态变量和外部静态变量和函数。除了上述函数,C还用于定义类成员变量和函数,即静态成员变量和静态成员函数。
注意:static在编程时的内存和全局特性允许不同时期调用的函数进行通信和传递信息,而C的静态成员可以在多个对象实例之间进行通信和传递信息。
5.C中的malloc和C中的new有什么区别?Malloc和new有些不同:
New,delete是一个可以重载的运算符,只能在c中使用。
Malloc,free是一个可以被覆盖的函数,在C和C中都可以使用。
New可以调用对象的构造函数,对应的delete调用对应的析构函数。
Malloc只分配内存,free只回收内存,不执行构造函数和析构函数。
New delete返回某种数据类型的指针,malloc free返回void的指针。
注意:malloc应用的内存空间要用free释放,new应用的内存空间要用delete释放。不要混淆,因为两者机制不同。
6.写一个标准宏MIN #定义min(a,b)((a)=(b)?(a):(b))
注意:调用时一定要注意这个宏定义的副作用,如下
(*p) (x)?(*p):(x)
p指针加了两次,违背了MIN的初衷。
7.指针能使volatile?volatile用在以下地方:
1.在中断服务程序中为被其他程序检测而修改的变量需要是易变的;
2.易挥发;应添加到多任务环境中任务间共享的徽标中;
3.内存映射的硬件寄存器通常需要用volatile来解释,因为每次读写都可能有不同的含义;
8.A和A有什么区别?请写出下列代码的打印结果。主要目的是考察A和A的区别。
#包含stdlo.h
Void main()
{
Int a[5]={1,2,3,4,5 };
int * ptr=(int)(a 1);
Printf("%d,%d ",(a 1),(ptr-1));
返回;
}
产量:2.5
注意:数组名A可以是数组的第一个地址,A是数组的指针。
思考,把原公式的int * ptr=(int *)(a 1);
当它是int *ptr=(int *)(a 1)时,输出结果会是什么
简述C,C程序编译的内存分配(1)从静态存储区分配:
程序编译时内存已经分配好了。这种记忆存在于程序的整个运行期间。它是快速和无错误的,因为有些系统会清理,例如,全局变量,静态变量等。
(2)在堆栈上分配:
当一个函数被执行时,函数中局部变量的存储单元在栈上被创建,这些存储单元在函数被执行时被自动释放。堆栈内存分配操作内置在处理器的指令集中,效率非常高,但分配的内存容量有限。
(3)从堆中分配:
也就是动态内存分配。当一个程序运行时,它适用于任何大小的内存。程序员负责决定什么时候释放内存或者删除内存。动态内存的寿命是由程序员决定的,使用起来非常灵活。如果空间是在堆上分配的,那么回收它是它的责任。否则,正在运行的程序会出现内存泄漏。此外,频繁分配和释放不同大小的堆空间会在堆中产生碎片。
编译C和C程序时,内存分为五个存储区:堆区、堆栈区、全局区、文字常量区和程序代码区。
10简述strcpy、sprintf和memecpy之间的区别。它们之间有以下不同之处。
(1)操作对象不同:strcpy的两个操作对象是字符串,sprintf的操作对象可以是多种数据类型,目的操作对象是字符串。memcpy的两个对象是两个可任意操作的内存地址,不限于任何数据类型。
(2)执行功能不同:strcpy主要实现字符串变量之间的复制,sprintf主要实现其他数据类型到字符串类型的转换,memcpy主要实现内存块之间的复制。
(3)执行效率不同:memcpy最高,sprintf最低。
注意:strcpy、sprintf、memcpy都可以实现复制功能,但是要根据实际需要,针对不同的对象选择合适的函数来实现复制功能。
11.将地址为ox67a9的整型变量的值设置为oxaa66int * ptr
ptr=(int *)ox67a 9;
* Ptr=oxaa66
说明:这个问题是一个典型的强制类型转换的例子。不管什么平台,地址长度和整数数据长度是一样的,也就是一个整数数据只要有意义就可以强制成地址指针类型。
12.面向对象的三个特点面向对象的三个特点是封装性、继承性和多态性。
13.C (1)默认构造函数的空类的成员函数是什么
(2)默认复制构造函数
(3)默认析构函数
(4)默认赋值运算符
(5)默认寻址运算符
(6)默认寻址运算符const
注意:有些书只是简单介绍了前四个函数,没有提到后两个函数,但后两个函数也是空类的默认函数。更何况,编译器只会在实际使用这些函数的时候才会定义它们。
14.谈谈你对复制构造函数和赋值运算符的理解。复制构造函数和复制运算符重载之间有以下两个区别:
(1)复制构造函数生成新的类对象,但赋值操作不能。
(2)由于复制构造函数直接构造一个新的类对象,所以在初始化这个对象之前不需要检查源对象是否与新对象相同,但是赋值运算符需要这个操作。此外,如果原始对象中的内存不匹配,则必须首先释放赋值运算符中的内存。
注意:当类中有指针类型成员变量时,一定要重写复制构造函数和赋值操作符,不要使用默认的。
15.简述类成员函数的重写,重载和隐藏的区别(1)重写和重载有以下区别:
区别:被重写和被重写的函数在两个类中,而重载和重载的函数在同一个类中。
参数的区别:被重写的函数和被重写的函数的参数列表必须相同,而重载的函数和重载的函数的参数列表必须不同。
虚的区别:被重写基类中的被重写函数必须用虚来修饰,而重载函数和重载函数可以用虚来修饰,也可以不用。
(2)隐藏和重写,重载有以下区别:
不像重载的作用域,像重写,隐藏函数和隐藏函数不在同一个类里。
参数的区别:隐藏函数和隐藏函数的参数表可以相同,也可以不同,但函数名必须相同。当参数不同时,无论基类中的参数是否被虚修饰,基类的函数都是隐藏的,而不是重写的。
注意:重载和覆盖虽然是实现多态的基础,但是技术完全不同,目的也完全不同。覆盖是动态绑定的多态性,重载是静态绑定的多态性。
16.简述多态实现的原理。当编译器在一个类中找到一个虚函数时,它会立即为这个类生成一个虚函数表vtable。虚函数表的每一个条目都是一个指向对应虚函数的指针,编译器会隐式地在这个类中插入一个指针vptr(对于vc编译器来说是插入在类中的第一个位置)指向虚函数表。在调用该类的构造函数时,编译器会隐式执行vptr和vtable之间的关联代码,将vptr指向对应的vtable,并将该类与该类的vtable链接。另外,在调用类的构造函数时,基类的指针现在已经变成了具体类的这个指针,这样就可以依靠这个这个这个指针得到正确的vtable,这样就可以真正和函数体连接起来了。这是动态绑定和多态的基本原理。
注意:一定要分清虚函数、纯虚函数和虚继承的关系和区别。牢记虚函数实现原理,因为这是多态C面试的重要考点之一,虚函数是实现多态的基础。
17.链表和数组有什么区别?数组和链表有以下区别:
(1)存储形式:数组是一个连续的空间,声明的时候就要确定它的长度。链表是一个长度可变的不连续动态空间,每个节点都要存储相邻节点的指针。
(2)数据搜索:数组线性搜索速度快,搜索操作直接使用偏移地址,链表需要按顺序搜索节点,效率低。
(3)数据插入和删除:链表可以快速插入和删除节点,而数组可能需要大量的数据移动。
(4)越界问题:链表没有越界问题,数组有。
注意:在选择数组或链表的数据结构时,必须根据实际需要选择。数组易于查询,链表易于插入和删除,数组节省空间但长度固定,链表虽然变长但占用存储空间更多。
18.如何反转单个链表?1.反向单链表循环算法。
有两种类型的链表:
Headed:头节点存储长度信息,头节点的next指向第一个实际节点;
如果没有领导节点,领导节点是第一个节点;
这里使用了前导节点的链表;需要三个指针来记录当前节点(用于倒车)、上一个节点和下一个节点(用于倒车后前进)。
代码如下:
/*
链式表
节点*下一个;
};
void reverseList(节点*头)
{
if((head==NULL) ((head-next)==NULL))返回;//如果头为空,或者头节点指向空节点(链表长度为0),则退出。
Node *pre,*cur,* next//cur记录当前位置,pre记录上一个位置,这是cur- next的值;Next记录下一个位置。反转后cur不等于cur- next。
cur=head-next;
pre=NULL//反转后头节点成为尾节点,其next为Null。
而(cur!=空)
{
next=cur-next;//cur- next反转后不能用,先记录这个节点
cur-next=pre;
pre=cur
cur=next
}
head-next=pre;//cur已经是空的,所以pre是尾节点。头-下一个指向它。
返回;
} 2.反转单链表的递归算法
代码如下:
List *reverse( List *oldList,List *newHead=NULL)
{
list * next=old list-next;//记录最后一次翻转后的链表
old list-next=new head;//将当前节点插入翻转链表的开头。
newHead=oldList//递归处理剩余的链表
return ( next==NULL)?newHead: reverse( t,newHead);
}
19.简述队列和栈的异同。队列和栈是线性存储结构,但是插入和删除数据的操作是不同的。队列是先进先出的,堆栈是后进先出的。
注意:栈区和堆区的区别在于,堆区的访问是随机的,而栈区是后进先出的。堆栈由编译器自动分配,存储函数参数和局部变量的值等。其操作方式类似于数据结构中的堆栈,堆一般由程序员分配和释放。如果程序员不释放它,它可能会在程序结束时被os恢复。分配方式类似于链表,不同于本主题中的堆和栈。Stack只是一个数据结构,而heap。
最后,祝面试的朋友们成功。
原创作品来自勿忘你的倡议心,的博主,
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。