笔试面试总结之C++概念篇.docx

上传人:b****7 文档编号:23349304 上传时间:2023-05-16 格式:DOCX 页数:21 大小:31.82KB
下载 相关 举报
笔试面试总结之C++概念篇.docx_第1页
第1页 / 共21页
笔试面试总结之C++概念篇.docx_第2页
第2页 / 共21页
笔试面试总结之C++概念篇.docx_第3页
第3页 / 共21页
笔试面试总结之C++概念篇.docx_第4页
第4页 / 共21页
笔试面试总结之C++概念篇.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

笔试面试总结之C++概念篇.docx

《笔试面试总结之C++概念篇.docx》由会员分享,可在线阅读,更多相关《笔试面试总结之C++概念篇.docx(21页珍藏版)》请在冰豆网上搜索。

笔试面试总结之C++概念篇.docx

笔试面试总结之C++概念篇

C++部分概念篇

*.如何引用一个已经定义过的全局变量?

extern可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个编写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。

(1)全局变量是在所有函数体的外部定义的,程序的所有部分(甚至其他文件中的代码)都可以使用。

全局变量不受作用域的影响,总是可用的。

如果在一个文件中使用extern关键字来声明另一个文件中存在的全局变量那么这个文件可以使用这个数据。

e.g.在cpp1中定义全局变量intglobe,在cpp2中引用:

externintglobe

(2)局部变量可以与全局变量同名,局部会屏蔽全局,要用全局变量,需要使用":

:

"。

补充:

全局变量可以定义在可被多个.C文件包含的头文件中,在不同的C文件中以static形式来声明同名全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错。

*.全局变量、静态全局变量、静态局部变量和局部变量的区别:

(1)按存储区域分,全局变量、静态全局变量和静态局部变量都存放在内存的静态存储区域,局部变量存放在内存的栈区。

(2)按作用域分,全局变量在整个工程文件内都有效;静态全局变量只在定义它的文件内有效;静态局部变量只在定义它的函数内有效,只是程序仅分配一次内存,函数返回后,该变量不会消失;局部变量在定义它的函数内有效,但是函数返回后失效。

(3)全局变量(外部变量)的说明之前再冠以static就构成了静态的全局变量。

全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。

这两者在存储方式上并无不同。

这两者的区别在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。

而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。

由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。

把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。

把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。

全局变量在main函数调用后,就开始分配,

静态变量则是在main函数前就已经初始化了。

局部变量则是在用户栈中动态分配的(还是建议看编译原理中的活动记录这一块)。

补充:

函数前加static使得函数成为静态函数。

但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。

static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。

内部函数(static)应该在当前源文件中说明和定义。

对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件。

使用内部函数的好处是:

不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。

static全局变量与普通的全局变量区别

static全局变量只初使化一次,防止在其他文件单元中被引用

static局部变量和普通局部变量区别

static局部变量只被初始化一次,下一次依据上一次结果值

static函数与普通函数区别

static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝

补充:

static关键字至少有下列n个作用:

(1)函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;

(2)在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;

(3)在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;

(4)在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;

(5)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。

static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。

A.c和B.c两个c文件中使用了两个相同名字的static变量,他们都放在数据区,但是编译器对他们的命名是不同的。

*.应用程序在运行时的内存包括代码区和数据区,其中数据区又包括哪些部分?

参考:

对于一个进程的内存空间而言,可以在逻辑上分成3个部份:

代码区,静态数据区和动态数据区。

动态数据区一般就是“堆栈”。

栈是一种线性结构,堆是一种链式结构。

进程的每个线程都有私有的“栈”。

全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。

程序通过堆栈的基地址和偏移量来访问本地变量。

*.C++中堆(heap)和栈(stack)的区别

在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。

(1)堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。

如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。

(动态申请数据)

(2)栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。

里面的变量通常是局部变量、函数参数等。

(3)自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。

(4)全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在C++里面没有这个区分了,他们共同占用同一块内存区。

(5)常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。

首先,我们举一个例子:

