您的位置:首页 > 编程语言 > C语言/C++

C/C++面试总结必考题 2

2015-03-10 22:31 274 查看
四 C++与QT(类:具有共性的实体的抽象。)
3.Windows程序的入口是哪里?写出Windows消息机制的流程。
答:
Windows程序的入口是WinMain函数
消息机制:系统将会维护一个或多个消息队列,所有产生的消息都会被放入或是插入队列中。系统会在队列中取出每一条消息,根据消息的接收句柄而将该消息发送给拥有该窗口的程序的消息循环。每一个运行的程序都有自己的消息循环,在循环中得到属于自己的消息并根据接收窗口的句柄调用相应的窗口过程。而在没有消息时消息循环就将控制权交给系统。
1. 面向对象的三个基本特征,并简单叙述之?
答:1)封装:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected,public)
2)继承:实现继承(指使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承 ( 仅使用属性和方法,实现滞后到子类实现)。
3)多态:允许将子类类型的指针赋值给父类类型的指针。

(1). 多态的作用?

答:主要是两个:1)隐藏实现细节,使得代码模块化。
2)类的继承与派生的时候,接口重用。

2. 重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?

答:从定义上来说:

重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

重写:是指子类重新定义复类虚函数的方法。

从实现原理上来说:

重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数。

重写:当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期
间是无法确定的(调用的子类的虚函数的地址无法给出)。
3、使用new与malloc分配内存有什么区别?
1、new 是c++中的操作符,malloc是c 中的一个函数
2、new 不止是分配内存,而且会调用类的构造函数,同理delete会调用类的析构函数,而malloc则只分配内存,不会进行初始化类成员的工作,同样free也不会调用析构函数
3、内存泄漏对于malloc或者new都可以检查出来的,区别在于new可以指明是那个文件的那一行,而malloc没有这些信息。
4、new 和 malloc效率比较
new可以认为是malloc加构造函数的执行。

new出来的指针是直接带类型信息的。
而malloc返回的都是void指针

4. C++中,关键字struct和class的区别仅仅在于:
struct定义的类的缺省成员为公有的,而class定义的类的缺省成员为私有的;
5. C++函数中值的传递方式有哪几种?

答:C++函数的三种传递方式为:值传递、指针传递和引用传递。

7、构造函数可以是虚函数吗?为什么?
答:不可以,创建对象时必须确定类型。

8、析构函数可以是虚函数吗?为什么?
答:可以。释放指向子类的基类指针时,不会造成内存泄露。默认的析构函数不是虚的,当类中至少有一个虚函数时,
需要虚析构函数。

9、C++语言中的static关键字的作用是什么?
答:
在函数体内,一个被声明为静态的变量在这函数被调用过程中维持其值不变。
在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所有函数访问,但不能被模块外的其他函数所问。
在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。

10、 面向对象的程序设计思想是什么?
答:把数据结构和对数据结构进行操作的方法封装形成一个个的对象。

11、什么是类?
答:把一些具有共性的对象归类后形成一个集合,也就是类。

12、对象都具有两方面特征是什么?分别是什么?
答:对象具有的特征是静态特征与动态特征。
静态特征是只能描述对象的属性(成员变量),动态属性是指对象表现出来的行为(成员函数)

13、在头文件中进行声明,在对应的实现文件中进行类的定义有什么意义?
答:这样可以提高编译效率只要编译一次对应的.obj文件后,再次应用该类的地方,这样类就无法再次编译,从而提高编译效率。

14、在类的内部定义成员函数的函数体,这种函数会具备那种属性?
答:这种函数会自动为内联函数,这种函数在函数调用的地方在编译阶段都会进行代码替换。

15. 成员函数通过什么来区分不同对象的成员数据?为什么它能够区分?
答:通过this指针指向对象的首地址来区分的。

16、C++编译器自动为类产生的四个缺省函数是什么?
答:默认构造函数,拷贝构造函数,析构函数,赋值函数。

