做题时对知识点的查漏补缺

1.IP地址分类?(A,B,C,D类)

2.c++异常处理?

try...catch 语句的执行过程是:

  • 执行 try 块中的语句,如果执行的过程中没有异常拋出,那么执行完后就执行最后一个 catch 块后面的语句,所有 catch 块中的语句都不会被执行;
  • 如果 try 块执行的过程中拋出了异常,那么拋出异常后立即跳转到第一个“异常类型”和拋出的异常类型匹配的 catch 块中执行(称作异常被该 catch 块“捕获”),执行完后再跳转到最后一个 catch 块后面继续执行。
  • 如果一个函数在执行过程中拋出的异常在本函数内就被 catch 块捕获并处理,那么该异常就不会拋给这个函数的调用者(也称为“上一层的函数”);如果异常在本函数中没有被处理,则它就会被拋给上一层的函数。
  • 为了增强程序的可读性和可维护性,使程序员在使用一个函数时就能看出这个函数可能会拋出哪些异常,C++ 允许在函数声明和定义时,加上它所能拋出的异常的列表,具体写法如下:

    void func() throw (int, double, A, B, C);

    void func() throw (int, double, A, B, C){...}

    上面的写法表明 func 可能拋出 int 型、double 型以及 A、B、C 三种类型的异常。异常声明列表可以在函数声明时写,也可以在函数定义时写。如果两处都写,则两处应一致。

    如果异常声明列表如下编写:

    void func() throw ();

    则说明 func 函数不会拋出任何异常。
  • 主要的异常/标准异常类?有哪几种:

3.对比路由器,交换机可以提供更大的带宽和数据转发功能

4.类的常成员函数: 函数返回类型    函数名(参数列表):const

5。

register int i = 0;
printf("i = %d, &i = %p\n", i, &i);

“寄存器变量通常储存在计算机内存中。如果幸运的话,寄存器变量储存在 CPU 的寄存器中,或者概括地说,储存在最快的可用内存中。与普通变量相比,访问和处理这些变量的速度更快。由于寄存器变量储存在寄存器而非内存中,所以无法获取寄存器变量的地址。” 这导致上述代码无法运行

6.构造函数,析构函数相关,构造、析构能被继承吗?

构造、析构函数都是不能被继承的。

 逻辑角度讲:子类是没法剥离父类的属性的,例如:小轿车无法剥离汽车的属性,这意味着不能继承?

但是构造函数可以被重载用于初始化,析构函数最多只能被写成虚函数,用于对子类对象的完全析构。

7.内存溢出和内存泄露的区别?

内存溢出:(Out Of Memory---OOM)

 系统已经不能再分配出你所需要的空间,比如你需要100M的空间,系统只剩90M了,这就叫内存溢出

例子:一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出。比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出。说白了就是我承受不了那么多,那我就报错,

原因可能如下:

         (1)内存中加载的数据过于庞大,一次性加载不了这么多,无法分配这种量的内存;

         (2)代码中存在死循环,死循环中一直占用内存而不释放,最终导致溢出;

         (3)递归调用太深,导致堆栈溢出等;

         (4)内存泄漏太多导致没有内存可用那么最终导致内存溢出;

8.缓冲区溢出?日常的哪些操作容易造成缓冲区溢出?

当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。

 危害有以下两点:

       1、程序崩溃,导致拒绝服务

       2、跳转并且执行一段恶意代码

9.如何避免编译器对结构体对齐优化:


struct mystruct11
{                   // 1字节对齐        4字节对齐
    int a;          // 4               4
    char b;         // 1               2(1+1)
    short c;        // 2               2
}__attribute__((packed));

通过在结构体定义的时候在后面添加__attribute__((packed));就可以取消对齐优化了,

:如果用typedef重命名结构体类型,新的名字要放在 “__attribute__((aligned(n)))”的后面,比如

 
  1. typedef struct mystruct111

  2. { // 1字节对齐 4字节对齐 2字节对齐

  3. int a; // 4 4 4

  4. char b; // 1 2(1+1) 2(1+1)

  5. short c; // 2 2 2

  6. short d; // 2 4(2+2) 2

  7. }__attribute__((aligned(2))) My111;

(注意“__attribute__((aligned(n)))”的作用是结构体变量整体n字节对齐,而不是结构体内各元素也要n字节对齐),这句话什么意思呢?简单理解:当32位编译器,默认对齐时4字节对齐,但是你会发现一个奇怪现象,当 “__attribute__((aligned(n)))”中的n=1、2、4时,他的打印结果都是12(这是4字节对齐的结果:12=4+2+2+4),因此可以看出,这里并不是要求结构体内部各元素都要按照n字节对齐,而是要求结构体整体对齐。只有当n的数值大于或等于4时(要求是2的幂次方)才会起作用。

10.内联函数 inline与define(宏定义)的区别

作用:不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处,适用于功能简单,规模较小又使用频繁的函数递归函数无法内联处理,内联函数不能有循环体,if或switch语句,不能进行异常接口声明。

内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。

递归函数不能内联是因为,递归函数无法保证在调用点展开。

内联函数必须在调用前声明,否则编译器不知道是内联函数,在编译时,如果在调用时未出现函数的定义,编译器就无法用内联函数体来替换调用函数的表达式。

比如下面代码片段: 
//函数一开始没有被声明为inline: 
void foo();   //需要一开始就写成inline void foo() ;
//然后就有代码调用它: 
foo(); 
//在调用后才有定义函数为inline: 
inline void foo() 

...... 

代码是的foo()函数最终没有实现inline;

注意事项:

(1) 在一个文件中定义的内联函数不能在另一个文件中使用。它们通常放在头文件中共享。 
(2) 内联函数应该简洁,只有几个语句,如果语句较多,不适合于定义为内联函数。 
(3) 内联函数体中,不能有循环语句、if语句或switch语句,否则,函数定义时即使有inline关键字,编译器也会把该函数作为非内联函数处理。 
(4) 内联函数要在函数被调用之前声明。关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用。

与宏定义的区别

       内联函数和宏的区别在于,宏是由预处理器对宏进行替代,而内联函数是通过编译器控制来实现的。而且内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。你可以象调用函数一样来调用内联函数,而不必担心会产生于处理宏的一些问题。内联函数与带参数的宏定义进行下比较,它们的代码效率是一样,但是内联欢函数要优于宏定义,因为内联函数遵循的类型和作用域规则,它与一般函数更相近,在一些编译器中,一旦关联上内联扩展,将与一般函数一样进行调用,比较方便。 

       另外,宏定义在使用时只是简单的文本替换,并没有做严格的参数检查,也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型,这样,它的使用就存在着一系列的隐患和局限性。即内联函数会更安全。

 

猜你喜欢

转载自blog.csdn.net/weixin_42067304/article/details/108469824