zoukankan      html  css  js  c++  java
  • c++基础面试笔记

    说说 static关键字的作用

    1. 定义全局静态变量和局部静态变量:在变量前面加上static关键字。初始化的静态变量会在数据段分配内存,未初始化的静态变量会在BSS段分配内存。直到程序结束,静态变量始终会维持前值。只不过全局静态变量和局部静态变量的作用域不一样;

    2. 定义静态函数:在函数返回类型前加上static关键字,函数即被定义为静态函数。静态函数只能在本源文件中使用;

    3. 在变量类型前加上static关键字,变量即被定义为静态变量。静态变量只能在本源文件中使用;

      //示例
      static int a;
      static void func();
    4. 在c++中,static关键字可以用于定义类中的静态成员变量:使用静态数据成员,它既可以被当成全局变量那样去存储,但又被隐藏在类的内部。类中的static静态数据成员拥有一块单独的存储区,而不管创建了多少个该类的对象。所有这些对象的静态数据成员都共享这一块静态存储空间。

    5. 在c++中,static关键字可以用于定义类中的静态成员函数:与静态成员变量类似,类里面同样可以定义静态成员函数。只需要在函数前加上关键字static即可。如静态成员函数也是类的一部分,而不是对象的一部分。所有这些对象的静态数据成员都共享这一块静态存储空间。

    答案解析

    当调用一个对象的非静态成员函数时,系统会把该对象的起始地址赋给成员函数的this指针。而静态成员函数不属于任何一个对象,因此C++规定静态成员函数没有this指针(划重点,面试题常考)。既然它没有指向某一对象,也就无法对一个对象中的非静态成员进行访问。

    宏定义

              使用宏,需要引入头文件:#include <climits>

              定义符号常量表示类型的限制

               #define P1 3.14

              预处理器会将代码中的宏名替换成指定的字符串(const定义的常量生效于编译阶段)

              优点:提高程序的可维护性,一改全改

              define定义的常量,运行时是直接的操作数,并不会存放在内存中。

              #define P1 3.14

              #define M(a,b) a*b

              main函数中输出cout << P1;        3.14

                                        cout <<M(2+3,4+5);           2+3*4+5=19

    指针

       在32位平台下,无论指针的类型是什么,sizeof(指针名)都是4,在64位平台下,无论指针的类型是什么,sizeof(指针名)都是8。

    (1)初始化:

    // 数组
    int a[5] = { 0 };
    char b[] = "Hello";    // 按字符串初始化,大小为6
    char c[] = { 'H','e','l','l','o','' };    // 按字符初始化
    int* arr = new int[10];    // 动态创建一维数组
    
    // 指针
    // 指向对象的指针
    int* p = new int(0);
    delete p;
    // 指向数组的指针
    int* p1 = new int[10];
    delete[] p1;
    // 指向类的指针:
    string* p2 = new string;
    delete p2;
    // 指向指针的指针(二级指针)
    int** pp = &p;
    **pp = 10;
    

    (2)指针操作:

       数组名的指针操作

    int a[3][4];  
    int (*p)[4];  //该语句是定义一个数组指针,指向含4个元素的一维数组
    p = a;        //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
    p++;          //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]
                  //所以数组指针也称指向一维数组的指针,亦称行指针。
    //访问数组中第i行j列的一个元素,有几种操作方式:
    //*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]。其中,优先级:()>[]>*。
    //这几种操作方式都是合法的。

       (3)指针变量的数据操作:

    char *str = "hello,douya!";
    str[2] = 'a';
    *(str+2) = 'b';
    //这两种操作方式都是合法的。

    函数指针的应用场景:回调(callback)。我们调用别人提供的 API函数(Application Programming Interface,应用程序编程接口),称为Call;如果别人的库里面调用我们的函数,就叫Callback。

    说说内联函数和宏函数的区别

    区别:

    1. 宏定义不是函数,但是使用起来像函数。预处理器用复制宏代码的方式代替函数的调用,省去了函数压栈退栈过程,提高了效率;而内联函数本质上是一个函数,内联函数一般用于函数体的代码比较简单的函数,不能包含复杂的控制语句,while、switch,并且内联函数本身不能直接调用自身。
    2. 宏函数是在预编译的时候把所有的宏名用宏体来替换,简单的说就是字符串替换 ;而内联函数则是在编译的时候进行代码插入,编译器会在每处调用内联函数的地方直接把内联函数的内容展开,这样可以省去函数的调用的开销,提高效率
    3. 宏定义是没有类型检查的,无论对还是错都是直接替换;而内联函数在编译的时候会进行类型的检查,内联函数满足函数的性质,比如有返回值、参数列表等
    4. inline函数一般用于比较小的,频繁调用的函数,这样可以减少函数调用带来的开销。只需要在函数返回类型前加上关键字inline,即可将函数指定为inline函数。
    5. 内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率 的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。

                                                                                                                                                                                     i++ 不能作为左值,而++i 可以:

    1
    2
    3
    4
    5
    inti = 0;
    int*p1 = &(++i);//正确
    int*p2 = &(i++);//错误
    ++i = 1//正确
    i++ = 1//错误

     说说new和malloc的区别,各自底层实现原理。

    1. new是操作符,而malloc是函数。
    2. new在调用的时候先分配内存,在调用构造函数,释放的时候调用析构函数;而malloc没有构造函数和析构函数。
    3. malloc需要给定申请内存的大小,返回的指针需要强转;new会调用构造函数,不用指定内存的大小,返回指针不用强转。
    4. new可以被重载;malloc不行
    5. new分配内存更直接和安全。
    6. new发生错误抛出异常,malloc返回null

    答案解析

    malloc底层实现:当开辟的空间小于 128K 时,调用 brk()函数;当开辟的空间大于 128K 时,调用mmap()。malloc采用的是内存池的管理方式,以减少内存碎片。先申请大块内存作为堆区,然后将堆区分为多个内存块。当用户申请内存时,直接从堆区分配一块合适的空闲快。采用隐式链表将所有空闲块,每一个空闲块记录了一个未分配的、连续的内存地址。

    new底层实现:关键字new在调用构造函数的时候实际上进行了如下的几个步骤:

    1. 创建一个新的对象
    2. 将构造函数的作用域赋值给这个新的对象(因此this指向了这个新的对象)
    3. 执行构造函数中的代码(为这个新对象添加属性)
    4. 返回新对象

     说说使用指针需要注意什么

      1. 定义指针时,先初始化为NULL。
      2. 用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。
      3. 不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
      4. 避免数字或指针的下标越界,特别要当心发生“多1”或者“少1”操作
      5. 动态内存的申请与释放必须配对,防止内存泄漏
      6. 用free或delete释放了内存之后,立即将指针设置为NULL,防止“野指针”
  • 相关阅读:
    爬取校园新闻首页的新闻
    网络爬虫基础练习
    综合练习:词频统计
    免费的论文查重网站
    Hadoop综合大作业
    理解MapReduce
    熟悉常用的HBase操作
    熟悉常用的HDFS操作
    爬虫大作业
    数据结构化与保存
  • 原文地址:https://www.cnblogs.com/0901-hcx/p/15269039.html
Copyright © 2011-2022 走看看