计算机保研/考研面试题——编程语言篇(C和C++)

        笔者在2023年参加了部分985和华五计算机夏令营和预推免面试,下面是笔者对于编程语言(主要是C和C++的基础语法)知识点一些总结,对于保研和考研均适用,对找工作的同学也有一定参考作用,欢迎大家关注点赞、收藏、评论,如需要其他学科的问题请关注我~(部分其他学科的知识点总结已在主页公布)


 相关文章:

计算机保研/考研面试题——数学篇-CSDN博客

计算机保研/考研面试题——数据结构与算法篇-CSDN博客

计算机保研/考研面试题——操作系统篇-CSDN博客

计算机保研/考研面试题——计算机网络篇-CSDN博客

计算机保研/考研面试题——数据库基础篇-CSDN博客

计算机保研/考研面试题——计算机组成原理篇-CSDN博客


1. 指针数组和数组指针的区别?★★

       指针数组:指针数组是指一个数组,其中每个元素都是指针类型。这意味着数组存储的是指针的地址,而指针指向的是其他数据或对象。例如,int *ptrArray[5] 定义了一个包含5个整型指针的数组。

       数组指针:数组指针是指一个指针,它指向一个数组的起始位置。数组指针本身是一个指针变量,存储的是数组的首地址。例如,int (*ptr)[5] 定义了一个指向包含5个整型元素的数组的指针。

2. 结构体和共用体的区别?★★

       结构体中的成员变量分别占用独立的内存空间,并且可以同时存储不同的值。

       共用体中的成员变量共享同一块内存空间,修改其中一个成员变量的值会影响到其他成员变量。

3. 指针在底层是如何实现的?★★

       在底层,指针是通过内存地址来实现的。每个变量在内存中都有一个唯一的地址,指针存储了这个地址,并可以通过该地址找到对应变量的值。

4. 指针和引用的区别是什么?★★★★

       指针和引用都是用于处理变量的间接访问。

       (1)语法

       指针:指针是一个变量,存储了另一个变量的内存地址。使用星号 (*) 来声明指针类型。

       引用:引用是目标变量的别名,它是对目标变量进行直接访问。在C++中,通过使用引用符号(&)来定义引用变量。

       (2)内存管理

       指针:指针可以被重新分配给其他变量,也可以指向空地址(NULL),并且可以通过new和delete操作符来动态地分配和释放内存。

       引用:引用一旦被初始化,就不能再改变它所引用的变量。引用本身并不占用额外的内存,它只是目标变量的别名。

       (3)空值处理

       指针:指针可以存储空地址,表示未指向任何有效的内存位置。

       引用:引用必须在声明时进行初始化,并且不能引用空值(NULL),它必须引用一个有效的对象。

5. C和C++的malloc和new有什么区别?★★★★

       C和C++中的malloc和new都用于动态分配内存,但有一些区别:

       (1)malloc是C库函数,使用时需要包含头文件stdlib.h,而new是C++关键字。

       (2)malloc只负责分配一块指定大小的内存空间,返回一个指向该空间的void*类型指针。new更高级一些,它会在分配内存的同时调用构造函数初始化对象,并返回一个指向该对象的指针。

       (3)malloc返回的是void*指针,需要进行显式的类型转换,并且对于自定义类型的对象,需要手动调用构造函数初始化。而new根据对象类型自动确定所需的内存空间,并执行相应的构造函数初始化操作,无需手动转换类型。

       (4)new在遇到内存分配失败时会抛出std::bad_alloc异常,而malloc则返回NULL指针表示分配失败。

6. 介绍一下C++的模板?并说说模板的好处。★★

       C++模板是一种通用的编程工具,它允许在编写代码时使用参数化类型和参数化函数。

       (1)C++模板分为两种类型:函数模板和类模板。

       ①函数模板: 函数模板是一种定义函数的方式,其中某些类型或值可以作为参数进行通用       化。函数模板的语法如下:

template <typename T>

返回类型 函数名(参数列表)

{

    // 函数体

}

       ②类模板:类模板与函数模板类似,但是用于定义通用的类。类模板的语法如下:

template <typename T>

class 类名

{

    // 类成员和函数定义

};

       (2)模板的好处

       通用代码:模板允许编写通用的代码,可以在不同类型上执行相同的操作。通过将类型参数化,可以实现对各种数据类型的通用处理。

       泛型编程:C++模板支持泛型编程,使得可以编写与特定类型无关的代码。这样可以提高代码的重用性和可扩展性,并减少冗余代码的编写。

       容器类和算法:容器类和算法可以使用模板来实现,在不同类型的数据上进行通用操作。

       函数重载:通过函数模板,可以为不同类型的参数提供相同逻辑的函数实现。这避免了为每个类型编写多个重载函数的重复工作。

7. 介绍vector内部的数据结构是如何实现的。★★

       在C++中,std::vector类是由一个动态分配的连续内存块实现的。它可以根据需要自动调整其大小,并提供了一组方法来方便地操作数据。

       具体实现上,std::vector通常使用一个指针(或称为迭代器)来指向内部的连续内存块。该内存块存储了容器中的元素,并且在内存中是连续分布的,这使得随机访问以及对元素的插入和删除操作变得高效。

       当元素数量超过内部内存块的容量时,std::vector会分配一个更大的内存块,并将原有元素复制到新的内存块中。这样,std::vector能够自动调整其大小,以适应不同容量需求。

8. 深拷贝和浅拷贝的区别是什么?★★★★

       深拷贝和浅拷贝的区别主要在于对于包含指针成员变量的对象:

       浅拷贝仅复制指针的地址,新旧对象之间共享同一块内存。当一个对象释放内存时,会影响到其他拷贝得到的对象,容易导致悬垂指针或内存泄漏。

       深拷贝将指针所指向的内存复制到新对象中。每个对象拥有独立的内存空间,在销毁对象时不会影响其他对象。

9. 如何理解构造函数和析构函数?★★

       构造函数:

       构造函数在创建对象时被调用,用于初始化对象的成员变量和执行其他必要的操作。构造函数具有以下特点:

       (1)与类同名:构造函数的名称与类名相同,没有返回类型(包括void)。

       (2)自动调用:在创建对象时,编译器会自动调用相应的构造函数。

       (3)可以重载:一个类可以有多个构造函数,它们可以以不同的参数列表进行重载,用于满足不同的对象创建需求。

       (4)初始化对象状态:构造函数负责初始化对象的成员变量,确保对象处于有效和一致的状态。

       析构函数:

       析构函数在对象销毁时被调用,用于清理对象分配的资源、执行善后操作。析构函数具有以下特点:

       (1)与类同名,前面加上波浪号(~):析构函数的名称与类名相同,但在前面加上波浪号(~),没有返回类型(包括void)。

       (2)自动调用:在对象销毁时,编译器会自动调用相应的析构函数。

       (3)无参数:析构函数不接受任何参数,因为它只负责当前对象的清理工作。

       (4)不可重载

10. 什么是多态?多态有什么好处?C++有哪些多态?★★★★★

       多态的定义:

       多态指同样的消息被不同类型的对象接收时导致不同的行为。

       多态的好处:

       (1)代码复用

       多态允许将通用的操作和行为定义在父类中,子类可以继承并重写这些方法。这样可以避免重复编写相似的代码,提高代码的复用性和效率。

       (2)可扩展性

       通过添加新的子类来扩展现有代码的功能,而无需修改现有代码。这样可以使代码具有更好的可维护性和可扩展性。

       (3)可读性

       多态能够使代码逻辑更加简洁明了,通过使用统一的接口和抽象的父类,可以减少代码的冗余性,使代码更易于理解和维护。

       (4)灵活性

       多态使得对象能够以多种形态存在和被使用。通过使用基类指针来操作不同的子类对象,可以在运行时动态地选择不同的实现,从而实现代码的灵活性和动态性。

       C++中的多态:

       ①重载多态(函数重载和运算符重载)

       ②强制多态(类型强制转换)

       ③类型参数化多态(函数模板、类模板)

       ④包含多态(继承及虚函数)