voidf(){int*p=newint[5];}

这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?

他分配的是一块栈内存,所以这句话的意思就是:

在栈内存中存放了一个指向一块堆内存的指针p。

在程序会先确定在堆中分配内存的大小,然后调用operatornew分配内存,然后返回这块内存的首地址,放入栈中,如果要释放内存,应该是delete[]p,这是为了告诉编译器:

我删除的是一个数组。

堆和栈主要的区别由以下几点:

(1)管理方式不同:

对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memoryleak。

C中的malloc函数分配的内存空间即在堆上,C++中对应的是new操作符。

(2)空间大小不同:

Stack空间有限,Heap是很大的自由存储区

(3)能否产生碎片不同:

对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。

对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出。

(4)生长方向不同:

对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。

(5)分配方式不同:

堆都是动态分配的,没有静态分配的堆。

栈有2种分配方式:

静态分配和动态分配。

(6)分配效率不同:

堆的效率比栈要低得多。

如果有人把堆栈合起来说,那它的意思是栈,可不是堆。

*.内存的分配方式的分配方式有几种

答:

一、从静态存储区域分配。

内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。

例如全局变量。

二、在栈上创建。

在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。

栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

三、从堆上分配,亦称动态内存分配。

程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。

动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

*.union和struct的区别

Union-共用体,构造数据类型,也叫联合体,用途:

使几个不同类型的变量共占一段内存(相互覆盖)。

Struct-结构体是一种构造数据类型,用途:

把不同类型的数据组合成一个整体-------自定义数据类型

(1)struct和union都是由多个不同的数据类型成员组成,但在任何同一时刻,union中只存放了一个被选中的成员,而struct的所有成员都存在。

在struct中,各成员都占有自己的内存空间,它们是同时存在的。

一个struct变量的总长度等于所有成员长度之和。

在Union中,所有成员不能同时占用它的内存空间,它们不能同时存在。

Union变量的长度等于最长的成员的长度。

(2)对于union的不同成员赋值,将会对其它成员重写,原来成员的值就不存在了,而对于struct的不同成员赋值是互不影响的。

设有以下说明和定义:

typedefunion

{

longi;

intk[5];

charc;

}DATE;

structdata

{

intcat;

DATEcow;

doubledog;

}too;

DATEmax;

则语句printf("%d",sizeof(structdata)+sizeof(max));的执行结果是:

___52____

考点:

区别struct与union.(一般假定在32位机器上)

答:

DATE是一个union,变量公用空间,里面最大的变量类型是int[5],占用20个字节,所以它的大小是20。

data是一个struct,每个变量分开占用空间。

依次为int4+DATE20+double8=32.所以结果是20+32=52.当然...在某些16位编辑器下,int可能是2字节,那么结果是int2+DATE10+double8=20

*.队列先进先出,栈后进先出

*.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?

c用宏定义,c++用inline。

e.g.写一个“标准”宏,这个宏输入两个参数并返回较小的一个。

#defineMin(X,Y)((X)>(Y)?

(Y):

(X))//结尾没有;

*.Template有什么特点?

什么时候用?

答:

Template可以独立于任何特定的类型编写代码,是泛型编程的基础。

当我们编写的类和函数能够多态的用于跨越编译时不相关的类型时,用Template。

模板主要用于STL中的容器,算法,迭代器等以及模板元编程。

(C++的template是实现在库设计和嵌入式设计中的关键。

template能实现抽象和效率的结合;同时template还能有效地防止代码膨胀)。

*.什么是预编译,何时需要预编译:

答:

就是指程序执行前的一些预处理工作,主要指#表示的。

何时需要预编译?

1)总是使用不经常改动的大型代码体。

2)程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。

在这种情况下,可以将所有包含文件预编译为一个预编译头。

*.关键字const有什么含意?

答:

const关键字至少有下列n个作用:

(1)欲阻止一个变量被改变,可以使用const关键字。

在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;