18. 构造函数与普通函数相比在形式上有什么不同?(构造函数的作用,它的声明形式来分析)
答:构造函数是类的一种特殊成员函数,一般情况下,它是专门用来初始化对象成员变量的。
构造函数的名字必须与类名相同,它不具有任何类型,不返回任何值。

19、. 什么时候必须重写拷贝构造函数?
答:当构造函数涉及到动态存储分配空间时,要自己写拷贝构造函数,并且要深拷贝。

20. 构造函数的调用顺序是什么?
答:
1.先调用基类构造函数
2.按声明顺序初始化数据成员
3.最后调用自己的构造函数。

21、 哪几种情况必须用到初始化成员列表?
答:类的成员是常量成员初始化;
类的成员是对象成员初始化,而该对象没有无参构造函数。
类的成员为引用时。

22、 什么是常对象?
答:常对象是指在任何场合都不能对其成员的值进行修改的对象。

23、静态函数存在的意义?
静态私有成员在类外不能被访问,可通过类的静态成员函数来访问;
当类的构造函数是私有的时,不像普通类那样实例化自己,只能通过静态成员函数来调用构造函数。

24、在类外有什么办法可以访问类的非公有成员?
答:友元,继承,公有成员函数。

25、 什么叫抽象类?
答:不用来定义对象而只作为一种基本类型用作继承的类。

26、 运算符重载的意义?
答:为了对用户自定义数据类型的数据的操作与内定义的数据类型的数据的操作形式一致。

27、不允许重载的5个运算符是哪些?
答:
1. .*(成员指针访问运算符号)
2. ::域运算符
3. Sizeof 长度运算符号
4. ?:条件运算符号
5. .(成员访问符)

28、 运算符重载的三种方式?
答:普通函数,友元函数,类成员函数。

29、 流运算符为什么不能通过类的成员函数重载?一般怎么解决?
答:因为通过类的成员函数重载必须是运算符的第一个是自己,而对流运算的重载要求第一个参数是流对象。所以一般通过友元来解决。

30、 赋值运算符和拷贝构造函数的区别与联系?
答:相同点:都是将一个对象copy到另一个中去。
不同点:拷贝构造函数涉及到要新建立一个对象。
拷贝构造函数:complex A(100); example B=A;

31、 拷贝构造函数在哪几种情况下会被调用?
答:1.当类的一个对象去初始化该类的另一个对象时;
2.如果函数的形参是类的对象,调用函数进行形参和实参结合时;
3.如果函数的返回值是类对象,函数调用完成返回时。

32、对象间是怎样实现数据的共享的?
答:通过类的静态成员变量来实现对象间的数据共享。静态成员变量占有自己独立的空间不为某个对象所私有。

33、 友元关系有什么特性?(类的外部访问类的私有成员)
答:单向的,非传递的,不能继承的。
34、内联函数和宏的区别在于:
宏是由预处理器对宏进行替代,
而内联函数是通过编译器控制来实现的。

35、 结构与联合有和区别?
1. 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员
的存放地址不同)。

2. 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。

36、用什么函数开启新进程、线程。 (4 分 )
答:CreateProccess()创建进程;
CreateThread()创建线程
MFC中还提供了_beginthread()与_beginthreadex()函数创建线程

MFC中SendMessage和PostMessage的区别?

答:PostMessage 和SendMessage的区别主要在于是否等待应用程序做出消息处理。
PostMessage只是把消息放入队列,然后继续执行;
而SendMessage必须等待应用程序处理消息后才返回继续执行。
这两个函数的返回值也不同,
PostMessage的返回值表示PostMessage函数执行是否正确,
而SendMessage的返回值表示其他程序处理消息后的返回值。
38. MFC 中,大部分类是从哪个类继承而来( CCmdTarget 、 CObject 、 CWinApp 、 CWnd )? (2 分)__CObject
__

