面试题整理

来源:互联网 发布:linux ftp下载速度慢 编辑:程序博客网 时间:2024/06/05 07:40

  • 线程和进程区别和联系。什么是线程安全2012.5.6 百度实习笔试题)

如果说,在操作系统中引入进程的目的,是为了使多个程序能并发执行,以提高资源利用率和系统吞吐量。那么,在操作系统中再引入线程,则是为了减少程序在并发执行时所付出的空间开销,使OS具有更好的并发性。

进程是作为拥有系统资源的基本单位,同时也是一个可独立调度和分派的基本单位(线程也是)。通常进程包含多个线程并为它们提供资源

线程安全:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。   

或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。

  • · CC++怎样分配和释放内存,区别是什么

C: malloc  free   //函数  calloc() 会初始化  realloc 会重置大小

C++:   new  delete  //运算符

C++中内存分为5个区: 堆 栈 全局/静态区 常量区 自由存储区(也有说代码区)

一、先来谈谈在C语言下,动态内存分配和释放的特点。

动态分配内存的定义是这样的,指在程序运行过程中,要申请内存,系统会根据程序的实际情况来分配,分配空间的大小是由程序的需求来决定的。在C语言下面,举个例子,定义一个指针,int *p;此时指针i是一个野指针,是一个指向不确定位置的指针,对它进行操作是很危险的,此时我们需要动态分配内存空间,让i指向它。而有一种形式是这样的,int *p=&b;这并非是一种动态内存分配方式,而是一种指针的初始化,把变量b的首地址给了指针p。在C语言下究竟如何实现动态内存分配的呢?这里提供了几个函数来实现,分别是malloc(),calloc(),realloc(),而释放内存的函数为free(),分别探讨他们的异同。

1.malloc函数
  函数原型为void *malloc(unsigned int size);在内存的动态存储区中分配一块长度为"size" 字节的连续区域。函数的返回值为该区域的首地址。 类型说明符表示把该区域用于何种数据类型。(类型说明符*)表示把返回值强制转换为该类型指针。“size”是一个无符号数。例如: pc=(char *) malloc (100); 表示分配100个字节的内存空间,并强制转换为字符数组类型,函数的返回值为指向该字符数组的指针, 把该指针赋予指针变量pc。若size超出可用空间,则返回空指针值NULL
2.calloc 函数
函数原型为void *calloc(unsigned int num, unsigned int size)
  按所给数据个数和每个数据所占字节数开辟存储空间。其中num为数据个数,size为每个数据所占字节数,故开辟的总字节数为num*size。函数返回该存储区的起始地址。calloc函数与malloc 函数的区别仅在于一次可以分配n块区域。例如: ps=(struct stu*) calloc(2,sizeof (struct stu)); 其中的sizeof(struct stu)是求stu的结构长度。因此该语句的意思是:按stu的长度分配2块连续区域,强制转换为stu类型,并把其首地址赋予指针变量ps
3. realloc函数:
  函数原型为void *realloc(void *ptr, unsigned int size)
重新定义所开辟内存空间的大小。其中ptr所指的内存空间是用前述函数已开辟的,size为新的空间大小,其值可比原来大或小。函数返回新存储区的起始地址(该地址可能与以前的地址不同)。例如p1=(float *)realloc(p1,16);将原先开辟的8个字节调整为16个字节。
**动态申请的内存空间要进行手动用free()函数释放
4. free函数:
  函数原型为void free(void *ptr)
  将以前开辟的某内存空间释放。函数原型为 void free(void *ptr)其中ptr为存放待释放空间起始地址的指针变量,函数无返回值。应注意:ptr所指向的空间必须是前述函数所开辟的。例如free((void *)p1);将上例开辟的16个字节释放。可简写为free(p1);由系统自动进行类型转换。
二、C++语言动态内存分配
2.1 C++中,用newdelete动态创建和释放数组或单个对象。 
动态创建对象时,只需指定其数据类型,而不必为该对象命名,new表达式返回指向该新创建对象的指针,我们可以通过指针来访问此对象。 
int *pi=new int; 
这个new表达式在堆区中分配创建了一个整型对象,并返回此对象的地址,并用该地址初始化指针pi 。 

2.2 动态创建对象的初始化 

动态创建的对象可以用初始化变量的方式初始化。 
int *pi=new int(100); //指针pi所指向的对象初始化为100 
string *ps=new string(10,’9’);//*ps “9999999999” 

如果不提供显示初始化,对于类类型,用该类的默认构造函数初始化;而内置类型的对象则无初始化。 
也可以对动态创建的对象做值初始化: 
int *pi=new int( );//初始化为
int *pi=new int;//pi 指向一个没有初始化的int 
string *ps=new string( );//初始化为空字符串 (对于提供了默认构造函数的类类型,没有必要对其对象进行值初始化) 

2.3 撤销动态创建的对象 

delete表达式释放指针指向的地址空间。 
delete pi ;// 释放单个对象 
delete [ ]pi;//释放数组 
如果指针指向的不是new分配的内存地址,则使用delete是不合法的。 

2.4 delete之后,重设指针的值 

delete p; //执行完该语句后,p变成了不确定的指针,在很多机器上,尽管p值没有明确定义,但仍然存放了它之前所指对象的地址,然后p所指向的内存已经被释放了,所以p不再有效。此时,该指针变成了悬垂指针(悬垂指针指向曾经存放对象的内存,但该对象已经不存在了)。悬垂指针往往导致程序错误,而且很难检测出来。 
一旦删除了指针所指的对象,立即将指针置为0,这样就非常清楚的指明指针不再指向任何对象。(零值指针:int *ip=0;) 

2.5 区分零值指针和NULL指针 

零值指针,是值是0的指针,可以是任何一种指针类型,可以是通用变体类型void*也可以是char*int*等等。 
空指针,其实空指针只是一种编程概念,就如一个容器可能有空和非空两种基本状态,而在非空时可能里面存储了一个数值是0,因此空指针是人为认为的指针不提供任何地址讯息。参考:http://www.cnblogs.com/fly1988happy/archive/2012/04/16/2452021.html 

2.6 new分配失败时,返回什么? 

1993年前,c++一直要求在内存分配失败时operator   new要返回0,现在则是要求operator   new抛出std::bad_alloc异常。很多c++程序是在编译器开始支持新规范前写的。c++标准委员会不想放弃那些已有的遵循返回0规范的代码,所以他们提供了另外形式的operator   new(以及operator   new[])以继续提供返回0功能。这些形式被称为无抛出,因为他们没用过一个throw,而是在使用new的入口点采用了nothrow对象
class   widget   {   ...   }; 

widget   *pw1   =   new   widget;//   分配失败抛出std::bad_alloc   

if   (pw1   ==   0)   ... //   这个检查一定失败 

widget   *pw2   =   new   (nothrow)   widget;   //   若分配失败返回

if   (pw2   ==   0)   ... //   这个检查可能会成功 

3. mallocnew的区别 

3.1 new 返回指定类型的指针,并且可以自动计算所需要大小。 
比如:    
1) int *p;    
p = new int; //返回类型为int* 类型(整数型指针),分配大小为 sizeof(int);    
或:    
int* parr;    
parr = new int [100]; //返回类型为 int* 类型(整数型指针),分配大小为 sizeof(int) * 100;    
2) 而 malloc 则必须要由我们计算字节数,并且在返回后强行转换为实际类型的指针。    
int* p;    
p = (int *) malloc (sizeof(int)*128);//分配128个(可根据实际需要替换该数值)整型存储单元,并将这128个连续的整型存储单元的首地址存储到指针变量p中  
double *pd=(double *) malloc (sizeof(double)*12);//分配12double型存储单元,并将首地址存储到指针变量pd中 

3.2 malloc 只管分配内存,并不能对所得的内存进行初始化,所以得到的一片新内存中,其值将是随机的。 
除了分配及最后释放的方法不一样以外,通过mallocnew得到指针,在其它操作上保持一致。 

4.有了malloc/free为什么还要new/delete? 

1) mallocfreeC++/C语言的标准库函数,new/deleteC++的运算符。它们都可用于申请动态内存和释放内存。 
2) 对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。 
因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。 
我们不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete。由于内部数据类型的对象没有构造与析构的过程,对它们而言malloc/freenew/delete是等价的。 
3) 既然new/delete的功能完全覆盖了malloc/free,为什么C++不把malloc/free淘汰出局呢?这是因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。 
如果用free释放“new创建的动态对象,那么该对象因无法执行析构函数而可能导致程序出错。如果用delete释放“malloc申请的动态内存,结果也会导致程序出错,但是该程序的可读性很差。所以new/delete必须配对使用,malloc/free也一样。
malloc()到底从哪里得到了内存空间? 
答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。 

原创粉丝点击