11. 什么是虚函数?虚函数有什么好处?★★★★★

       虚函数是在父类中声明的一个函数,通过在函数声明前加上关键字"virtual"来定义。虚函数可以在派生类中被重写,并且通过基类指针或引用调用时,根据指针或引用所指向的对象类型来动态地选择调用哪个函数的实现。

       虚函数的好处:

       (1)实现多态

       通过基类指针或引用调用虚函数时,可以根据指向的具体对象类型来动态地决定调用哪个类的函数实现,实现不同对象的不同行为。

       (2)动态绑定

通过基类指针或引用调用虚函数时,实际调用的函数实现会在运行时决定,而不是在编译时确定。这样可以根据对象的实际类型来动态地决定调用哪个函数实现,提供更大的灵活性和可扩展性。

       (3)可以被覆盖

       在派生类中,可以通过重写(覆盖)基类中的虚函数来改变其原有的行为,不影响其他派生类对象对该函数的调用。

12. 什么是纯虚函数?★★★

       纯虚函数是在父类中声明的一个没有实现的虚函数,通过在函数声明后加上关键字 "= 0" 来定义。纯虚函数本身没有函数体,只用于接口定义和规范派生类的行为。

       纯虚函数的特点如下:

       (1)没有函数体:纯虚函数没有具体的实现代码,只有函数声明。它相当于一个接口,要求派生类必须实现该函数。

       (2)强制派生类实现:这样可以确保派生类都具备该函数的功能,同时也避免了在基类中给出默认实现可能引发的歧义性。

       (3)抽象类:含有纯虚函数的类被称为抽象类。抽象类不能被实例化。

       使用纯虚函数的好处包括:

       (1)接口规范:纯虚函数定义了一个接口,明确了基类和派生类之间的合约关系。通过纯虚函数,可以规范派生类需要实现的功能和行为。

       (2)支持多态:纯虚函数在基类中作为一个可重写(覆盖)的函数存在,可以通过基类指针或引用来调用派生类的具体实现,实现多态性。

13. C/C++函数中如果return想返回多个值,有什么解决方案?★★★

       (1)使用全局变量,从定义变量到程序结束;

       (2)使用数组、结构体或类:

       定义一个结构体或类,将需要返回的多个值封装在结构体或类的成员变量中,然后将该结构体或类作为函数的返回值。这样就可以一次性返回多个值。

       (3)通过引用参数传递:

       定义函数参数为引用类型,函数内部修改参数的值,然后在调用函数时传入外部变量作为引用参数。

       (4)通过指针参数传递:

       使用指针参数传递:类似于引用参数,将函数的参数定义为指向相应类型的指针,并在函数内部修改指针指向的变量的值。通过传递变量的地址作为指针参数,函数可以将多个值返回给调用者。

void myFunction(int* value1, float* value2, char* value3) {

    *value1 = 100;

    *value2 = 3.14f;

    *value3 = 'a';

}

int main() {

    int a;

    float b;

    char c;

    myFunction(&a, &b, &c);//返回后的a,b,c都会改变

    return 0;

}

14. 栈溢出的可能原因?★★★

       (1)局部变量过多或过大:

       当函数中声明的局部变量数量过多、占用内存过大时,会占用大量的栈空间。如果栈空间不足以容纳这些局部变量,就会发生栈溢出。

       (2)动态内存分配错误:

       使用动态内存分配函数(如malloc、new)申请了大量内存但没有正确释放,导致堆积过多的内存,进而影响栈的使用。

       (3)递归调用错误:

       如果在递归函数中没有正确地定义终止条件,递归可能会无限地循环调用自身,导致栈的使用超出限制。每次递归调用都会在栈上创建一个新的函数调用帧,当递归层数过多时,栈空间被耗尽。

       (4)函数调用层级过深:

       在函数内部频繁地调用其他函数,形成很深的调用层级,会占用大量的栈空间。如果递归层级过多或者函数调用层级过深,可能导致栈溢出。