39. WaitForSingleObject 有何作用;
m_pThrd 的类型是 CWinThread* 时, WaitForSingleObject(m_pThrd->m_hThread,INFINITE); 有何作用。 (4 分 )
答:WaitForSingleObject是表示等待线程的一个函数。参数为INFINITE表示一直等待线程CWinThread执行结束后,再继续处理自身程序。

6. __stdcall 、 __cdecl 、 __pascal 在什么方面有所不同。 (4 分 )
答:这些都是一些函数参数的调用约定,告诉编译器函数参数压栈的顺序,以及压入堆栈的内容由谁来清除,是调用者还是函数本身清除堆栈的内容。简单列表如下:
Directive Parameter order Clean-upPasses parameters in registers?

pascal Left-to-right Routine No

cdecl Right-to-left Caller No

stdcall Right-to-left Routine No

1、为什么要使用命名空间?
解决命名冲突的问题。定义类的名称以及不同厂商。
2、内联函数和宏的区别
宏是由预处理器对宏进行替代,而内联函数是通过编译器控制来实现的。
3、void func(intx,int y = 40,int z = 49);
// 只能在声明时设置默认参数 缺省参数都必须是从右到左定义 ,使用时却是从左到右。
4、只要函数参数的类型不同,或者参数的个数不同,或者二者兼而有之,两个或两个以上
的函数可以使用相同的函数名

5、引用与指针有什么区别?
1) 引用必须被初始化,指针不必。
2) 引用初始化以后不能被改变,指针可以改变所指的对象。
2) 不存在指向空值的引用,但是存在指向空值的指针。

6、结构与类的区别:

默认访问权限不同。

struct 默认public;

class默认为private;
数据成员可以是任何类型,但是不能用auto,register,extern。

4、调用析构函数的条件:

1、对象自动退出生命周期2、程序员手动释放对象指针。

5、delete 与 delete [] 区别
delete 只会调用一次析构函数,而 delete[] 会调用每一个成员的析构函数。
6、虚函数的作用?
接口重用
2.构造函数可以是虚函数吗?为什么?

答:不可以,创建对象时必须确定类型。从内存分配,虚函数的用处等方面来讲都可以。

3.析构函数可以是虚函数吗?为什么?

答:可以。释放指向子类的基类指针时,不会造成内存泄露。默认的析构函数不是虚的,当类中至少有一个虚函数时,需要虚析构函数。

7. MFC中CString是类型安全类么?
答:不是,其它数据类型转换到CString可以使用CString的成员函数Format来转

五 平台与驱动部分
1、 问:Bootloader在嵌入式系统中处于什么地位?bootloader的主要作用是什么?
答:Bootloader 是系统加电后、内核运行之前执行的一段代码,处于嵌入式系统的最底层。
Bootloader的主要作用有两个:一、为启动内核准备好正确的软硬件环境,软件主要指堆、栈等,硬件主要指内存、系统时钟等,最终将内核由固态存储器加载到内存中;二是为更新、备份、恢复系统提供控制平台。

u-boot的配置与编译过程:
配置u-boot :例如运行make 名字_config
调用mkconfig脚本文件。


