linuxC/C++面试问题总结整理

linuxC/C++面试问题总结整理

因为一些原因重新找工作了,面的linux c/c++,这里把面试中经常碰到的问题总结一下。


单元测试

在深信服被问了单元测试,集成测试是什么的问题,一时没想出明确的答案,只给了大概意思 汗-_-||。

Alt text

单元测试:  单元测试是对软件基本组成单元(软件设计的最小单位)进行正确性检验的测试工作,如函数、过程(function,procedure)或一个类的方法(method)。 
集成测试:  集成测试是在单元测试的基础上,将所有模块按照概要设计要求组装成为子系统或系统,验证组装后功能以及模块间接口是否正确的测试工作。集成测试也叫组装测试、联合测试、子系统测试或部件测试。 
系统测试:  系统测试是将经过集成测试的软件,作为计算机系统的一个部分,与系统中其他部分结合起来,在实际运行环境下对计算机系统进行的一系列严格有效地测试,以发现软件潜在的问题,保证系统的正常运行。

关键字const

几乎面C++都会问的问题。

1.const声明的变量只能被读

2.必须初始化

3.常量和指针: 
常量和指针常量:

/**
*int* p = 4; //non-const pointer,non-constdata
*const char* p = &p; //non-constpointer,const data;
*char* const p = &p;//constpointer,non-const data;
*const char* const p = &p; //constpointer,const data;
**/
int j=0;
const int i=0; //i是常量,i的值不会被修改
const int *p1=&i; //指针p1所指内容是常量,可以不初始化
int * const p2=&j //指针p2是常量,所指内容可修改
const int * const p3=&i; //指针p3是常量,所指内容也是常量
p1=j //合法
*p2=100; //合法

4.const与define 
const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。

5.在C++中,还可以修饰函数的定义体,定义类的const成员函数。被const修饰的东西受到强制保护,可以预防意外的变动,提高了程序的健壮性。

一道题 下面的输出是什么:

char str1[]="abc";
char str2[]="abc";
const char str3[] = "abc";
const char str4[] = "abc";
char *p1 = "abc";
char *p2 = "abc";
const char *p3 = "abc";
const char *p4 = "abc";
cout << (str1==str2) << endl;
cout << (str3==str4) << endl;
cout << (p1==p2) << endl;
cout << (p3==p4) << endl;

str1 str2 str3 str4都是字符数组, 只是恰巧存放的内容相同 “abc“ 他们的值 就是第一个元素 str[0] 的地址. 
p1 p2 p3 p4都是指针,指向相同的常量字符串”abc”的地址。 
关于其中const的作用, 是修饰的字符串内容”abc”,是只读的,而不是修饰的变量str,str存放在栈空间。

cout << (str1==str2) << endl;
cout << (str3==str4) << endl;
cout << (p1==p2) << endl;
cout << (p3==p4) << endl;
cout << &str1 << " " << &str2 <<endl;
cout << &str3 << " " << &str4 <<endl;
printf("%d\n","abc");
printf("%d %d\n",&p1[0], &p1[0]);
printf("%d %d\n",&p3[0], &p4[0]);

运行结果:

Alt text

关键字static

预备知识—程序的内存分配 
一个由C/C++编译的程序占用的内存分为以下几个部分

栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 
堆区(heap) — 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。 
全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量、未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 
文字常量区—常量字符串就是放在这里的。程序结束后由系统释放 
程序代码区—存放函数体的二进制代码。

一个正常的程序在内存中通常分为程序段、数据端、堆栈三部分。程序段里放着程序的机器码、只读数据,这个段通常是只读,对它的写操作是非法的。数据段放的是程序中的静态数据。动态数据则通过堆栈来存放。

在内存中,它们的位置如下: 
+——————+ 内存低端 
| 程序段 | 
|——————| 
| 数据段 | 
|——————| 
| 堆栈 | 
+——————+ 内存高端

修饰全局变量

存储方式: 
全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。

全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。

作用范围: 
普通的全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,普通的(也就是非静态)的全局变量在各个源文件中都是有效的。

而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。 

修饰局部变量 
生存周期 —变量从定义到销毁的时间范围 
普通局部变量存储在栈中,数据则随着函数等的作用域结束导致出栈而销毁。 
静态局部变量存放在静态区,所以它的生命周期和全局变量相同是从程序开始到程序结束。

初始化 
静态局部变量只能被初始化一次.

修饰函数 
作用范围: 
static global函数将其作用域限制在本源文件之内,对其它源文件不可见。而global函数具有全局可见性,对其它源文件则可见。

内存: 
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。

此处static的含义和全局变量相同,不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。 
定义静态函数的好处: 静态函数不能被其它文件所用; 其它文件中可以定义相同名字的函数,不会发生冲突;

总结

把局部变量改变为静态变量后,是改变了它的存储方式,即改变了它的生存期。

把全局变量改变为静态变量后,是改变了它的作用域, 限制了它的使用范围。

关键字volatile

举例说明: 
volatile int i=10; 
int j = i; 
… 
int k = i;

volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。

volatile 影响编译器编译的结果,指出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进行编译优化,加volatile关键字的变量有关的运算,将不进行编译优化。)。

其中编译器编译优化是:

由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问,不会出错。

线程间同步的方法

参考这篇文章: 
https://blog.csdn.net/qq_17308321/article/details/79929623

信号量

信号量是用来解决进程间的同步与互斥问题的一种进程间通信机制,包括一个称为信号量的变量和在该信号量下等待资源的进程等待队列,以及对信号量进行的两个原子操作(P/V操作)。其中,信号量对应于某一种资源,取一个非负的整形值。信号量值(常用sem_id表示)指的是当前可用的该资源的数量,若等于0则意味着目前没有可用的资源。

PV原子操作

PV原子操作的具体定义如下:

● P操作:如果有可用的资源(信号量值>0),则此操作所在的进程占用一个资源(此时信号量值减1,进入临界区代码);如果没有可用的资源(信号量值=0),则此操作所在的进程被阻塞直到系统将资源分配给该进程(进入等待队列,一直等到资源轮到该进程)。

● V操作:如果在该信号量的等待队列中有进程在等待资源,则唤醒一个阻塞进程;如果没有进程等待它,则释放一个资源(即信号量值加1)。

先整理这么多了,以后遇到的其他问题会在这补上,或者新写一篇。

posted @ 2018-05-24 01:05  靑い空゛  阅读(749)  评论(1编辑  收藏  举报