前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[C++]C++面试知识总结

[C++]C++面试知识总结

作者头像
昊楠Hacking
发布2018-04-16 10:12:32
1.7K0
发布2018-04-16 10:12:32
举报

1.程序运行知识

1.1 内存布局和分配方式

C程序的内存布局如下:

  • 静态存储区:存储全局变量和static变量,通常在程序编译期间已经分配好了。
    • BSS段:存放未初始化的static变量和全局变量
    • Data段:存放初始化过的static变量和全局变量
    • Text段:存储程序的二进制代码,程序代码区。  
  • 堆:程序运行时通过malloc申请的内存区存放在堆中,需要使用free来释放该内存空间,生存期在malloc和free之间。
  • 栈:执行函数时,函数的局部变量存储在栈中,执行结束后自动释放该内存区域,栈内存分配运算内置与处理器指令集中。

C++程序的内存布局与C程序布局类似,区别是C++不再区分全局变量和静态变量是否已经初始化,全部存储在静态存储区;另外堆中存放new/delete申请释放的资源,而malloc和free申请的资源存放在自由存储区。

1.2 内存溢出原因

  • 栈溢出:越界访问造成,例如局部变量数组越界访问或者函数内局部变量使用过多,超出了操作系统为该进程分配的栈的大小,还有递归函数层次过多超过了栈大小。
  • 堆溢出:程序申请了资源但忘记释放该资源,造成内存泄露,累积泄露内存过多会造成内存溢出。

1.3 内存泄露和检测

  • C++内存泄漏检测内存泄露是指程序中动态分配了内存,但是在程序结束时没有释放这部分内存,从而造成那一部分内存不可用的情况。
  •  动态内存泄露检测:检查new/delete的资源是否正确释放,检查程序运行期间内存是否一直在增长,使用内存检测工具来检测泄露情况。

1.4  程序生成过程

  • 预处理阶段:根据文件中的预处理指令来修改源文件的内容。如#include指令,作用是把头文件的内容添加到.cpp文件中。
  • 编译阶段:将其翻译成等价的中间代码或汇编代码。
  • 汇编阶段:把汇编语言翻译成目标机器指令。
  • 链接阶段:例如,某个源文件中的函数可能引用了另一个源文件中定义的某个函数;在程序中可能调用了某个库文件中的函数。

1.5 预编译

  • 定义:预编译又称为预处理 , 是做些代码文本的替换工作。处理 # 开头的指令 , 比如拷贝 #include 包含的文件代码, #define 宏定义的替换 , 条件编译等。
  • 功能:宏定义,文件包含,条件编译。

1.6 头文件的作用

  • 保存程序的声明。
  • 通过头文件可以来调用库函数。因为有些代码不能向用户公布,只要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库功能,编译器会从库中提取相应的代码。
  • 如果某个接口被实现或被使用时,其方式与头文件中的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改错的负担。

2. 基本数据类型和用法知识

2.1 struct与class的区别

  • 默认情况下,struct的成员变量是public的,而class是private的。
  • struct保证成员按照声明顺序在内存中存储,而class不能保证。
  • 默认情况下,struct是public继承,而class是private继承。

2.2 struct与union的区别

  • struct中各个成员变量是独立的,union中的成员变量共享同一片内存区域,内存区域长度由成员变量中长度最大的一个决定。
  • struct不能保证分配的是连续内存,但union分配的是连续内存。

2.3 const和define的用途以及区别

  • const用途:用来定义常量、修饰函数参数、修饰函数返回值,可以避免被修改,提高程序的健壮性。
  • define用途:是宏定义,在编译的时候会进行替换,这样做的话可以避免没有意义的数字或字符串,便于程序的阅读。
  • 区别:const定义的数据有数据类型,而宏常量没有数据类型。编译器可以对const常量进行类型检查。而对宏定义只进行字符替换,没有类型安全检查,所以字符替换时可能出错。

2.4 枚举和define的区别

  • #define 是在预编译阶段进行简单替换。枚举常量则是在编译的时候确定其值。
  • 一般在编译器里,可以调试枚举常量,但是不能调试宏常量。
  • 枚举可以一次定义大量相关的常量,而#define 宏一次只能定义一个。

2.5 内联函数和宏的区别

  • 内联函数在编译时展开,宏在预编译时展开。
  • 在编译的时候内联函数可以直接被嵌入到目标代码中,而宏只是一个简单的文本替换,内联函数可以完成诸如类型检测、语句是否正确等编译功能,宏就不具备这样的功能。inline函数是函数,宏不是函数。   