2、问:简述s3c2440 NAND/NOR两种启动方式的异同?
答:
Nor启动:
系统加电后会从0x000000开始的三总线位置读取第一条指令进行工作,norFLASH采用总线结构,可以直接连在三总线的0x00000位置上,所以将bootloader烧到norflash 0x0000位置上,系统加电后即可运行bootloader的第一条代码,单片机一般采用此种启动方式。
优点:硬件连接简单、可靠
缺点:nor flash由于结构的原因,容量一般做不了太大,而且其读写速度也较慢。
Nand启动:
因为nand不支持总线线性寻址,所以CPU会从nand自动拷4K代码到内部RAM,并从这段RAM开发运行程序,所以这4k代码往往是bootloader的第一阶段代码,其作用为将bootloadr的主要部分搬到内存中运行,然后进行后续工作
优点:此方案充分利用了nand大容量存储、sdram高速运行的特点,解决了嵌入式系统存储与运行的容量与速度问题
缺点:中间包含了多次的搬运过程,效率稍稍有些低。
3、 问:为什么bootloader大多由两阶段启动构成?以你熟悉的bootloader为例讲解一下两阶段分别干什么事情?
答:bootloader会直接对硬件进行操作,为了分离硬件相关性,一般bootloader有两部分代码组成,第一部分一般由汇编完成,完成与体系结构相关代码、功能的实现。
第二部分由C语言完成,完成与系统机构无关的通用功能的实现。
vivi的stage1实际完成的主要任务://引导内核,从flash拷贝到sdram。
1. 禁用看门狗、关闭所有中断、初始化系统时钟
2. 设置S3C2410的和内存相关的13个寄存器
3. 初始化调试指示灯(可选)
4. 初始化UART,作为调试口(可选)
5. 从NAND或NOR FLASH复制代码到SDRAM
6. 跳转到main,进入stage2
vivi的stage2实际完成的主要任务 //启动内核
1. step1:打印版本信息
2. step2:初始化GPIO
3. step3:MMU初始化
4. step4:堆初始化
5. step5:MTD设备初始化
6. step6:存放vivi的私有参数
7. step7:添加vivi支持的命令
8. step8:根据用户选择进入vivi命令模式或启动内核

4、 问:Linux内核由哪几部分组成,各自有什么作用?
答:进程管理:管理linux中的任务调度,比如多进程、多线程、信号、进程间通信等
内存管理:管理进程调度中伴随的内存分配与释放
文件系统管理:管理系统中的存储设备,如:U盘、SD卡、FLASH、硬盘等
设备管理:管理系统中的各种字符设备,如LCD、触摸屏、串口、传感器等
网络管理:管理系统中的网络设备,为用户提供各种网络服务

5、 问:简述Linux模块编程的含义及意义
答:Linux中采用了模块的机制,允许用户将内核代码如驱动等编译成模块,而不是直接编译进内核
这样可以有效的减小内核的开发周期,减小最终内核的体积,避免调试bug对内核的影响,使得开发更加迅速。

6、 问:Linux有哪几种常见的根文件系统格式?简述其各自特点?
答:cramfs/jffs2/yaffs/yaffs2/
yaffs/yaffs2是专为嵌入式系统使用NAND型闪存而设计的一种日志型文件系统,其特点是可读可写。
cramfs是Linux的创始人 Linus Torvalds参与开发的一种只读的压缩文件系统
在cramfs文件系统中,每一页(4KB)被单独压缩,可以随机页访问,其压缩比高达2:1,为嵌入式系统节省大量的Flash存储空间,使系统可通过更低容量的FLASH存储相同的文件,从而降低系统成本
JFFS文件系统最早是由瑞典Axis Communications公司基于Linux2.0的内核为嵌入式系统开发的文件系统。JFFS主要用于NOR型闪存,基于MTD驱动层。
7、问:简述boa服务器与CGI程序通信过程?
答:通过Internet把用户请求送到服务器,服务器接收用户请求并交给CGI程序处理,CGI程序把处理结果传送给服务器,服务器把结果送 回到用户。

8、问:同步与异步串行通信息的区别?
答:同步是通信息双方使用同一时钟线,而一但时钟线太长就容易受到干扰,如SPI,I2C等等,所以常用于短距离通信;而异步通信是双方使用各自的时钟,如uart、USB等,传输距离更远。

9、问:设备驱动框架中的宏描述信息那一个是不能省略的:
答:MODULE_LICENSE("GPL");即GPL是不能省的。

10、问:设备驱动开发中,常用到 __init __exit声明函数,其作用是什么?
答:表示被修饰的函数所占内存资源用完是可以回收的。