15. 简述C/C++程序编译时的内存分配情况。★★★★★

       (1)栈区(编译器自动分配释放、内存分配连续、存放函数参数和局部变量)

       在函数的执行过程中,每次函数调用时会在栈上创建一个新的帧,用于存储函数的局部变量和返回地址。当函数执行完毕时,这个帧会被销毁。栈的内存分配和释放是自动进行的,由编译器负责管理。

       (2)堆区(程序员分配释放、内存分配不连续、要通过指针链接)

       堆的内存分配和释放需要显式地进行管理。在C中,使用malloc和free函数进行内存的分配和释放;而在C++中,可以使用new和delete运算符进行内存的分配和释放。

       一般由程序员分配释放, 若程序员不释放,程序结束时可能由操作系统回收。类似于链表,在内存中的分布不是连续的,它们是不同区域的内存块通过指针链接起来的。

       (3)静态存储区(全局内存区)

       全局内存区是用于存储全局变量、静态变量和静态常量的一块内存区域。这块内存在程序启动时被分配,并在整个程序的生命周期中一直存在,直到程序结束才被释放。

       (4)常量区

       常量区用于存储常量字符串和其他常量数据。这些数据在程序运行期间是只读的。

       (5)程序代码区

       代码区存储程序的指令,也就是可执行代码(编译后的机器代码)。

16. C和C++的区别是什么?★

       C++是C的超集,也就是说,C++包括了C的所有基础特性,并且还增加了一些新的特性。下面列举一些C和C++之间的主要区别:

       面向对象编程

       C++ 是一种面向对象的编程语言,而 C 是面向过程语言。因此,C++ 支持类、继承、封装、多态等一系列面向对象的概念和特性。

       标准库

       C++ 标准库比 C 标准库更加完善和强大。C++ 标准库包括了很多容器类,如 vector、map、set 等,以及输入输出流、字符串处理等常用功能。这些库函数可以在许多情况下提高开发效率。

       命名空间

       C++ 引入了命名空间的概念,可以避免函数命名相同的冲突。使用命名空间可以将代码按照逻辑分组,并更好地组织代码。

       异常处理

       C++ 支持异常处理机制,这个机制可以增强程序的容错性和可靠性。当程序发生异常时,可以抛出异常并在可控范围内进行处理,避免程序崩溃。而 C 不支持异常处理机制。

       运算符重载

       C++ 允许对运算符进行重载,可以使得运算符在处理特定类型的数据时更具有描述性。而 C 不支持运算符重载。

17. C++和Python在底层上的区别?★★

       (1)编译与解释

       C++是一种编译型语言,源代码通过编译器转换为可执行的机器码才能运行。

       Python是一种解释型语言,代码逐行解释执行,无需编译,相对而言速度较慢。然而,Python具有丰富的库和模块,可以通过集成高性能库(如NumPy和Pandas)来提高执行效率。

       (2)静态类型和动态类型

       C++是一种静态类型语言,变量的类型需要在编译时确定,并且不能随意更改。

       Python是一种动态类型语言,变量的类型在运行时确定,并且可以随意更改。

       (3)内存管理

       C++中开发人员需要手动管理内存,包括分配和释放内存。这可能导致内存泄漏和野指针等问题。

       Python使用垃圾回收机制自动处理内存管理,开发人员无需手动分配和释放内存。

