资源描述
以下题目可能与原题目有差入,但力争使题目与原题目接近。
这是某个公司的linux内核驱动笔试题目,希望对各位要参加面试的朋友提供一点帮助,同时又要对公司试 题保密,唉,没方法,具体公司名字只能采用XXX代替啦!八_八……
如果这样还是“那个”的话(八_八),请公司及时与偶联系,偶会第一时间将其删除,谢谢!
(一)主要题型:
选择题(每题3分,约20题吧,具体什么题都有,包括网络、C以及其他硬件方面的基础知识);简答题(总分约40分,主要包括读C程序给出结果同时给出适当的解释及其他一些硬件方面的问题); (―)主要内容:
1、题目概述
(1)C方面:
这一局部比拟简单,主要是类似指针空间分配、strcpy (主要是考第一个参数是否有空间,结合指针空间 分配考)、二重指针、+ +及 (先加后加,先减后减)等,还有就是volatile及register修饰符的意思。 (2)其他方面:
这一局部比拟杂,什么都可以考你,多半都是基础知识,尤其是硬件方面,华为的主要题目为:(主要列出 C以外的题目,我认为C是非常简单的,工人)2、具体题目
(1)选择题局部:
1、网段最多能支持多少主机?(大概有5个备选项)2、10M网卡传输过程中物理层采用什么编码? (SNAP?)(大概有4个备选项)
3、栈与队列的特点?(备选大概只有两个,A为FIFO, B为LIFO)4>Cache的工作方式划分?(大概也有4个答案,大概是:wiite・none, write・all, write-through, whte・back)。
5、什么叫NMI中断?(四个备选项)6、RISC主要性能及特性?(大概有6个备选项)
7、在嵌入式系统中,所谓的北桥指的是什么?
(2)简答题:
1、说说轮巡任务调度与抢占式任务调度的区别?(大概为8分吧,记不清了)2、什么叫存储器高速缓存技术,其主要目的?(大概6分)
3、画出计算机组成的最小逻辑框图。(哼,这道题竟然10分)4、谈谈Volatile与Register修饰符的作用?
【一、来自Q群友】Llinux内核里面,内存申请有哪几个函数,各自的区别?
2. IRQ和FTQ有什么区别,在CPU里面是是怎么做的?
3. int *a;
char *b;a和b本身是什么类型?
这个实现方式让我为难,因为这个语法没有确切表到达底怎么回事。如果一 个应试者给出这个作为方案,我将用这个作为一个机会去探究他们这样做的
基本原理。如果他们的基本答案是:“我被教着这样做,但从没有想到过为 什么。”这会给我留下一个坏印象。
第三个方案是用goto
Loop:
• • •
goto Loop;
应试者如给出上面的方案,这说明或者他是一个汇编语言程序员(这也许是 好事)或者他是一个想进入新领域的BASIC/FORTRAN程序员。
数据声明(Data declarations)
5.用变量a给出下面的定义
a) 一个整型数(An integer) int a;
b) 一个指向整型数的指针(A pointer to an integer) int *a;
c) 一个指向指针的的指针,它指向的指针是指向一个整型数
(A pointer to a pointer to an integer) int **a;
d) 一个有10个整型数的数组(An array of 10 integers)int a[10];
e) 一个有10个指针的数组,该指针是指向一个整型数的
(An array of 10 pointers to integers) int *a[10];
f) 一个指向有10个整型数数组的指针
(Apointertoan array of 10integers) int (*a) [10];
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数
(Apointertoa function thattakes an integer as anargument and returns an integer) int (*a)(int);
h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参 数并返回一个整型数
( An array of ten pointers to functions that take an inte ger argument and return an integer ) int (*a[10]) (int)
答案是:
a) int a; // An integer
b) int*a; //Apointer to aninteger
c) int**a;//Apointer to apointer toaninteger
d) inta[10];//An array of 10 integers
e) int*a [10];//An array of10 pointerstointegersint(*a)[10]; //A pointer toanarray of 10 integers
f) int(*a)(int);//A pointer toafunction a that takes
an integer argument and returns an integerint(*a[10])(int) ;// An arrayof10 pointers to functio
ns that take an integer argument and return an integer
人们经常声称这里有几个问题是那种要翻一下书才能回答的问题,我同意这 种说法。当我写这篇文章时,为了确定语法的正确性,我确实查了一下书。
但是当我被面试的时候,我期望被问到这个问题(或者相近的问题)。因为 在被面试的这段时间里,我确定我知道这个问题的答案。应试者如果不知道
所有的答案(或至少大局部答案),那么也就没有为这次面试做准备,如果 该面试者没有为这次面试做准备,那么他又能为什么出准备呢?
Static
6 .关键字static的作用是什么?
这个简单的问题很少有人能回答完全。在C语言中,关键字static有三个 明显的作用:
1) .在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其 值不变。
2) .在模块内(但在函数体外),一个被声明为静态的变量可以被模块内 所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3) .在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调 用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
大多数应试者能正确回答第一局部,一局部能正确回答第二局部,同是很少 的人能懂得第三局部。这是一个应试者的严重的缺点,因为他显然不懂得本地化 数据和代码范围的好处和重要性。
Const
7 .关键字const是什么含意?
我只要一听到被面试者说:“const意味着常数”,我就知道我正在和一个 业余者打交道。去年Dan Saks已经在他的文章里完全概括了 const的所有用法, 因此ESP (译者:Embedded Systems Programming)的每一位读者应该非常熟悉 const能做什么和不能做什么.如果你从没有读到那篇文章,只要能说出const 意味着“只读”就可以了。尽管这个答案不是完全的答案,但我接受它作为一个 正确的答案。(如果你想知道更详细的答案,仔细读一下Saks的文章吧。)如 果应试者能正确回答这个问题,我将问他一个附加的问题:下面的声明都是什么 意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整 型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一 个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是 不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指 针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确 回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问, 即使不用关键字const,也还是能很容易写出功能正确的程序,那么我为什么 还要如此看重关键字const呢?我也如下的几下理由:
1) .关键字const的作用是为给读你代码的人传达非常有用的信息,实 际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花 很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然, 懂得用const的程序员很少会留下的垃圾让别人来清理的。)
2) .通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑 的代码。
3) .合理地使用关键字const可以使编译器很自然地保护那些不希望被改 变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。
Volatile
8 .关键字volatile有什么含意 并给出三个不同的例子。
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样, 编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时 必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。 下面是volatile变量的几个例子:
1) .并行设备的硬件寄存器(如:状态寄存器)
2) . 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3) .多线程应用中被几个任务共享的变量
回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式 系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等 打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。
假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微 深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。
4) . 一个参数既可以是const还可以是volatile吗?解释为什么。
5) . 一个指针可以是volatile吗?解释为什么。
6) .下面的函数有什么错误:
int square(volatile int *ptr)
{
return *ptr * *ptr;
)
下面是答案:
7) .是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意 想不到地改变。它是const因为程序不应该试图去修改它。
8) .是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个 指向一个buffer的指针时。
9) .这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的 平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代 码:
int square(volatile int *ptr)
(
int a, b;
a = *ptr;
b = *ptr;
return a * b;
)
由于*Ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果, 这段代码可能返不是你所期望的平方值!正确的代码如下:
long square (volatile int *ptr)
(
int a;
a = *ptr;
return a * a;
)
位操作 (Bit manipulation)
9 .嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变 量a,写两段代码,第一个设置a的bit 3,第二个清除a的bit 3。在以 上两个操作中,要保持其它位不变。
对这个问题有三种基本的反响
1) .不知道如何下手。该被面者从没做过任何嵌入式系统的工作。
2) .用bit fieldso Bit fields是被扔到C语言死角的东西,它保证你 的代码在不同编译器之间是不可移植的,同时也保证了的你的代码是不可重用 的。我最近不幸看到Infineon为其较复杂的通信芯片写的驱动程序,它用到 了 bit fields因此完全对我无用,因为我的编译器用其它的方式 来实现 bit fields的。从道德讲:永远不要让一个非嵌入式的家伙粘实际硬件的边。
3) .用^defines和bit masks操作。这是一个有极高可移植性的方法,是应该被用到的方法。最正确的解决方案如下: ^define BIT3 (0xl«3) static int a;
void set_bit3(void) (
a |= BIT3;
)
void clear_bit3(void)
(
a &二〜BIT3;
)
一些人喜欢为设置和清除值而定义一个掩码同时定义一些说明常数,这也是 可以接受的。我希望看到几个要点:说明常数、仁和&二~操作。
访问固定的内存位置 (Accessing fixed memory locations)
10 .嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在 某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是 一个纯粹的ANSI编译器。写代码去完成这一任务。
这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换
(typecast)为一指针是合法的。这一问题的实现方式随着个人风格不同而不同。 典型的类似代码如下:
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa55;
一个较晦涩的方法是:
*(int * const)(0x67a9) = 0xaa55;
即使你的品味更接近第二种方案,但我建议你在面试时使用第一种方案。
中断(Interrupts)
11.中断是嵌入式系统中重要的组成局部,这导致了很多编译开发商提供 一种扩展一让标准C支持中断。具代表事实是,产生了一个新的关键 字—interrupto下面的代码就使用了—interrupt关键字去定义了一个中断 服务子程序(ISR),请评论一下这段代码的。
interrupt double computearea (double radius)double area = PI * radius * radius;
printf (/z Area =area);return area;
这个函数有太多的错误了,以至让人不知从何说起了:
1) . ISR不能返回一个值。如果你不懂这个,那么你不会被雇用的。
2) . ISR不能传递参数。如果你没有看到这一点,你被雇用的机会等同第 一项。
3) .在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/ 编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮 点运算。止匕外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。
4) .与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢 掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你 的被雇用前景越来越光明了。
代码例子(Code examples)
12 .下面的代码输出是什么,为什么?
void foo(void)
(unsigned int a = 6;
int b = -20;(a+b > 6) ?puts(〃> 6〃): puts (〃〈二 6〃);
这个问题测试你是否懂得C语言中的整数自动转换原那么,我发现有些开发者 懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是“>6" o原因 是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符 号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大 于6O这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要 的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。
13 .评价下面的代码片断:
unsigned int zero = 0;
unsigned int compzero 二 OxFFFF;
/*1's complement of zero */
对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写 如下:
unsigned int compzero = 、0;
这一问题真正能揭露出应试者是否懂得处理器字长的重要性。在我的经验 里,好的嵌入式程序员非常准确地明白硬件的细节和它的局限,然而PC机程序 往往把硬件作为一个无法防止的烦恼。
到了这个阶段,应试者或者完全垂头丧气了或者信心满满志在必得。如果显 然应试者不是很好,那么这个测试就在这里结束了。但如果显然应试者做得不错, 那么我就扔出下面的追加问题,这些问题是比拟难的,我想仅仅非常优秀的应试 者能做得不错。提出这些问题,我希望更多看到应试者应付问题的方法,而不是 答案。不管如何,你就当是这个娱乐吧…
动态内存分配(Dynamic memory allocation)
14 .尽管不像非嵌入式计算机那么常见,嵌入式系统还是有从堆(heap) 中动态分配内存的过程的。那么嵌入式系统中,动态分配内存可能发生的问题是什么?
这里,我期望应试者能提到内存碎片,碎片提供的问题,变量的持行时间等 等。这个主题已经在ESP杂志中被广泛地讨论过了(主要是P. J. Plauger,他的解释远远超过我这里能提到的任何解释),所有回过 头看一下这些杂志吧!让应试者进入一种虚假的平安感觉后,我拿出这么一个小 节目:下面的代码片段的输出是什么,为什么?
char *ptr;
if ((ptr 二(char *)malloc(0))二二 NULL)
puts ("Got a null pointer");
else
puts (z,Got a valid pointer");
这是一个有趣的问题。最近在我的一个同事不经意把0值传给了函数 malloc,得到了一个合法的指针之后,我才想到这个问题。这就是上面的代码, 该代码的输出是“Got a valid pointer"。我用这个来开始讨论这样的一问 题,看看被面试者是否想到库例程这样做是正确。得到正确的答案固然重要,但 解决问题的方法和你做决定的基本原理更重要些。
Typedef
15 . Typedef在C语言中频繁用以声明一个已经存在的数据类型的同义 字。也可以用预处理器做类似的事。例如,思考一下下面的例子:
#define dPS struct s *
typedef struct s * tPS;
以上两种情况的意图都是要定义dPS和tPS作为一个指向结构s指针。 哪种方法更好呢?(如果有的话)为什么?
这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被恭 喜的。答案是:typedef更好。思考下面的例子:
dPS pl,p2;
tPS p3,p4;
第一个扩展为
struct s * pl, p2;
上面的代码定义pl为一个指向结构的指,p2为一个实际的结构,这也许不 是你想要的。第二个例子正确地定义了 P3和p4两个指针。
晦涩的语法
16 . C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做 些什么?
int a = 5, b = 7, c;
c = a+++b;
这个问题将做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子 是完全合乎语法的。问题是编译器如何处理它?水平不高的编译作者实际上会争 论这个问题,根据最处理原那么,编译器应当能处理尽可能所有合法的用法。因此, 上面的代码被处理成:
c = a++ + b;
因此,这段代码持行后a = 6, b = 7, c = 12o
如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不把 这个当作问题。我发现这个问题的最大好处是:这是一个关于代码编写风格,代 码的可读性,代码的可修改性的好的经典C/C++面试笔试题
分类:linux驱动笔试2011・11・16 22:27 87人阅读评论(0)收一举报C/C++经典面试题
面试题1:变量的声明和定义有什么区别为变量分配地址和存储空间的称为定义,不分配地址的称为声明。一个变量可以在多个地方 声明,但是只在一个地方定义。加入extern修饰的是变量的声明,说明此变量将在文件以 外或在文件后面局部定义。
说明:很多时候一个变量,只是声明不分配内存空间,直到具体使用时才初始化,分配内存 空间,如外部变量。
a、b里面本身存放的只是一个地址,难道是这两个地址有不同么?
4 .中断的上半局部和下半局部的问题:
讲下分成上半局部和下半局部的原因,为何要分?讲下如何实现?
分析:中断服务例程一般都是在中断请求关闭的条件下执行的,以防止嵌套而使中断控 制复杂化。但是,中断是一个随机事件,它随时会到来,如果关中断的时间太长,CPU就不 能及时响应其他的中断请求,从而造成中断的丧失。因此,内核的目标就是尽可能快的处理 完中断请求,尽其所能把更多的处理向后推迟。例如,假设一个数据块已经到达了网线,当 中断控制器接受到这个中断请求信号时,Linux内核只是简单地标志数据到来了,然后让处 理器恢复到它以前运行的状态,其余的处理稍后再进行(如把数据移入一个缓冲区,接受数 据的进程就可以在缓冲区找到数据)。因此,内核把中断处理分为两局部:前半局部(top half) 和后半局部(bottom half),前半局部内核立即执行,而后半局部留着稍后处理。
首先,一个快速的“前半局部”来处理硬件发出的请求,它必须在一个新的中断产生之 前终止。通常地,除了在设备和一些内存缓冲区(如果你的设备用到了 DMA,就不止这些) 之间移动或传送数据,确定硬件是否处于健全的状态之外,这一局部做的工作很少。
然后,就让一些与中断处理相关的有限个函数作为“后半局部”来运行:
•允许一个普通的内核函数,而不仅仅是服务于中断的一个函数,能以后半局部的身 份来运行。
•允许几个内核函数合在一起作为一个后半局部来运行。
后半局部运行时是允许中断请求的,而前半局部运行时是关中断的,这是二者之间的主要区 别.内核函数mmap的实现原理,机制?
6•驱动里面为什么要有并发、互斥的控制?如何实现?讲个例子?
7 . spinlock自旋锁是如何实现的?
8 .任务调度的机制?
【二、本人碰到】.嵌入式linux和wince操作系统的特点和特性?
1 .嵌入式linux中tty设备驱动的体系结构?
2 .嵌入式设备,为加快启动速度,可以做哪些方面的优化?
3 . USB设备的枚举过程?
4 .PSRAM、SDRAM、DDR、DDR2 的时序特性?
5 . I2C触摸屏芯片与CPU的数据传输流程?画出相关图例?(这题目记得不是太清楚了, 大概是考查I2C设备驱动的数据传输过程)面试题2:写出bool、int、float,指针变量与“零值”比拟的if语句
bool 型数据:if( flag ){A;} else { B; }int 型数据:if( 0 != flag ){A;} else { B; }
指针型数:if( NULL == flag ) {A;} else { B; }float 型数据:if ((flag >= NORM ) && (flag <= NORM )){A;
2}
注意:应特别注意在int、指针型变量和“零值”比拟的时候,把“零值”放在左边,这样当把“二=" 误写成“二”时,编译器可以报错,否那么这种逻辑错误不容易发现,并且可能导致很严重的后 果。
面试题3: sizeof和strlen的区别sizeof和strlen有以下区别:
sizeof是一个操作符,strlen是库函数。0
sizeof的参数可以是数据的类型,也可以是变量,而strlen只能以结尾为,\0'的字符串作参 数。9
编译器在编译时就计算出了 sizeof的结果。而strlen函数必须在运行时才能计算出来。并 且sizeof计算的是数据类型占内存的大小,而strlen计算的是字符串实际的长度。0
数组做sizeof的参数不退化,传递给strlen就退化为指针了。0注意:有些是操作符看起来像是函数,而有些函数名看起来又像操作符,这类容易混淆的名 称一定要加以区分,否那么遇到数组名这类特殊数据类型作参数时就很容易出错。最容易混淆 为函数的操作符就是sizeofo
面试题4: C语言的关键字static和C++的关键字static有什么区别在C中static用来修饰局部静态变量和外部静态变量、函数。而C++中除了上述功能外, 还用来定义类的成员变量和函数。即静态成员和静态成员函数。
注意:编程时static的记忆性,和全局性的特点可以让在不同时期调用的函数进行通信,传 递信息,而C++的静态成员那么可以在多个对象实例间进行通信,传递信息。
面试题5: C中的malloc和C+ +中的new有什么区别malloc和new有以下不同:
(1) new、delete是操作符,可以重载,只能在C++中使用。
(2) malloc、free是函数,可以覆盖,C、C++中都可以使用。
(3) new可以调用对象的构造函数,对应的delete调用相应的析构函数0
(4) malloc仅仅分配内存,free仅仅回收内存,并不执行构造和析构函数
(5) new、delete返回的是某种数据类型指针,malloc、free返回的是void指针。
注意:malloc申请的内存空间要用free释放,而new申请的内存空间要用delete释放,不 要混用。因为两者实现的机理不同。
面试题 6:写一个“标准”宏 MIN #define min(a,b)((a)<=(b)?(a):(b))注意:在调用时一定要注意这个宏定义的副作用,如下调用:((++*p)v=(x)?(++*p):(x)。
p指针就自加了两次,违背了 MIN的本意。
3面试题7: 一个指针可以是volatile吗
可以,因为指针和普通变量一样,有时也有变化程序的不可控性。常见例:子中断服务子程 序修改一个指向一个buffer的指针时,必须用volatile来修饰这个指针。
说明:指针是一种普通的变量,从访问上没有什么不同于其他变量的特性。其保存的数值是 个整型数据,和整型变量不同的是,这个整型数据指向的是一段内存地址。
面试题8: a和&a有什么区别请写出以下代码的打印结果,主要目的是考察a和&a的区别。#include<stdio.h> void main( void ) {int a[5]={1,2,3,4,5}; int *ptr=(int *)(&a+1); printf(n%d,%d",*(a+1 ),*(ptr-1)); return;}
输出结果:2, 5o注意:数组名a可以作数组的首地址,而&a是数组的指针。思考,将原式的int*ptr=(int
*)(&a+1);改为int *ptr=(int *)(a+1);时输出结果将是什么呢?
面试题9:简述C、C++程序编译的内存分配情况C、C++中内存分配方式可以分为三种:
(1)从静态存储区域分配:
内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在。速度快、不容易 出错,因为有系统会善后。例如全局变量,static变量等。
(2)在栈上分配:
在执行函数时,函数内局部变量的存储单元都在栈上创立,函数执行结束时这些存储单元自 动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3)从堆上分配:
即动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负 责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活。如 果在堆上分配了空间,就有责任回收它,否那么运行的程序会出现内存泄漏,另外频繁地分配 和释放不同大小的堆空间将会产生堆内碎块。
一个C、C++程序编译时内存分为5大存储区:堆区、栈区、全局区、文字常量区、程序代 码区C4
面试题10:简述strcpy> sprintf与memcpy的区别三者主要有以下不同之处:
(1)操作对象不同,strcpy的两个操作对象均为字符串,sprintf的操作源对象可以是多种 数据类型,目的操作对象是字符串,memcpy的两个对象就是两个任意可操作的内存地址, 并不限于何种数据类型。
(2)执行效率不同,memcpy最高,strcpy次之,sprintf的效率最低。
(3)实现功能不同,strcpy主要实现字符串变量间的拷贝,sphntf主要实现其他数据类型 格式到字符串的转化,memcpy主要是内存块间的拷贝。
说明:strcpy> sprintf与memcpy都可以实现拷贝的功能,但是针对的对象不同,根据实际 需求,来选择合适的函数实现拷贝功能。
面试题11 :设置地址为0x67a9的整型变量的值为0xaa66 int *ptr; ptr = (int *)0x67a9; *ptr = 0xaa66;说明:这道题就是强制类型转换的典型例子,无论在什么平台地址长度和整型数据的长度是 一样的,即一个整型数据可以强制转换成地址指针类型,只要有意义即可。
面试题12:面向对象的三大特征面向对象的三大特征是封装性、继承性和多态性:
封装性:将客观事物抽象成类,每个类对自身的数据和方法实行protection (private, protected, public)。0
继承性:广义的继承有三种实现形式:实现继承(使用基类的属性和方法而无需额外编码 的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实 现滞后到子类实现)。0
多态性:是将父类对象设置成为和一个或更多它的子对象相等的技术。用子类对象给父类 对象赋值之后,父类对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。0 说明:面向对象的二个特征是实现面向对象技术的关键,每一个特征的相关技术都非常的复 杂,程序员应该多看、多练。
面试题13: C++的空类有哪些成员函数
缺省构造函数。。
缺省拷贝构造函数。e
缺省析构函数。。
缺省赋值运算符。9
缺省取址运算符。0
缺省取址运算符consto e注意:有些书上只是简单的介绍了前四个函数。没有提及后面这两个函数。但后面这两个函 数也是空类的默认函数°另外需要注意的是,只有当实际使用这些函数的时候,编译器才会 去定义它们。
5面试题14:谈谈你对拷贝构造函数和赋值运算符的认识
拷贝构造函数和赋值运算符重载有以下两个不同之处:
(1)拷贝构造函数生成新的类对象,而赋值运算符不能。
(2)由于拷贝构造函数是直接构造一个新的类对象,所以在初始化这个对象之前不用检验 源对象是否和新建对象相同。而赋值运算符那么需要这个操作,另外赋值运算中如果原来的对 象中有内存分配要先把内存释放掉注意:当有类中有指针类型的成员变量时,一定要重写拷贝构造函数和赋值运算符,不要使 用默认的。
面试题15:用C++设计一个不能被继承的类template <typename T> class A {friend T; private: A() {}〜A() {}}; class B : virtual public A<B> { public: B() {}〜B() {}}; class C : virtual public B { public: C() {}〜C() {}}; void main( void ) { B b; //C c; return;}注意:构造函数是继承实现的关键,每次子类对象构造时,首先调用的是父类的构造函数, 然后才是自己的。
面试题16:访问基类的私有虚函数写出以下程序的输出结果:#include <iostream.h> class A
6{ virtual void g() { cout« ”A::g" « endl;} private: virtual void f() { cout«« endl;}};
class B : public A { void g() { cout « "B::g" « endl;} virtual void h() { cout ««endl;}}; typedef void( *Fun )( void ); void main() { B b; Fun pFun; for(int i = 0 ; i < 3; i++)
{ pFun = ( Fun )*( (int*) * (int* )(&b) + i); pFun();}}输出结果:B::g A::f B::h
注意:此题主要考察了面试者对虚函数的理解程度。一个对虚函数不了解的人很难正确的做 出此题。在学习面向对象的多态性时一定要深刻理解虚函数表的工作原理。
面试题17:简述类成员函数的重写、重载和隐藏的区别
(1)重写和重载主要有以下几点不同。
范围的区别:被重写的和重写的函数在两个类中,而重载和被重载的函数在同一个类中。。 参数的区别:被重写函数和重写函数的参数列表一定相同,而被重载函数和重载函数的参 数列表一定不同。。
virtual的区别:重写的基类中被重写的函数必须要有virtual修饰,而重载函数和被重载函 数可以被07
virtual修饰,也可以没有。
(2)隐藏和重写、重载有以下几点不同°
与重载的范围不同:和重写一样,隐藏函数和被隐藏函数不在同一个类中。0
参数的区别:隐藏函数和被隐臧的函数的参数列表可以相同,也可不同,但是函数名肯定 要相同。当参数不相同时,无论基类中的参数是否被virtual修饰,基类的函数都是被隐藏, 而不是被重写。0说明:虽然重载和覆盖都是实现多态的基础,但是两者实现的技术完全不相同,到达的目的 也是完全不同的,覆盖是动态态绑定的多态,而重载是静态绑定的多态。
面试题18:简述多态实现的原理编译器发现一个类中有虚函数,便会立即为此类生成虚函数表vtableo虚函数表的各表项 为指向对应虚函数的指针。编译器还会在此类中隐含插入一个指针• vptr (对vc编译器来说, 它插在类的第一个位置上)指向虚函数表。调用此类的构造函数时,在类的构造函数中,编 译器会隐含执行vptr与vtable的关联代码,将vptr指向对应的vtable,将类与此类的vtable 联系了起来。另外在调用类的构造函数时,指向基础类的指针此时已经变成指向具体的类的 this指针,这样依靠此this指针即可得到正确的vtable,。如此才能真正与函数体进行连接, 这就是动态联编,实现多态的基本原理。
注意:一定要区分虚函数,纯虚函数、虚拟继承的关系和区别。牢记虚函数实现原理,因为 多态C++面试的重要考点之一,而虚函数是实现多态的基础。
面试题19:链表和数组有什么区别数组和链表有以下几点不同:
(1)存储形式:数组是一块连续的空间,声明时就要确定长度。链表是一块可不连续的动 态空间,长度可变,每个结点要保存相邻结点指针。
(2)数据查找:数组的线性查找速度快,查找操作直接使用偏移地址。链表需要按顺序检 索结点,效率低。
(3)数据插入或删除:链表可以快速插入和删除结点,而数组那么可能需要大量数据移动。 (4)越界问题:链表不存在越界问题,数组有越界问题。
说明:在选择数组或链表数据结构时,一定要根据实际需要进行选择。数组便于查询,链表 便于插入删除。数组节省空间但是长度固定,链表虽然变长但是占了更多的存储空间。
面试题20:怎样把一个单链表反序
(1)反转一个链表。循环算法。
展开阅读全文