C/C++基础笔试(一)

  面试时总会遇到一些基础题目,其实也是大部分以往见过或者网上可以搜索到的,都是十分基础的问题,这类问题答对了不会给自己加多少分;但如果答错或者答得不完整,自己在面试官眼里就是基础不牢固的印象。所以好记性不如烂笔头,将遇到的部分笔试题,重新整理答案在博客。

题目1: static 作用
答案:
对于C语言来说:
1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
对于C++语言来说:
在类中,static可以用来修饰静态数据成员和静态成员方法
静态数据成员
(1)静态数据成员可以实现多个对象之间的数据共享,它是类的所有对象的共享成员,它在内存中只占一份空间,如果改变它的值,则各对象中这个数据成员的值都被改变。
(2)静态数据成员是在程序开始运行时被分配空间,到程序结束之后才释放,只要类中指定了静态数据成员,即使不定义对象,也会为静态数据成员分配空间。
(3)静态数据成员可以被初始化,但是只能在类体外进行初始化,若为对静态数据成员赋初值,则编译器会自动为其初始化为0 。
(4)静态数据成员既可以通过对象名引用,也可以通过类名引用。
静态成员函数
(1)静态成员函数和静态数据成员一样,他们都属于类的静态成员,而不是对象成员。
(2)非静态成员函数有this指针,而静态成员函数没有this指针。
(3)静态成员函数主要用来方位静态数据成员而不能访问非静态成员。

题目2:volatile关键字的作用,并举例
答案:
作用:防止编译对程序的优化
举例:
  1)中断服务程序中修改的供其它程序检测的变量需要加volatile;
  2)多任务环境下各任务间共享的变量应该加volatile;
  3)存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义。

题目3:const和#define
答案:
1) 编译器处理方式不同
 define宏是在预处理阶段展开。
 const常量是编译运行阶段使用。
2)类型和安全检查不同
 define宏没有类型,不做任何类型检查,仅仅是展开。
 const常量有具体的类型,在编译阶段会执行类型检查。
3) 存储方式不同
 define宏仅仅是展开,给出的是立即数,不分配内存,在内存中会有多个拷贝,消耗内存大。
 const常量在静态存储区中分配空间,在程序运行过程中内存中只有一个拷贝。
4)空间和效率
在编译时, 编译器通常不为const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
宏替换只作替换,不做计算,不做表达式求解。
宏定义的作用范围仅限于当前文件。
默认状态下,const对象只在文件内有效,当多个文件中出现了同名的const变量时,等同于在不同文件中分别定义了独立的变量。 如果想在多个文件之间共享const对象,必须在变量定义之前添加extern关键字(在声明和定义时都要加)。

题目4:重载和覆盖
答案:
重载(overload)
1)函数或者方法有相同的名称,但是参数列表不相同(类型、顺序、数目)的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法
2) 仅是函数的返回值无法重装,重载要求参数列表必须不同。
3) 程序是根据参数列表来确定具体要调用哪个函数的。

覆盖(重写override)
1)覆盖是存在类中,子类重写从基类继承过来的函数。但是函数名、返回值、参数列表都必须和基类相同。
2)当子类的对象调用成员函数的时候,如果成员函数有被覆盖则调用子类中覆盖的版本,否则调用从基类继承过来的函数
3) 如果子类覆盖的是基类的虚函数,利用基类指针指向不同的子类对象,在运行的时候动态的决定要调用哪个子类虚函数,从而实现多态。

两者区别:
1)重载要求函数名相同,但是参数列表必须不同,返回值可以相同也可以不同;
  覆盖要求函数名、参数列表、返回值必须相同。
2)在类中重载是同一个类中不同成员函数之间的关系;
  在类中覆盖则是子类和基类之间不同成员函数之间的关系。
3)重载函数的调用是根据参数列表来决定调用哪一个函数;
  覆盖函数的调用是根据对象类型的不同决定调用哪一个。
4)在类中对成员函数重载是不能够实现多态。

题目5:浮点型、整型、布尔型数、指针与0比较
答案:
float:

float aif(a < 0.000001 && a > -0.000001)

int:

int i;
if(i == 0)
if(i != 0)

bool:

bool b;
if(b)
if(!b)

*p:

int *p;
if(p == NULL)
if(p != NULL)

题目6:进程和线程的区别
答案:
1)进程是cpu资源分配的最小单位,线程是cpu调度的最小单位。
2)进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段;线程共享进程的资源,一个进程至少有一个线程。
3)线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
4)多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了;而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
5)线程中执行时一般都要进行同步和互斥,因为他们共享同一进程的所有资源。
6)线程是轻两级的进程,它的创建和销毁所需要的时间比进程小很多,所有操作系统中的执行功能都是创建线程去完成的。

题目7:指针和引用
答案:
1)都是地址范畴;指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。
2)指针可以是空值,可以在任何时候被初始化;引用不可以为空,当被创建的时候,必须初始化。
3)指针可以用const修饰;引用不可以用const修饰。
4)指针可以有多级;引用只能是一级(int **p;合法 而 int &&a是不合法的)。
5)指针的值在初始化后可以改变,即指向其它的存储单元;引用在进行初始化后就不能再改变。
6)”sizeof指针”得到的是指针本身的大小;”sizeof引用”得到的是所指向的变量(对象)的大小。
7)指针和地址运用自增(++)不同,指针是地址进行自增;引用是值进行自增。
8)如果返回动态内存分配的对象或者内存,必须使用指针,返回引用可能引起内存泄漏。

题目8:判断CPU模式,小端模式返回0,大端模式返回1
答案:
首先知道大、小端模式;
大端模式:数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。网络数据一般为大端模式。
小端模式:数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
代码:用联合体方式判断

int check(void)
{
    union x
    {
        int a;
        char b;
    }c;
    c.a = 1;
    return(c.b != 1);
}

题目9:写一个”标准”宏MIN ,这个宏输入两个参数并返回较小的一个

答案:

#define MIN(A,B) ((A) <= (B) ? (A) : (B)) 

你可能感兴趣的:(C,C++)