接下来一周会总结一篇,方便后续面试无需重新搜集资料,以下内容来自于牛客网C++面试汇总,也有一些自己平时总结的问题和知识点,希望自己能够坚持下去,加油
【计算机基础与C++】
1.static关键词作用
(1)修饰变量
全局静态变量
存储位置:静态存储区;生命周期:程序整个运行期间一直存在;初始化:未经初始化的静态变量会被自动初始化为0;作用域:声明它的文件外是不可见的
局部静态变量
存储位置:静态存储区;生命周期:程序整个运行期间一直存在;初始化:未经初始化的静态变量会被自动初始化为0;作用域:局部作用域,定义它的函数块或者语句结束的时候,作用域结束;但是离开作用域以后,并没有被销毁,仍然停留在内存中,只是不能再对它进行访问,并且值不变
(2)修饰函数
静态函数
作用域:只在声明它的文件中可见,不能被其他文件所用
(3)修饰类中的成员
静态成员
多个对象之间共享数据,不是某个对象的成员,只存储一个,供所有对象公用
(4)修饰类中的成员函数
静态成员函数
不能引用类中的非静态成员,只能引用类中说明的静态成员
调用方式: <类名>::<静态成员函数名>(参数表)
2.C和C++的区别
设计思想:
C++:面向对象的语言 C:面向过程的语言
语法上:
(1)C++具有封装,继承,多态三种特性
(2)C++增加了许多类型安全的功能,比如强制类型转换
(3)C++支持范式编程,模板类,函数模板
3.C++中指针和引用的区别
(1)指针有自己的空间,引用只是变量的别名
(2)指针可以被初始化为NULL,引用必须被初始化并且是一个已有对象的引用
(3)可以有const指针,但是没有const引用
(4)指针在使用中可以指向其它对象,但是引用只能是一个对象,不能被改变
(5)指针可以有多级指针,但是引用只能是一个
(6)指针和引用++运算符的意义不同,指针++是把指针指向下一个位置,引用++是直接把变量的值加1
(7)返回动态内存分配的对象或者内存,必须使用指针,否则可能会引起内存泄漏
4.指针和数组的区别
(1)指针是保存数据的地址;数组是直接保存数据
(2)指针是间接访问数据,首先获得指针的内容,然后将其作为地址,从该地址中提取数据;数组是直接可以访问数据
(3)指针可以指向不同的数据类型,数组通常用于固定数目且数据类型相同的元素
(4)指针通过malloc分配内存,free释放内存;数组是隐式的分配和删除
5.什么是野指针?
指向一个已删除的对象或者访问受限内存区域的指针
6.为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数?
(1)将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,使用基类指针指向子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏
(2)因为虚函数需要额外的虚函数表和虚表指针,占用额外的内存,只有当需要作为父类的时候,才会把析构函数设置为虚函数
7.什么是函数指针?
(1)定义:指向函数的指针变量
(2)用途:调用函数和做函数的参数,比如回调函数
(3)示例:
char *fun(char *p); // 函数fun
char *(*pf)(char *p); // 指向fun函数的函数指针pf
pf = fun; // 函数指针pf指向fun
pf(p); // 通过pf去调用函数fun
8.C++中析构函数的作用
(1)析构函数是当对象生命周期结束时,自动执行析构函数
(2)析构函数名也应与类名相同,在函数名前面加一个取反符号~
(3)不带任何参数,也没有返回值,只能有一个析构函数,不能重载
(4)类析构的顺序:1)派生类本身的析构函数 2)对象成员析构函数 3)基类的析构函数
9.重载和重写的区别
(1)重载:两个函数名相同,但是参数列表不同,返回值类型没有要求,在同一作用域中
(2)重写:子类继承了父类,父类中的函数是虚函数,在子类中重新定义了这个虚函数,这种情况是重写
10.隐式类型转换
对于内置类型,低精度的变量给高精度的变量赋值会发生隐式类型转换
对于只存在单个参数的构造函数的对象构造来说,函数调用可以直接使用该参数传入,编译器会自动调用其构造函数生成临时对象
11.extern“C”
C++调用C语言的函数需要加 extern“C”
12.C++中的拷贝赋值函数的形参能否进行值传递
不能,调用拷贝构造函数的时候,首先要将实参传递给形参,这个传递的过程中又要调用拷贝构造函数,如此循环,无法完成拷贝,会造成内存溢出
13.C++中类的访问权限
(1)成员访问限定符:public protected private
(2)类的内部都是可以互相访问的,类外部使用对象访问成员,并且只能访问public属性的成员,不能访问private, protected属性的成员
14.C++中struct和class的区别
可以用struct和class定义类,都可以继承
区别:struct的默认继承权限是public; class的默认继承权限和访问权限是private
15.一个C++源文件从文本到可执行文件经历的过程
(1)预处理阶段:对源代码文件中文件包含关系(头文件),预编译语句(宏定义)进行
分析和替换,生成预编译文件
(2)编译阶段:将经过预处理后的预编译文件转换成特定汇编代码,生成汇编文件
(3)汇编阶段:将编译阶段生成的汇编文件转化为机器码,生成可重定位目标文件
(4)链接阶段:将多个目标文件及所需要的库连接成最终的可执行目标文件
16.include头文件的顺序以及双引号“”和尖括号< >的区别
如果在a.h中声明一个b.h中定义的变量,而不引用b.h, 那么要在a.c文件中引用b.h文件,并且要
先引用b.h, 后引用a.h, 否则会报变量类型未声明
双引号与尖括号的区别:
双引号包含的头文件,查找的文件顺序是:
(1)当前头文件目录
(2)编译器设置的头文件路径
(3)系统变量CPLUS_INCLUDE_PATH/C_INCLUDE_PATH指定的头文件路径
尖括号包含的头文件,查找头文件的路径顺序为:
(1)编译器设置的头文件路径
(2)系统变量CPLUS_INCLUDE_PATH/C_INCLUDE_PATH指定的头文件路径
17.C++中的内存管理
在C++中,虚拟内存分为代码段,数据段,BSS段,堆区,文件映射区,栈区
代码段:包括只读存储区和文本区,其中只读存储区存储字符串常量,文本区存储程序的机器代码
数据段:存储程序中已初始化的全局变量和静态变量
bss段:存储未初始化的全局变量和(局部+全局)静态变量,以及所有被初始化为0的全局变量和静态变量
堆区:调用new/malloc函数在堆区动态分配内存,同时需要调用delete/free释放申请的空间
映射区:存储动态链接库以及调用mmap函数进行的文件映射
栈:使用栈空间存储函数的返回地址,参数,局部变量,返回值
18.什么是内存泄漏?如何判断内存泄漏
内存泄漏:由于疏忽或者错误造成程序未能释放不再使用的内存的情况,并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费
内存泄漏的分类:
(1)堆内存泄漏:堆内存指的是程序运行中根据需要分配通过malloc、new等从堆中分配的一块内存,完成后必须通过free或者delete删除,程序的设计过程中导致这部分的内存没有被释放,就会造成内存泄漏
(2)系统资源泄漏:程序使用系统分配的资源,BitMap, handle, socket等没有使用相应函数释放掉,导致系统资源的浪费,严重影响系统效能,系统运行不稳定
(3)没有将基类的析构函数定义为虚函数,当基类指针指向子类对象时,如果基类的析构函数不是虚函数,子类的析构函数将不会被调用,子类的资源没有被释放,造成内存泄漏
一方面可以使用Linux环境下的内存泄漏检查工具 valgrind;另一方面可以在写代码时添加内存申请和释放的统计功能,统计当前申请和释放的内存是否一致,来判断内存是否泄漏
19.什么情况下会发生段错误?
段错误通常发生在访问非法内存地址的时候,具体有以下几种情况:
(1)使用野指针
(2)试图修改字符串常量的内容
20.new和malloc的区别
(1)new 分配内存按照数据类型进行分配,malloc分配内存按照指定的大小分配
(2)new返回的是指定对象的指针,malloc返回的是void* ,malloc的返回值需要进行类型转化
(3)new不仅分配一段内存,而且会调用构造函数,malloc不会;delete除了释放内存之外还会调用对象的析构函数,free不会
(4)new是一个操作符可以重载,malloc是一个库函数
(5)new如果分配失败会抛出bad_malloc异常,而malloc失败了会返回空
(6)申请数组时,new[]一次分配所有内存,多次调用构造函数,搭配使用delete[],delete[]多次调用析构函数,销毁数组中的每个对象,malloc只能使用sizeof(int)*n