18. C++和Java的区别?★★

       (1)语法风格:C++是一种面向过程和面向对象的语言,语法相对较为灵活,可以直接操作内存和指针。而Java是一种纯面向对象的语言,语法较为严谨,所有的代码都必须定义在类中。

       (2)平台依赖性:C++编译生成的程序可以在不同平台上运行,包括Windows、Linux和macOS等。而Java程序需要在Java虚拟机(JVM)上运行,因此具有更高的平台依赖性。

       (3)内存管理:C++允许手动管理内存,开发人员需要自行分配和释放内存。而Java使用自动内存管理机制(垃圾回收),开发人员无需显式地处理内存分配和释放。

       (4)异常处理:C++使用try-catch语句来捕获和处理异常,开发人员可以自定义异常类型。而Java使用try-catch-finally块来处理异常,并且提供了统一的异常类层次结构。

       (5)执行速度:由于C++更接近底层语言,其执行速度通常比Java更快。而Java通过JVM的即时编译器进行优化,因此在某些情况下可能具有更好的性能。

       (6)应用领域:C++主要用于系统级开发、游戏开发和性能敏感的应用程序。Java主要用于企业级应用程序、移动应用开发和大型跨平台项目。

19. C++和Java的面向对象多态性的区别?★★

       (1)C++中需要使用关键字virtual显式声明虚函数,而Java中所有非静态方法默认都是虚函数,不需特别声明。

       (2)C++中使用指针或引用调用虚函数时,需要通过基类的指针或引用来实现多态性;而Java中任何对象引用都可以实现多态性。

       (3)C++中通过纯虚函数和抽象类来定义接口,派生类必须实现这些纯虚函数;而Java中没有纯虚函数的概念,可以通过接口(interface)来定义规范。接口中的方法必须由实现类提供具体实现。

20. Python和Java的区别?

       (1)语法风格:Python具有简洁、优雅的语法风格,注重可读性,使用缩进来表示代码块。而Java语法较为严谨,使用大括号来表示代码块。

       (2)应用领域:Python适用于广泛的领域,如数据分析、机器学习、科学计算、Web开发等。Java主要用于企业级应用程序开发、Android应用开发和大型系统开发等。

       (3)执行方式:Python是解释型语言,在运行时由解释器逐行解释执行。而Java是编译型语言,源代码首先被编译成字节码,然后在Java虚拟机(JVM)上执行。

       (4)平台依赖性:Python程序可以在多个平台上运行,包括Windows、Linux和macOS等。而Java程序需要依赖JVM来实现跨平台性。

       (5)内存管理:Python使用自动内存管理机制(垃圾回收),开发人员无需手动管理内存。而Java也提供了垃圾回收机制,但开发人员可以通过手动操作对象的引用来进行内存管理。

       (6)编程风格:Python强调代码的简洁和可读性,鼓励使用简单明了的语句和表达式。而Java更注重面向对象的编程范式,需要明确定义类、方法和接口等。

       (7)生态系统:Python拥有强大的第三方库和工具支持,如NumPy、Pandas、Django等,可以快速开发各种应用。Java也有丰富的库和框架,如Spring、Hibernate等,适用于大型企业级项目。

21. 面向对象编程和面向过程编程的区别,面向对象编程的性质是什么?

       区别:

       面向对象编程的特点使得代码更易于理解、扩展和维护,提高了代码的重用性和可靠性。它强调的是将问题中的实体和行为映射到代码中的对象和方法,更贴近实际问题的描述和思考方式。

       而面向过程编程则关注解决问题的步骤和流程,更加直接和线性。

       面向对象编程性质:

       继承性:一个类可以继承另一个已存在的类的属性和方法,减少了代码重复,并支持代码的扩展和修改。

       封装性:将相关的数据和方法封装在对象中,隐藏内部实现细节并提供公共接口。

       多态性:相同的消息可以被不同的对象类型处理,提供了灵活性和可扩展性。

       抽象性:通过接口和抽象类定义通用规范,屏蔽细节,便于代码设计和维护。

  • 23
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值