(2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;

(3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;

(4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;

(5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。

constinta;

a是一个常整型数

intconsta;

a是一个常整型数

constint*a;

a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)

int*consta;

a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)

constint*consta;

a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)

*.数据声明(Datadeclarations)

区分指针

int*p[n];-----指针数组,每个元素均为指向整型数据的指针。

int(*p)[n];------p为指向一维数组的指针,这个一维数组有n个整型数据。

int*p();----------函数带回指针,指针指向返回的值。

int(*p)();------p为指向函数的指针。

一个整型数

(Aninteger)

inta;

一个指向整型数的指针

(Apointertoaninteger)

int*a;

一个指向指针的的指针,它指向的指针是指向一个整型数

(Apointertoapointertoaninteger)

int**a;

一个有10个整型数的数组

(Anarrayof10integers)

inta[10];

一个有10个指针的数组,该指针是指向一个整型数的

(Anarrayof10pointerstointegers)

int*a[10];

一个指向有10个整型数数组的指针

(Apointertoanarrayof10integers)

int(*a)[10];

一个指向函数的指针,该函数有一个整型参数并返回一个整型数

(Apointertoafunctionthattakesanintegerasanargumentandreturnsaninteger)

int(*a)(int);

一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数

(Anarrayoftenpointerstofunctionsthattakeanintegerargumentandreturnaninteger)

int(*a[10])(int);

*.struct和class

c和c++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct可以。

c++中struct和class的主要区别在于默认的存取权限不同,struct默认为public,而class默认为private。

c++中的类具有成员保护功能,并且具有继承,多态这类oo(面向对象)特点,而c里的struct没有没有成员函数,不能继承,派生等等。

*.C++:

memset,memcpy和strcpy的根本区别?

答:

1)memset用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为''或'';例:

chara[100];memset(a,'',sizeof(a));

Memset原型:

externvoid*memset(void*buffer,charc,intcount);

用法:

#include"memory.h"

功能:

把buffer所指内存区域的前count个字节设置成字符c。

说明:

返回指向buffer的指针。

2)memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度;例:

chara[100],b[50];memcpy(b,a,sizeof(b));注意如用sizeof(a),会造成b的内存地址溢出。

memcpy原型:

externvoid*memcpy(void*dest,void*src,unsignedintcount);

{

ASSERT((dest!

=NULL)&&(src!

=NULL));

ASSERT((dest>src+count)||(src>dest+count));//防止内存重叠,也可以用restrict修饰指针

Byte*bdest=(Byte*)dest;

Byte*bsrc=(Byte*)src;

While(count-->0)

*bdest++=**bsrc++;

Returndest;

}

用法:

#include

功能:

由src所指内存区域复制count个字节到dest所指内存区域。

说明:

src和dest所指内存区域不能重叠,函数返回指向dest的指针。

3)strcpy就只能拷贝字符串了,它遇到'\0'就结束拷贝;例:

chara[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串长度(第一个'\0'之前)是否超过50位,如超过,则会造成b的内存地址溢出。

strcpy原型:

externchar*strcpy(char*dest,char*src);

{

ASSERT((dest!

=NULL)&&(src!

=NULL));

Char*address=dest;

While((*dest++=*src++)!

=’\0’)

Continue;

Returndest;

}

用法:

#include

功能:

把src所指由NULL结束的字符串复制到dest所指的数组中。

说明:

src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。

返回指向dest的指针。

附:

ASSERT()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE(0),程序将报告错误,并终止执行。

如果表达式不为0,则继续执行后面的语句。

这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。

例如,变量n在程序中不应该为0,如果为0可能导致错误,你可以这样写程序:

......

ASSERT(n!

=0);

k=10/n;

......

ASSERT只有在Debug版本中才有效,如果编译为Release版本则被忽略。

assert()的功能类似,它是ANSIC标准中规定的函数,它与ASSERT的一个重要区别是可以用在Release版本中。

*.字符串拷贝可以使用sprintf、strcpy及memcpy函数

答案:

这些函数的区别在于实现功能以及操作对象不同。

1.strcpy函数操作的对象是字符串,完成从源字符串到目的字符串的拷贝功能。

2.snprintf函数操作的对象不限于字符串:

虽然目的对象是字符串,但是源对象可以是字符串、也可以是任意基本类型的数据。

这个函数主要用来实现(字符串或基本数据类型)向字符串的转换功能。

如果源对象是字符串,并且指定%s格式符,也可实现字符串拷贝功能。

3.memcpy函数顾名思义就是内存拷贝,实现将一个内存块的内容复制到另一个内存块这一功能。

内存块由其首地址以及长度确定。

memcpy的操作对象不局限于某一类数据类型,或者说可适用于任意数据类型,只要能给出对象的起始地址和内存长度信息、并且对象具有可操作性即可。

memcpy函数通常限于同种类型数据或对象之间的拷贝,其中当然也包括字符串拷贝以及基本数据类型的拷贝。

对于字符串拷贝来说,用上述三个函数都可以实现,但是其实现的效率和使用的方便程度不同:

1.strcpy无疑是最合适的选择:

效率高且调用方便。

2.snprintf要额外指定格式符并且进行格式转化,麻烦且效率不高。

3.memcpy虽然高效,但是需要额外提供拷贝的内存长度这一参数,易错且使用不便。

*.析构函数和虚函数的用法和作用?

析构函数也是特殊的类成员函数,它没有返回类型,没有参数,不能随意调用,也没有重载。

只是在类对象生命期结束的时候,由系统自动调用释放在构造函数中分配的资源。

这种在运行时,能依据其类型确认调用那个函数的能力称为多态性,或称迟后联编。

析构函数一般在对象撤消前做收尾工作,比如回收内存等工作,

虚拟函数的功能是使子类可以用同名的函数对父类函数进行覆盖,并且在调用时自动调用子类覆盖函数,如果是纯虚函数,则纯粹是为了在子类覆盖时有个统一的命名而已。

纯虚函数如何定义:

virtualvoidf()=0;是接口,子类必须要实现

注意:

子类重新定义父类的虚函数的做法叫覆盖,override,而不是overload(重载),重载的概念不属于面向对象编程,重载指的是存在多个同名函数,这些函数的参数表不同。

重载是在编译期间就决定了的,是静态的,因此,重载与多态无关。

与面向对象编程无关。

含有纯虚函数的类称为抽象类,不能实例化对象,主要用作接口类//

补充:

多态。

overload和override的区别。

overload是重载,重载是一种参数多态机制,即代码通过参数的类型或个数不同而实现的多态机制。

是一种静态的绑定机制(在编译时已经知道具体执行的是哪个代码段)。

override是覆盖。

覆盖是一种动态绑定的多态机制。

即在父类和子类中同名元素(如成员函数)有不同的实现代码。

执行的是哪个代码是根据运行时实际情况而定的。

Overload特点:

1、方法名必须相同2、参数列表必须不相同3、返回值类型可以不相同

注意:

override存在于继继承的关系类中。

publicboolwithdraw(doubleamt,stringname)

publicdoublewithdraw(doubleamt)

Override特点(三相同):

1、方法名相同2、参数列表相同3、返回值类型相同

注意:

存在于同一类中,但是只有虚方法和抽象方法才能被覆写.

publicoverrideboolwithdraw(...)

*.强制类型转换

标准C++中有四个类型转换符:

static_cast、dynamic_cast、reinterpret_cast、和const_cast。

static_cast:

数制转换

用法:

static_cast(expression)

该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。

它主要有如下几种用法:

1.用于类层次结构中基类和子类之间指针或引用的转换。

进行上行转换(把子类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。

2.用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。

这种转换的安全性也要开发人员来保证。

3.把空指针转换成目标类型的空指针。

4.把任何类型的表达式转换成void类型。

注意:

static_cast不能转换掉expression的const、volitale、或者__unaligned属性。

dynamic_cast:

用于执行向下转换和在继承之间的转换

用法:

dynamic_cast(e

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 小学教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1