2022界C/C++面试总结

本文深入探讨了C++中的指针和引用的区别,包括它们的初始化、使用场景和特性。此外,讨论了内存管理,如new/delete与malloc/free的对比,以及智能指针的作用。文章还涵盖了面向对象的三大特征——封装、继承和多态,详细解释了每种特征的概念和应用场景。同时,提到了C++11的新特性,如auto关键字和智能指针。此外,简要介绍了Linux基础命令、文件系统、排序算法以及操作系统中的进程和线程概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 指针大小:

指针可以在任何时候指向到另一个对象。

引用必须在创建时被初始化。指针可以在任何时间被初始化。

指针就是内存地址,指针变量是用来存放内存地址的变量,在同一CPU构架下,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。

指针描述了数据在内存中的位置,标示了一个占据存储空间的实体,在这一段空间起始位置的相对距离值。在 C/C++语言中,指针一般被认为是指针变量,指针变量的内容存储的是其指向的对象的首地址,指向的对象可以是变量(指针变量也是变量),数组,函数等占据存储空间的实体。

  1. 指针和引用的区别###

指针有自己的一块空间,而引用只是一个别名;

指针可以被初始化为NULL,而引用必须被初始化;

指针在使用中可以指向其它对象,但是引用只能是一个对象的引用,不能被改变;

指针可以有多级指针(**p),而引用只有一级;

  1. auto自定义:
  2. 面向对象三大特征
  3. 封装:

把数据和操作绑定在一起封装成抽象的类,仅向用户暴露接口,而对其隐藏具体实现,以此避免外界干扰和不确定性访问;继承:让某种类型对象获得另一个类型对象的属性和方法,提高了代码的可维护性;多态:让同一事物体现出不同事物的状态,提高了代码的扩展性。

  1. 什么是封装

封装可以隐藏实现细节,使得代码模块化;封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。在面向对象编程上可理解为:把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息藏。                                                                                                                                                               

  1. 什么是继承?

继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。其继承的过程,就是从一般到特殊的过程。

通过继承创建的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。

继承的实现方式?

继承概念的实现方式有三类:实现继承、接口继承和可视继承。

1. 实现继承是指使用基类的属性和方法而无需额外编码的能力;

2. 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;

3. 可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。                                                                                                                                          

  1. 什么是多态?

多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

覆盖,重载。覆盖:是指子类重新定义父类的虚函数的做法。重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

  1. 智能指针:

C++中的四个智能指针: shared_ptr、unique_ptr、weak_ptr、auto_ptr

A:智能指针出现的原因:智能指针的作用就是用来管理一个指针,将普通的指针封装成一个栈对象,当栈对象的生命周期结束之后,会自动调用析构函数释放掉申请的内存空间,从而防止内存泄露。

shared_ptr实现共享式拥有概念。多个智能指针指向相同对象,该对象和其相关资源会在最后一个引用被销毁时被释放。

unique_ptr实现独占式拥有概念,保证同一时间内只有一个智能指针可以指向该对象。

weak_ptr 是一种共享但不拥有对象的智能指针, 它指向一个 shared_ptr 管理的对象。进行该对象的内存管理的是那个强引用的 shared_ptr,weak_ptr只是提供了对管理对象的一个访问手段,它的构造和析构不会引起引用计数的增加或减少。weak_ptr 设计的目的是为协助 shared_ptr工作的用来解决shared_ptr相互引用时的死锁问题。注意的是我们不能通过weak_ptr直接访问对象的方法,可以通过调用lock函数来获得shared_ptr,再通过shared_ptr去调用对象的方法。

auto_ptr采用所有权模式,C++11中已经抛弃

  1. (ubuntu)文件/文件夹的建立
  2. tar:(ubuntu):
  3. new和delete:delete[]什么时候用,是否必须用,什么时候可以不用:有new无delete后果如何,最坏什么情况