2.6 new/delete和malloc/free的区别

  • new/delete用调用构造函数来实例化对象和调用析构函数释放对象申请的资源。
  • malloc/free用来申请内存和释放内存,但是申请和释放的对象只能是内部数据类型。
  • malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。

2.7 delete和delete[]的区别

  • delete只会调用一次析构函数,delete[]会调用每一个成员的析构函数。
  • delete与new配套,delete []与new []配套,用new分配的内存用delete删除用new[]分配的内存用delete[]删除。

2.8 指针和引用的概念和区别

  • 指针指向一块内存,指针保存的是内存的地址;引用是变量的别名,本质是引用该变量的地址。解引用是取指针指向的地址的内容,取地址是获得变量在内存中的地址。
  • 引用在创建的同时必须初始化,保证引用的对象是有效的,所以不存在NULL引用。
  • 指针在定义的时候不必初始化,所以,指针则可以是NULL,可以在定义后面的任何地方重新赋值。
  • 引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用。
  • 指针在任何时候都可以改变为指向另一个对象。
  • 引用的创建和销毁并不会调用类的拷贝构造函数。
  • 因为不存在空引用,并且引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用,所以比指针安全。由于const 指针仍然存在空指针,并且有可能产生野指针,所以还是不安全。
  • 程序会给指针变量分配内存区域,而引用不需要分配内存区域。
  • 返回引用时,在内存中不产生被返回值的副本。

2.9 memset,memcpy和strcpy的区别

  • memset用来对一段内存空间全部设置为某个字符。
  • memcpy是内存拷贝函数,可以拷贝任何数据类型的对象。
  • strcpy只能拷贝字符串,遇到’\0′结束拷贝。

2.10 指针在16位机,32位机,64位机中分别占多大内存

  • 16位机:2字节。
  • 32位机:4字节。
  • 64位机:8字节。

2.11 字符指针,浮点数指针和函数指针哪个占用内存更大

  • 一样大,指针的占用内存大小只和机器相关。

2.12 如何引用一个全局变量

  • 在同一文件中:直接引用。
  • 咋不同文件中:直接引用头文件;使用extern声明变量。

2.13 变量声明和定义的区别

  • 变量声明:告诉编译器有某个类型的变量,但不会为其分配内存。
  • 变量定义:位该类型的变量分配内存。

2.14 野指针,未初始化指针和空指针的区别

  • 野指针:指向一个已删除的对象或无意义地址的指针。
    • 原因:指针变量没有被初始化,或者指针p被free或者delete之后,没有置为NULL。  
  • 空指针:空指针表示“未分配” 或者“尚未指向任何地方” 的指针。
  • 区别:空指针可以确保不指向任何对象或函数; 而未野指针或初始化指针则可能指向任何地方。

2.15 常量指针和指针常量的区别

  • 常量指针:是一个指向常量的指针。可以防止对指针误操作而修改该常量。
  • 指针常量:是一个常量,且是一个指针。指针常量不能修改指针所指向的地址,一旦初始化,地址就固定了,不能对它进行移动操作。但是指针常量的内容是可以改变。

2.16 指针函数和函数指针的区别

  • 指针函数:返回值是指针的函数。
  • 函数指针:一个指向函数的指针。函数名被括号括起来,并且加有指针符号。

2.17 const char*, char const*, char* const的区别

  • char * const cp;//cp是常指针,指向char类型的数据
  • const char * cp;//cp是char类型的指针,指向const char
  • char const * p;//C++里面没有const*的运算符,所以const属于前面的类型。

2.18 static全局变量与普通的全局变量的区别

  • 全局变量在整个工程文件内都有效。
  • 静态全局变量只在定义它的文件内有效。
  • 全局变量和静态变量如果没有手工初始化,则由编译器初始化为0。

2.19 static局部变量和普通局部变量的区别

  • 静态局部变量只在定义它的函数内有效,只是程序仅分配一次内存,函数返回后,该变量不会消失,直到程序运行结束后才释放。
  • 普通局部变量在定义它的函数内有效,这个函数返回会后失效。
  • static局部变量会自动初始化,而局部变量不会。

