[关闭]
@qiezhian 2014-11-15T13:57:59.000000Z 字数 5537 阅读 1594

C/C++笔试知识点2

programming


参考:http://blog.163.com/kan586@126/blog/static/9553245420089118501078/

1.static的作用

  1. static一个主要的作用是“隐藏”,不论是变量或函数,对外模块是不可见的,因此可用于在各模块定义同名函数。
  2. 初始化为0.存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,也就是所谓“本地全局变量”。一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。

2.const

3.多线程

  1. 临界区、互斥量、事件、信号量四种方式
  2. 临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)的区别
  3. 1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。
  4. 2、互斥量:采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享
  5. 3、信号量:它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目
  6. 4、事 件: 通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作

4.什么是“引用”?

申明和使用“引用”要注意哪些问题?

  1. 引用就是某个目标变量的“别名”(alias),对应用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,**因此引用本身不占存储单元**,系统也不给引用分配存储单元。不能建立数组的引用。

将“引用”作为函数参数有哪些特点?

  1. 1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
  2. 2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
  3. 3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。

在什么时候需要使用“常引用?

  1. 如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量
  1. int a ;
  2. const int &ra=a;
  3. ra=1; //错误
  4. a=1; //正确
  1. string foo( );
  2. void bar(string & s);
  3. //那么下面的表达式将是非法的:
  4. bar(foo( ));
  5. bar("hello world");
  6. /*
  7. 原因在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。
  8. 引用型参数应该在能被定义为const的情况下,尽量定义为const 。
  9. */

引用与多态的关系?

  1. //引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例。
  2. Class A;
  3. Class B : Class A{...};
  4. B b; A& ref = b;

什么时候需要“引用”?

  1. 流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其它情况都推荐使用引用。

5. 结构与联合有和区别?

  1. 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。
    1. 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。

6.extern用法?

http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777431.html
extern “C”

  1.   在C++环境下使用C函数的时候,常常会出现编译器无法找到obj模块中的C函数定义,从而导致链接失败的情况,应该如何解决这种情况呢?
  2.   答案与分析:
  3.   extern C的主要作用就是为了能够正确实现C++代码调用其他C语言代码。C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因此会造成链接时找不到对应函数的情况,此时C函数就需要用extern C”进行链接指定,这告诉编译器,请保持我的名称,不要给我生成用于链接的中间函数名。

extern 和 static

  1. (1) extern 表明该变量在别的地方已经定义过了,在这里要使用那个变量.
  2. (2) static 表示静态的变量,分配内存的时候, 存储在静态区,不存储在栈上面.
  3. static 作用范围是内部连接的关系, extern有点相反.它和对象本身是分开存储的,extern也是分开存储的,但是extern可以被其他的对象用extern 引用,而static 不可以,只允许对象本身用它. 具体差别首先,staticextern是一对“水火不容”的家伙,也就是说externstatic不能同时修饰一个变量;其次,static修饰的全局变量声明与定义同时进行,也就是说当你在头文件中使用static声明了全局变量后,它也同时被定义了;最后,static修饰全局变量的作用域只能是本身的编译单元,也就是说它的“全局”只对本编译单元有效,其他编译单元则看不到它.一般定义static全局变量时,都把它放在原文件中而不是头文件,这样就不会给其他模块造成不必要的信息污染,同样记住这个原则吧!

extern 和const

  1. C++中const修饰的全局常量据有跟static相同的特性,即它们只能作用于本编译模块中,但是const可以与extern连用来声明该常量可以作用于其他编译模块中, extern const char g_str[];
  2. 然后在原文件中别忘了定义: const char g_str[] = "123456";
  3. 所以当const单独使用时它就与static相同,而当与extern一起合作的时候,它的特性就跟extern的一样了!所以对const我没有什么可以过多的描述,我只是想提醒你,const char* g_str = "123456" const char g_str[] ="123465"是不同的, 前面那个const 修饰的是char *而不是g_str,它的g_str并不是常量,它被看做是一个定义了的全局变量(可以被其他编译单元使用), 所以如果你像让char*g_str遵守const的全局常量的规则,最好这么定义const char* const g_str="123456".

7.struct内存布局