new delete和malloc free都是释放申请的堆上的空间,都是成对存在的,否则将会造成内存泄露或二次释放不同的是,new delete是C++中定义的操作符,new除了分配空间外,还会调用类的构造函数来完成初始化工作,delete除了释放空间外还会调用类的析构函数。而malloc和free是C语言中定义的函数。

不需要delete[]的情况:因为int是内置类型,new[]和delete[]在配合int使用时知道int是内置类型,不需要析构函数,

有new无delete后果如何,最坏什么情况

堆内存泄漏(heap leak)。堆内存值得是程序运行过程中根据需要分配通过malloc\realloc\new等从堆中分配的一块内存,再完成之后必须要通过调用对应的free或者delete删除。

如果程序的设计的错误导致这部分内存没有被释放,那么此后这块内存将不会被使用,就会产生Heap Leak。

  1. 析构函数:什么时候使用,什么时候调用:

对象生命周期结束,被销毁时

delete指向对象的指针时,或delete指向对象的基类类型指针,而其基类虚构函数是虚函数时

对象i是对象o的成员,o的析构函数被调用时,对象i的析构函数也被调用

  1. 结构和类的区别:里面分别有什么,什么没有,
  2. 菱形继承###,virual,纯虚函数#####:什么时候使用virtual#:

菱形继承即多个类继承了同一个公共基类,而这些派生类又同时被一个类继承

第一种解决方法,使用域限定我们所需访问的函数

方法二:virtual

  1. 函数,重写函数,重定义:区别

C++ 允许在同一个作用域内声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。不能仅通过返回类型的不同来重载函数。

调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策

重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

重写:是指子类重新定义父类虚函数的方法。

  1. 指针函数 函数指针区别##

指针函数本质上是一个函数,函数的返回值是一个指针;

函数指针本质上是一个指针,C++在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址,有了函数指针后,就可用该指针变量调用函数。

char * fun(char * p)  {…}          //  指针函数fun

char * (*pf)(char * p);             //  函数指针pf

pf = fun;                        // 函数指针pf指向函数fun

pf(p);                        // 通过函数指针pf调用函数fun

  1. 指针常量##:常量指针:

指针常量:顾名思义它就是一个常量,但是是指针修饰的。

因为声明了指针常量,说明指针变量不允许修改。如同次指针指向一个地址该地址不能被修改,但是该地址里的内容可以被修改

  1. linux基本命令####

mkdir 目录

  1. 头文件<>和‘’ ‘’:区别

A:编译器预处理阶段查找头文件的路径不一样:

对于使用双引号包含的头文件,编译器从用户的工作路径开始搜索

对于使用尖括号包含的头文件,编译器从标准库路径开始搜索

  1. 文件读取:

直接读取,以空格换行

数组方法,逐行读取,可读取空格getline

字符串读取,逐行读取,可读取空格

读取至Vector容器中

  1. 代码如何编译:
  2. static具体使用在什么地方:

静态变量在程序执行之前就创建,在程序执行的整个周期都存在。可以归类为如下五种:

  • 局部静态变量:作用域仅在定义它的函数体或语句块内,该变量的内存只被分配一次,因此其值在下次函数被调用时仍维持上次的值;
  • 全局静态变量:作用域仅在定义它的文件内,该变量也被分配在静态存储区内,在整个程序运行期间一直存在;
  • 静态函数:在函数返回类型前加static,函数就定义为静态函数。静态函数只是在声明他的文件当中可见,不能被其他文件所用;
  • 类的静态成员:在类中,静态成员属于整个类所拥有,对类的所有对象只有一份拷贝,因此可以实现多个对象之间的数据共享,并且使用静态数据成员还不会破坏隐藏的原则,即保证了安全性;
  • 类的静态函数:在类中,静态成员函数不接收this指针,因而只能访问类的static成员变量,如果静态成员函数中要引用非静态成员时,可通过对象来引用。(调用静态成员函数使用如下格式:<类名>::<静态成员函数名>(<参数表>);)
  1. C和C++区别##:内容上##,自己感觉:

设计思想上:

C++是面向对象的语言,而C是面向过程的结构化编程语言

语法上:

C++具有封装、继承和多态三种特性

C++相比C,增加多许多类型安全的功能,比如强制类型转换

C++支持范式编程,比如模板类、函数模板等

  1. STL:vector,list:分别机制和区别:什么时间扩容

vector是一种动态数组,在内存中具有连续的存储空间,支持快速随机访问。由于具有连续的存储空间,所以在插入和删除操作方面,效率比较慢。

list是STL实现的双向链表,与vector相比, 它允许快速的插入和删除,但是随机访问却比较慢。

什么时间扩容

新增元素:Vector通过一个连续的数组存放元素,如果集合已满,在新增数据的时候,就要分配一块更大的内存,将原来的数据复制过来,释放之前的内存,在插入新增的元素;

对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了 ;

初始时刻vector的capacity为0,塞入第一个元素后capacity增加为1;

不同的编译器实现的扩容方式不一样,VS2015中以1.5倍扩容,GCC以2倍扩容。

  1. 模板:
  2. sizeof()数组,指针大小:
  • 类的大小为类的非静态成员数据的类型大小之和,也就是说静态成员数据不作考虑。
  • 普通成员函数与sizeof无关。
  • 虚函数由于要维护在虚函数表,所以要占据一个指针大小,也就是4字节。
  • 类的总大小也遵守类似class字节对齐的,调整规则。

字节对齐原则:在系统默认的对齐方式下:每个成员相对于这个结构体变量地址的偏移量正好是该成员类型所占字节的整数倍,且最终占用字节数为成员类型中最大占用字节数的整数倍。

  1. struct和class区别:##

struct 更适合看成是一个数据结构的实现体,class 更适合看成是一个对象的实现体。它们最本质的一个区别就是:struct 访问权限默认是 public 的,class 默认是 private 的。

  1. 左值,右值:

A:左值:能对表达式取地址的具名对象/变量等。一般指表达式结束后依然存在的持久对象。

右值:不能对表达式取地址的字面量、函数返回值、匿名函数或匿名对象。一般指表达式结束就不再存在的临时对象。

右值引用和左值引用的区别在于:

通过&获得左值引用,左值引用只能绑定左值。

通过&&获得右值引用,右值引用只能绑定右值,基于右值引用可以实现移动语义和完美转发,右值引用的好处是减少右值作为参数传递时的复制开销,提高效率。

  1. 堆,栈区别##

申请方式:系统自动分配和管理,程序员手动分配和管理。

效率:由系统分配,计算机底层对栈提供了一系列支持:分配专门的寄存器存储栈的地址,压栈和入栈有专门的指令执行,因此,其速度快不会有内存碎片由程序员分配,堆是由C/C++函数库提供的,机制复杂,需要一些列分配内存、合并内存和释放内存的算法,因此效率较低,可能由于操作不当产生内存碎片。

扩展方向:栈从高地址向低地址进行扩展,堆由低地址向高地址进行扩展。

程序局部变量是使用的栈空间,new/malloc动态申请的内存是堆空间;同时,函数调用时会进行形参和返回值的压栈出栈,也是用的栈空间。

  1. ifdef与#endif的作用及用法

防止双重定义

https://blog.youkuaiyun.com/qq_40584593/article/details/85217303

  1. C++11有哪些新特性
  1. auto关键字:编译器可以根据初始值自动推导出类型,但是不能用于函数传参以及数组类型的推导;
  2. nullptr关键字:nullptr是一种特殊类型的字面值,它可以被转换成任意其它的指针类型;而NULL一般被宏定义为0,在遇到重载时可能会出现问题。
  3. 智能指针:C++11新增了std::shared_ptr、std::weak_ptr等类型的智能指针,用于解决内存管理的问题。
  4. 初始化列表:使用初始化列表来对类进行初始化
  5. 右值引用:基于右值引用可以实现移动语义和完美转发,消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率
  6. atomic原子操作用于多线程资源互斥操作
  7. 新增STL容器array以及tuple
  1. 数据结构
  1. :十种排序算法##
  2. 快速排序###