2.20 sizeof用在不同对象上的区别

  • sizeof是C语言的一种单目操作符,并不是函数。sizeof以字节的形式返回操作数的大小。
  • 若操作数具有类型char、unsigned char或signed char,其结果等于1。
  • 当操作数是指针时,sizeof依赖于系统的位数。
  • 当操作数具有数组类型时,其结果是数组的总字节数。
  • 联合类型操作数的sizeof是其最大字节成员的字节数。
  • 结构类型操作数的sizeof是这种类型对象的总字节数。
  • 如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。

2.21 sizeof与strlen的区别

  • sizeof是运算符,计算数据所占的内存空间;strlen()是一个函数,计算字符数组的字符数。
  • sizeof可以用类型作参数;strlen()只能用char*作参数,必须是以‘/0’结束。
  • 数组做sizeof的参数不退化,传递给strlen就退化为指针了。
  • sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现建立的最大对象的字节大小。

2.22 空指针指向了内存的什么地方

  • 标准并没有对空指针指向内存中的什么地方这一个问题作出规定,一般取决于系统的实现。我们常见的空指针一般指向 0 地址,即空指针的内部用全 0 来表示。空指针的“逻辑地址”一定是0,对于空指针的地址,操作系统是特殊处理的。并非空指针指向一个0地址的物理地址。在实际编程中不需要了解在我们的系统上空指针到底是一个 0指针还是非0地址,我们只需要了解一个指针是否是空指针就可以了——编译器会自动实现其中的转换,为我们屏蔽其中的实现细节。

2.23 有一个char * 型指针刚好指向一些int 型变量, 我想跳过它们。 为什么((int *)p)++; 不行?

  • 类型转换的实质“把这些二进制位看作另一种类型, 并作相应的对待”。
  • ((int *)p)++是一个转换操作符, 根据定义它只能生成一个右值(rvalue)。
  • 而右值既不能赋值, 也不能用++ 自增。
  • 正确的做法:p = (char *)((int *)p + 1);。

3. 面向对象知识

3.1 面向对象三个基本特点

  • 封装:将客观事物抽象成类,每个类对自身的数据和方法。封装可以使得代码模块化,目的是为了代码重用。
  • 继承:子类继承父类的方法和属性,继承可以扩展已存在的代码,目的是为了代码重用。
  • 多态:通过继承同一个基类,产生了相关的不同的派生类,与基类中同名的成员函数在不同的派生类中会有不同的实现,也就是说:一个接口、多种方法。

3.2 多态的作用

  • 可以隐藏实现的细节,使得代码模块化;方便扩展代码;
  • 可以实现接口重用。

3.3 空类默认的成员函数

  • 默认构造函数
  • 析构函数
  • 复制构造函数
  • 赋值运算符

3.4 类的成员函数重载、覆盖和隐藏的概念和区别

  • 重载是指再同一个作用域内,有几个同名的函数,但是参数列表的个数和类型不同。
  • 函数覆盖是指派生类函数覆盖基类函数,函数名、参数类型、返回值类型一模一样。派生类的对象会调用子类中的覆盖版本,覆盖父类中的函数版本。
  • 隐藏”是指派生类的函数屏蔽了与其同名的基类函数。
  • 覆盖和隐藏的区别:
    • 派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏。
    • 派生类的函数与基类的函数同名,参数也相同。基类函数有virtual,是覆盖,没有virtual就是隐藏。

3.5 基类和子类的构造、析构顺序

  • 定义一个对象时先调用基类的构造函数、然后调用派生类的构造函数
  • 先派生类的析构后基类的析构,也就是说在基类的的析构调用的时候,派生类的信息已经全部销毁了

3.6 深拷贝与浅拷贝的区别

  • 深拷贝意味着拷贝了资源和指针
  • 浅拷贝只是拷贝了指针,没有拷贝资源

3.7 构造函数的特点

  • 构造函数只在建立对象的时候自动被调用一次
  • 构造函数必须是公共的,否则无法生成对象
  • 构造函数只负责为自己的类构造对象 

3.8 析构函数的特点

  • 函数名称固定:~类名( )
  • 没有返回类型,没有参数
  • 不可以重载,一般由系统自动的调用

3.8 公有继承、私有继承、受保护的继承

  • 公有继承时,派生类对象可以访问基类中的公有成员,派生类的成员函数可以访问基类中的公有和受保护成员;公有继承时基类受保护的成员,可以通过派生类对象访问但不能修改。
  • 私有继承时,基类的成员只能被直接派生类的成员访问,无法再往下继承。
  • 受保护继承时,基类的成员也只被直接派生类的成员访问,无法再往下继承。

3.9 类成员中只能使用构造函数的初始化列表而不能赋值的有哪些

  • const成员
  • 引用成员