11、问:驱动开发中用到的各个寄存器地址,物理地址吗?如果不是那怎么得到虚拟地址的?
答:不是物理地址,是通过ioremap()宏进行重映射的。

12、问:驱动开发中,用于并发操作保护的信号量和自旋锁有什么区别?
答:信号量是睡眠锁,等待期间不占用CPU资源,但唤醒切换时很消耗时间,所以常用于使用不态频繁且阻塞时间较长的地方;而自旋锁是忙等待,即会被CPU调度,所以不能长时间等待,用于等待时间比较短或频繁使用的地方。

13、问:内核中的工作队列是作什么用的?
答:用于某些函数需要延时处理的地方,也常用于中断下半部,从而缩短中断服务程序的处理的时间。

14、.怎样实现并发控制

答:用到锁和事务处理,做为一个事务的应用程序访问一个表时,用锁对该表设置一个优先级,如果设置成功就进行下一步操作,不成功的话就事务回滚,返回到最初状态,保证一个程序操作完数据库后,才允许其它程序操作
15.Linux驱动程序流程及功能。
设备驱动程序的功能:

对设备初始化和释放
把数据从内核传送到硬件和从硬件读取数据
读取应用程序传送给设备文件的数据和回送应用程序请求的数据
检测和处理设备出现的错误

16、 Linux内核引导时,从文件/etc/fstab中读取要加载的文件系统。

17、什么是GPIO寄存器?
GPIO寄存器就是cpu分配给GPIO的地址。
使用软件访问这些地址就可以访问对应的硬件引脚。
分类:
上拉寄存器、 控制寄存器、驱动寄存器、数据寄存器

常见问题:
char a[] = “hello”;
a[0] = ‘X’;
cout << a<< endl;
char *p = “world”; // 注意p指向常量字符串
p[0] = ‘X’; // 编译器不能发现该错误
cout << p<< endl;
常量字符串不能被修改
注意:当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针
四、有关内存的思考题(这个题目见一次考一次)



void GetMemory(char *p)

{

p = (char *)malloc(100);

}

void Test(void)

{

char *str = NULL;

GetMemory(str);

strcpy(str, "hello world");

printf("%s", str);

}



请问运行Test函数会有什么样的结果?

答:str并没有指向新开辟的内存空间,出段错误,访问了不该访问的内存



char *GetMemory(void)

{

char p[] = "hello world";

return p;

}

void Test(void)

{

char *str = NULL;

str = GetMemory();

printf("%s", str);

}



请问运行Test函数会有什么样的结果?

答:打印结果不确定

void GetMemory2(char **p, int num)

{

*p = (char *)malloc(num);

}

void Test(void)

{

char *str = NULL;

GetMemory(&str, 100);

strcpy(str, "hello");

printf("%s", str);

}

请问运行Test函数会有什么样的结果?

答:打印出hello,有可能存在内存泄露问题





void Test(void)

{

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

strcpy(str, “hello”);

free(str);

if(str != NULL)

{

strcpy(str, “world”);

printf("%s", str);

}

}

请问运行Test函数会有什么样的结果?

答: 打印出world,也有可能出段错误,因为访问未知的内存空间



六、编写strcpy函数

已知strcpy函数的原型是

char*strcpy(char *strDest, const char *strSrc);

其中strDest是目的字符串,strSrc是源字符串。



(1)不调用C++/C的字符串库函数,请编写函数 strcpy

char *strcpy(char*strDest, const char *strSrc);{    assert((strDest!=NULL) && (strSrc !=NULL));    //2分   assert 是个宏 如果条件为假整个程序将退出 ,可自己判断    char *address = strDest;                                 //2分   while( (*strDest++ = * strSrc++) != ‘\0’)            // 2分      ;    return address ;                                              //2分}


(2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?

为了支持链式操作,即可以将函数的返回值做为另一个函数的参数。
如:strcpy(strDest,strcpy(strDest1,strSrc));

可以将strSrc copy到strDest1,strDest。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: