笔试(一)

1.C++程序中各种数据存储的位置

int a = 0; //全局数据区
char *p1; //全局数据区,分配该区时内存全部清零

main() {
int b; 栈
char s[ ] = "abc"; // 栈
char *p2; // 栈
char *p3 = "123456"; //123456\0在常量区,p3在栈上。
static int c = 0; // 全局数据区

p1 = (char *)malloc(10);
p2 = (char *)malloc(20); //分配得来得10和20字节的区域就在自由数据区。

strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456" 优化成一个地方。
}

总结:

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

栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量存储区。里面的变量通常是局部变量、函数参数等。

堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。

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

全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。

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

2.  %   &   .  &&   <=   = 那个优先级别最高

.  &    %   <=   &&    =

3. 以下哪些通信方式是可靠的通讯方式   

(1)信号 (2)管道 (3)消息 (4)tcp (5)udp (6)串口I/O  

可靠:信号,管道,tcp

4.(M)?(a++):( a--),此处的M与下面哪一项是等价

A,M==O,B,M==1,C,M!=O,D,M!=1

答案:C

5. Unix的启动顺序?

UNIX系统的启动过程如下:
1 用户打开计算机电源。
2 计算机自动执行ROM引导程序。
3 将第一块硬盘的boot区调入内存并执行。硬盘的boot区存有硬盘的分区信息和驱动程序。
4 将硬盘的活动分区上的bootstrap程序调入内存并执行。bootstrap程序位于该活动分区上的第0号块中。
5 将UNIX的启动程序/boot调入内存并执行。
6 将UNIX的内核程序/unix调入内存并执行。
7 检测并配置内存和硬件设备。
8 启动/etc/init进程。init将/etc/inittab调入内存,并根据启动层次的不同,选择/etc/inittab内不同的程序来执行。对于多用户来说,init会执行/sbin/bcheckrc和/sbin/brc进程,最后由/sbin/rc2进程将系统带入多用户使用环境,并为每个终端启动/etc/getty一个进程等待接收用户的登录。

6. 数制转换151转2进制和九进制

10010111,177

7. 在linux下,查看目录大小的命令是:du –sh dirname

8. 修改文件属性的命令是:chomd

9.切换为其他用户身份的命令是:su

10.

11. 插入排序算法。
有一个数组a[0] 到 a[i-1]为从小到大排序,a[i]到a[count-1]没有排序,请您添加3条语句使它们按照从小到大排序。

int insert_sort(int a[],int count)
{
for(int i=1;i<count;++i)
{
int j,t;
t=a[i];
(j=i-1; )
while(j>=0&&t<a[j])
{
(a[j+1]=a[j];)
j--;
}
(a[j+1]=t;)
}
return 0;
}

12. 异步socket编程中,send不出数据的错误码是什么,(举Linux或Windows为例),你是怎么处理的?

非阻塞SOCKET,SEND不出数据的原因有2个吧,TCP下连接断开了和该SOCKET处在阻塞状态(也就是说在发送数据中)。UPD发不出只有TCP后面的情况。

处理的办法就是记录下该SOCKET的状态,当状态为阻塞的时间,放入缓冲,当该SOCKET再次可写时,发送。

13.

malloc/free与new/delete的区别

相同点:都可用于申请动态内存和释放内存
不同点:
(1)操作对象有所不同。
malloc与free是C++/C 语言的标准库函数,new/delete 是C++的运算符。对于非内部数据类的对象而言,光用maloc/free 无法满足动态对象的要求。对象在创建的同时要自动执行构造函数, 对象消亡之前要自动执行析构函数。由于malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加malloc/free。

(2)用法上也有所不同。
函数malloc 的原型如下:
void * malloc(size_t size);
用malloc 申请一块长度为length 的整数类型的内存,程序如下:
int *p = (int *) malloc(sizeof(int) * length);
我们应当把注意力集中在两个要素上:“类型转换”和“sizeof”。
1、malloc 返回值的类型是void *,所以在调用malloc 时要显式地进行类型转换,将void * 转换成所需要的指针类型。
2、 malloc 函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。
函数free 的原型如下:
void free( void * memblock );
为什么free 函数不象malloc 函数那样复杂呢?这是因为指针p 的类型以及它所指的内存的容量事先都是知道的,语句free(p)能正确地释放内存。如果p 是NULL 指针,那么free
对p 无论操作多少次都不会出问题。如果p 不是NULL 指针,那么free 对p连续操作两次就会导致程序运行错误。


new/delete 的使用要点:
运算符new 使用起来要比函数malloc 简单得多,例如:
int *p1 = (int *)malloc(sizeof(int) * length);
int *p2 = new int[length];
这是因为new 内置了sizeof、类型转换和类型安全检查功能。对于非内部数据类型的对象而言,new 在创建动态对象的同时完成了初始化工作。如果对象有多个构造函数,那么new 的语句也可以有多种形式。
如果用new 创建对象数组,那么只能使用对象的无参数构造函数。例如
Obj *objects = new Obj[100]; // 创建100 个动态对象
不能写成
Obj *objects = new Obj[100](1); // 创建100 个动态对象的同时赋初值1
在用delete 释放对象数组时,留意不要丢了符号‘[]’。例如
delete []objects; // 正确的用法
delete objects; // 错误的用法
后者相当于delete objects[0],漏掉了另外99 个对象。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

1、new自动计算需要分配的空间,而malloc需要手工计算字节数
2、new是类型安全的,而malloc不是,比如:
int* p = new float[2]; // 编译时指出错误
int* p = malloc(2*sizeof(float)); // 编译时无法指出错误
new operator 由两步构成,分别是 operator new 和 construct
3、operator new对应于malloc,但operator new可以重载,可以自定义内存分配策略,甚至不做内存分配,甚至分配到非内存设备上。而malloc无能为力
4、new将调用constructor,而malloc不能;delete将调用destructor,而free不能。
5、malloc/free要库文件支持,new/delete则不要。

14.VC中有哪些方法避免C编程中的头文件重复包含:

#ifndef   !!!! #def !!!! #endif 

15.在C++中extern c的作用  (按键转换,比如点击p输出q) 

作为extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。 

extern "C"是连接申明(linkage declaration),被extern "C"修饰的变量和函数是按照C语言方式编译和连接的

16.编程中异步IO和同步IO有什么区别?说说你可知道的几种IO?

IO基本概念
Linux的内核将所有外部设备都可以看做一个文件来操作。那么我们对与外部设备的操作都可以看做对文件进行操作。我们对一个文件的读写,都通过调用内核提供的系统调用;内核给我们返回一个file descriptor(fd,文件描述符)。对一个socket的读写也会有相应的描述符,称为socketfd(socket描述符)。描述符就是一个数字(可以理解为一个索引),指向内核中一个结构体(文件路径,数据区,等一些属性)。应用程序对文件的读写就通过对描述符的读写完成。
一个基本的IO,它会涉及到两个系统对象,一个是调用这个IO的进程对象,另一个就是系统内核(kernel)。

一般来说,服务器端的I/O主要有两种情况:一是来自网络的I/O;二是对文件(设备)的I/O。
首先一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作,

同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO、非阻塞IO、IO复用、信号驱动IO都是同步IO,如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,那么就是异步IO。

阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。

当一个read操作发生时,会经过如下流程:
通过read系统调用想内核发起读请求。
内核向硬件发送读指令,并等待读就绪。
内核把将要读取的数据复制到描述符所指向的内核缓存区中。
将数据从内核缓存区拷贝到用户进程空间中。

同步:所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。
异步:异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。

同步IO和异步IO是针对应用程序和内核的交互而言的。
同步IO指的是用户进程触发I/O操作并等待或者轮询的去查看I/O操作是否就绪。
异步IO是指用户进程触发I/O操作以后就立即返回,继续开始做自己的事情,而当I/O操作已经完成的时候会得到I/O完成的通知。

同步IO在读取数据时,都要在同步流程中进行一次内核态到用户态的数据拷贝。
异步IO需要操作系统更强的支持,操作系统开启独立的内核线程去处理IO操作。当read请求的数据到达时,由内核负责读取socket中的数据,并写入用户指定的缓冲区中,最后内核通知用户线程。异步IO接受到内核通知时,已经完成了内核态到用户态的数据拷贝。

IO多路复用

用户首先将需要进行IO操作的socket添加到select中,然后阻塞等待select系统调用返回。当数据到达时,socket被激活,select函数返回。用户线程正式发起read请求,读取数据并继续执行。

从流程上来看,使用select函数进行IO请求和同步阻塞模型没有太大的区别,甚至还多了添加监视socket,以及调用select函数的额外操作,效率更差。但是,使用select以后最大的优势是用户可以在一个线程内同时处理多个socket的IO请求。用户可以注册多个socket,然后不断地调用select读取被激活的socket,即可达到在同一个线程内同时处理多个IO请求的目的。而在同步阻塞模型中,必须通过多线程的方式才能达到这个目的。

IO多路复用方式允许单线程内处理多个IO请求,但是每个IO请求的过程还是阻塞的(在select函数上阻塞),平均时间甚至比同步阻塞IO模型还要长。如果用户线程只注册自己感兴趣的socket或者IO请求,然后去做自己的事情,等到数据到来时再进行处理,则可以提高CPU的利用率。
由于select函数是阻塞的,因此多路IO复用模型也被称为异步阻塞IO模型。注意,这里的所说的阻塞是指select函数执行时线程被阻塞,而不是指socket。一般在使用IO多路复用模型时,socket都是设置为NONBLOCK的,不过这并不会产生影响,因为用户发起IO请求时,数据已经到达了,用户线程一定不会被阻塞。
IO多路复用是最常使用的IO模型,但是其异步程度还不够“彻底”,因为它使用了会阻塞线程的select系统调用。因此IO多路复用只能称为异步阻塞IO,而非真正的异步IO。

“真正”的异步IO需要操作系统更强的支持。在IO多路复用模型中,事件循环将文件句柄的状态事件通知给用户线程,由用户线程自行读取数据、处理数据。而在异步IO模型中,当用户线程收到通知时,数据已经被内核读取完毕,并放在了用户线程指定的缓冲区内,内核在IO完成后通知用户线程直接使用即可。

异步IO

用户线程直接使用内核提供的异步IO API发起read请求,且发起后立即返回,继续执行用户线程代码。不过此时用户线程已经将调用的AsynchronousOperation和CompletionHandler注册到内核,然后操作系统开启独立的内核线程去处理IO操作。当read请求的数据到达时,由内核负责读取socket中的数据,并写入用户指定的缓冲区中。最后内核将read的数据和用户线程注册的CompletionHandler分发给内部Proactor,Proactor将IO完成的信息通知给用户线程(一般通过调用用户线程注册的完成事件处理函数),完成异步IO。

五种IO的模型:阻塞IO、非阻塞IO、多路复用IO、信号驱动IO和异步IO
前四种都是同步IO,在内核数据copy到用户空间时都是阻塞的。
最后一种是异步IO,通过API把IO操作交由操作系统处理,当前进程不关心具体IO的实现,通过回调函数,或者信号量通知当前进程直接对IO返回结果进行处理。

网络编程模型:

1.同步阻塞模型
2.多进程并发模型
3.多线程并发模型
4.IO多路复用(事件驱动)模型

17.怎样解决在vc中内存泄漏的问题(release版本)

(1)放置关键字assert()  (2)生成map文件。它并不往exe文件中添加任何东西,仅仅只是把编译连接时的所有函数入口地址记录在后缀为.map文件。程序崩溃的时候,可以得到一个崩溃时的EIP地址,通过地址可以很容易的查到崩溃所在的函数。(在vc setting下有个link按钮选上generate mapfile)  (3)Release版本也是可以设置断点的,在希望设置断点处加入_asm int 3 (4)熟悉汇编,通过编译时的汇编看出 (5)使用第三方调试器。  (6)关掉发行版中的一些优化选项,生成调试信息。

 

posted @ 2018-03-15 18:03  陈焕彪  阅读(171)  评论(0编辑  收藏  举报