选出一个key,一般是最左边或是最右边的。

 2、定义一个L和一个R,L从左向右走,R从右向左走。(需要注意的是:若选择最左边的数据作为key,则需要R先走;若选择最右边的数据作为key,则需要L先走)。

 3、在走的过程中,若R遇到小于key的数,则停下,L开始走,直到L遇到一个大于key的数时,将L和R的内容交换,R再次开始走,如此进行下去,直到L和R最终相遇,此时将相遇点的内容与key交换即可。(选取最左边的值作为key)

  1. 冒泡排序:
  2. 时间/空间复杂度:(平均)原理,最好,最差是如何的序列
  3. 原码,补码,反码;
  4. 链表###和堆,数组:
  5. 队列:##

先进先出

在队尾添加元素,在队头删除元素。

入队: 通常命名为push()

出队: 通常命名为pop()

  1. 循环队列:

循环队列入队, 队尾循环后移: SQ->rear =(SQ->rear+1)%Maxsize;

循环队列出队, 队首循环后移: SQ->front =(SQ->front+1)%Maxsize;

队空: SQ.front=SQ.rear; // SQ.rear 和 SQ.front 指向同一个位置

队满: (SQ.rear+1) %Maxsize=SQ.front; // SQ.rear 向后移一位正好是 SQ.front

  1. 指针指向:

操作系统:

  1. 进程,线程:

进程是程序的一次执行,而什么是线程(Thread),线程可以理解为进程中的执行的一段程序片段线程是指进程内的一个执行单元

Linux:

  1. 解压

算法:

  1. git基本命令:
  1. git代码拉取:
  2. git分支合并:

其他

  1. python数据爬取:

PythonpyCharm)

Python在数据分析和交互、探索性计算以及数据可视化等方面都显得比较活跃,这就是Python作为数据分析的原因之一,python拥有numpy、matplotlib、scikit-learn、pandas、ipython等工具在科学计算方面十分有优势,尤其是pandas,在处理中型数据方面可以说有着无与伦比的优势,已经成为数据分析中流砥柱的分析工具。 Python也具有强大的编程能力,这种编程语言不同于R或者matlab,python有些非常强大的数据分析能力,并且还可以利用Python进行爬虫,写游戏,以及自动化运维,在这些领域中有着很广泛的应用,这些优点就使得一种技术去解决所有的业务服务问题,这就充分的体现的Python有利于各个业务之间的融合。

import requests

import pandas as pd

import json

import time

from IPython.display import display, HTML    # 可以输出正确的表格样式

  1. 职业规划:
  2. 为什么选择c++:
  3. C++中的数据库连接:
  4. 一个单向链表,不知道头节点,一个指针指向其中的一个节点,问如何删除这个指针指向的节点?

答:将这个指针指向的next节点值copy到本节点,将next指向next->next,并随后删除原next指向的节点

  1. 排序算法:

1、稳定性

归并排序、冒泡排序、插入排序。基数排序是稳定的

选择排序、快速排序、希尔排序、堆排序是不稳定的

  1. 冒泡排序

是相邻元素之间的比较和交换,两重循环O(n2);所以,如果两个相邻元素相等,是不会交换的。所以它是一种稳定的排序方法

  1. 选择排序

选取最小的元素放在前面,

  1. 希尔排序

队列/2  队列/4

  1. 快速排序

选取第一个为key,左边不懂,右边开始找小于key的,左边找大于key的

  1. 直接插入排序

从第二个开始,和前面的已经排好的序列进行比较

  1. 挖坑排序

选取第一个key,取出,第一个位置为坑位,从右边开始向前,找出比key小的元素,放入坑位,从左边开始遍历找到比key大的元素,放入坑位

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值