http://www.cnblogs.com/fly1988happy/archive/2012/04/12/2444408.html

  1. 1.struct的内存大小为每个数据内存的加和,首先按照最大的数据类型进行单个分配,如果前一个数据占用不了所有的内存,而剩下的内存可以放下下一个数据,则第二个数据不另外分配内存(但是地址必须是从这个数据类型大小的整数倍开始,看下面的struct C),否则重新分配一个最大类型的内存。(个人觉得这种方法比较好理解!)
  2. struct A
  3. {
  4. int a;
  5. char b;
  6. double c;
  7. };
  8. struct B
  9. {
  10. int a;
  11. double b;
  12. char c;
  13. };
  14. struct A
  15. {
  16. int a;
  17. char b;
  18. short c;
  19. char d;
  20. };
  21. 对于结构体A:
  22. 因为A中最大的数据类型是double,占8个字节。所以系统先分配8个字节用来放int,结果int只需要4个就够了,然后剩下的4个字节中的1个可以用来放后面的char,碰到double c时,因为此时的3个字节不能存下,所以再分配了一个8个字节来存放double c。因此A占用16个字节。
  23. 对于结构体B
  24. 系统碰到int分给他8个字节存放,碰到double时,剩下的4个字节不足以存放,所以再分配了8个字节,再遇到char时又分配了8个字节,这样B共分配了24个字节。(系统其实是浪费了5个字节的空间)
  25. 比较AB,只有变量定义的顺序不一样,结果占用的内存空间也不一样。所以,结构体里面最好按照类型从小到大的顺序来排列,以免浪费空间。
  26. 对于结构体C
  27. 按照上述方法,最大的数据类型是int,占4个字节,系统先分配4个字节(0~3);再分配4个字节(4~7),存放char bshort c2个字节,但是必须从2的整数倍开始,所以应当分配(6~7),中间空余1个字节;char d1个字节,但是上次分配的4字节用完了,所以需要再分配4个字节存放char dd只占用1个字节,所以剩下3个字节空闲。sizeof(struct C)=12

8.union联合的内存布局

联合表示几个变量共用一个内存位置,在不同的时间保存不同的数据类型和不同长度的变量。在union中,所有的联合成员共用一个空间,并且同一时间只能储存其中一个成员变量的值。
Union的大小为其内部所有变量的最大值,并且按照类型最大值的整数倍进行内存对齐。

  1. union myun
  2. {
  3. struct { int x; int y; int z; }u;
  4. int k;
  5. }a;
  6. int main()
  7. {
  8. a.u.x =4;
  9. a.u.y =5;
  10. a.u.z =6;
  11. a.k = 0;
  12. printf("%d %d %d\n",a.u.x,a.u.y,a.u.z);
  13. return 0;
  14. }

union类型是共享内存的,以size最大的结构作为自己的大小,这样的话,myun这个结构就包含u这个结构体,而大小也等于u这个结构体的大小,在内存中的排列为声明的顺序x,y,z从低到高,然后赋值的时候,在内存中,就是x的位置放置4,y的位置放置5,z的位置放置6,现在对k赋值,对k的赋值因为是union,要共享内存,所以从union的首地址开始放置,首地址开始的位置其实是x的位置,这样原来内存中x的位置就被k所赋的值代替了,就变为0了,这个时候要进行打印,就直接看内存里就行了,x的位置也就是k的位置是0,而y,z的位置的值没有改变,所以应该是0,5,6。

9.new的作用以及构造函数调用顺序

1.new与malloc都是配置内存,但new会引发构造函数的执行。
2.new产生的对象是在堆(heap)内存中产生的,所以直到整个程序结束或者调用delete函数才会释放。而临时对象是在栈(stack)中产生的,当离开作用域时其析构函数就会自动调用,这一点要特别注意。
3.构造函数调用顺序:
  基类->类成员->派生类
 析构函数调用顺序刚好相反
  派生类->类成员->基类
4.四中对象的生命期如下:
(1)全局对象,程序一开始,构造函数执行(比程序进入点更早),程序即将结束时,析构函数执行。
 (2)局部对象,对象诞生则构造函数执行,离开作用域,析构函数执行。
(3)static对象,诞生则构造函数执行,程序即将结束时,析构函数执行,但比全局对象的析构函数早一步执行。
(4)new生成对象,诞生时构造函数执行,delete调用时析构函数执行。
5.四种不同的对象生存方式(stack、heap、global、local static)

10.ifndef / define /endif

防止头文件的重复包含和编译

11.内存泄露检查

http://www.cnblogs.com/taoxu0903/archive/2007/10/27/939261.html

12.复杂指针读法

  1. 右左法则:
  2. 从左向右看, 找到第一个标识符,上例中就是 a
  3. 1.先往右看, 如果是 [..] 那么 读作"a 是一个数组", 接下来的东西,就是数组元素的类型,和大小了,如果是 "(...)" 那么就是一个函数, 剩下的就是描述函数的参数和返回值了。遇到右括号就往左。
  4. .再往左看, 如果前缀是 * 那么读作 "a 是一个指针", 接下来分析指向什么。
  5. 3.读过的就用XX替换掉,并把XX当做标识符,重复上面的步骤,直到确定变量类型。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注