3.10 函数模板与类模板的区别

  • 函数模板是模板的一种,可以生成各种类型的函数实例,函数模板的实例化是由编译程序在处理函数调用时自动完成的
  • 类模板的实例化必须由程序员在程序中显式地指定。

3.11 引用与多态的关系

  • 引用就是对象的别名。
  • 引用主要用作函数的形参。
  • 引用必须用与该引用同类型的对象初始化: 引用是除指针外另一个可以产生多态效果的手段。
  • 一个基类的引用可以指向它的派生类实例。

3.12 static成员变量和static成员函数

  • static数据成员独立于该类的任意对象而存在。
  • tatic数据成员(const static数据成员除外)在类定义体内声明,必须在类外进行初始化。
  • static数据成员定义放在cpp文件中,不能放在初始化列表中。
  • static成员函数在类的外部定义。
  • Static成员函数没有this形参。
  • 可以直接访问所属类的static成员,不能直接使用非static成员。
  • 因为static成员不是任何对象的组成部分,所以static成员函数不能被声明为const。
  • static成员函数也不能被声明为虚函数。

3.13 static总结

  • 函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值。
  • 在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问。
  • 在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内。
  • 在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝。
  • 在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。

3.13 const总结

  • 欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了。
  • 对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const。
  • 在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值。
  • 对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量。
  • 对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。

4. STL标准库

4.1 STL

  • 容器:主要的七种容器 vector,list,deque,map,multimap,set,multiset。
  • 算法
  • 迭代器

参考文献

[1] c++面试知识,知乎。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-04-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.程序运行知识
    • 1.1 内存布局和分配方式
      • 1.2 内存溢出原因
        • 1.3 内存泄露和检测
          • 1.4  程序生成过程
            • 1.5 预编译
              • 1.6 头文件的作用
              • 2. 基本数据类型和用法知识
                • 2.1 struct与class的区别
                  • 2.2 struct与union的区别
                    • 2.3 const和define的用途以及区别
                      • 2.4 枚举和define的区别
                        • 2.5 内联函数和宏的区别
                          • 2.6 new/delete和malloc/free的区别
                            • 2.7 delete和delete[]的区别
                              • 2.8 指针和引用的概念和区别
                                • 2.9 memset,memcpy和strcpy的区别
                                  • 2.10 指针在16位机,32位机,64位机中分别占多大内存
                                    • 2.11 字符指针,浮点数指针和函数指针哪个占用内存更大
                                      • 2.12 如何引用一个全局变量
                                        • 2.13 变量声明和定义的区别
                                          • 2.14 野指针,未初始化指针和空指针的区别
                                            • 2.15 常量指针和指针常量的区别
                                              • 2.16 指针函数和函数指针的区别
                                                • 2.17 const char*, char const*, char* const的区别
                                                  • 2.18 static全局变量与普通的全局变量的区别
                                                    • 2.19 static局部变量和普通局部变量的区别
                                                      • 2.20 sizeof用在不同对象上的区别
                                                        • 2.21 sizeof与strlen的区别
                                                          • 2.22 空指针指向了内存的什么地方
                                                            • 2.23 有一个char * 型指针刚好指向一些int 型变量, 我想跳过它们。 为什么((int *)p)++; 不行?
                                                            • 3. 面向对象知识
                                                              • 3.1 面向对象三个基本特点
                                                                • 3.2 多态的作用
                                                                  • 3.3 空类默认的成员函数
                                                                    • 3.4 类的成员函数重载、覆盖和隐藏的概念和区别
                                                                      • 3.5 基类和子类的构造、析构顺序
                                                                        • 3.6 深拷贝与浅拷贝的区别
                                                                          • 3.7 构造函数的特点
                                                                            • 3.8 析构函数的特点
                                                                              • 3.8 公有继承、私有继承、受保护的继承
                                                                                • 3.9 类成员中只能使用构造函数的初始化列表而不能赋值的有哪些
                                                                                  • 3.10 函数模板与类模板的区别
                                                                                    • 3.11 引用与多态的关系
                                                                                      • 3.12 static成员变量和static成员函数
                                                                                        • 3.13 static总结
                                                                                          • 3.13 const总结
                                                                                            • 4. STL标准库
                                                                                              • 4.1 STL
                                                                                              • 参考文献
                                                                                              相关产品与服务
                                                                                              容器服务
                                                                                              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                                                                                              领券
                                                                                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档