C/C++面试题

1、static的作用

1)修饰局部变量


概念:当使用static关键字修饰局部变量时,该变量就变成了静态局部变量。这意味着它不再是传统的自动存储期变量,而是具有静态存储期。

作用域:静态局部变量的作用域确实没有变化,它仍然是在其定义的局部范围内,即它所在的代码块(例如函数体)内部。在作用域外,该变量是不可见的。

生存期:静态局部变量的生存期与全局变量类似,都是全局的。这意味着静态局部变量在程序开始执行时就已经存在,并且直到程序结束才会被销毁。这与普通的局部变量不同,普通局部变量在函数被调用时创建,在函数返回时销毁。

特点:静态局部变量的初始化只会在第一次进入包含它的函数时发生。之后,每次函数被调用时,该变量都会保留上一次函数返回时的值,而不是被重新初始化。这是静态局部变量与普通局部变量之间的主要区别。

插曲:

外部链接

  • 外连接允许其他源文件或库访问的函数和变量。如果一个名称(如函数或变量)对编译单元(.cpp文件)来说不是局部的,那么在链接的时候,其他的编译单元可以访问它,也就是说它可以和别的编译单元交互。
  • 当使用extern关键字标记函数或变量时,它们就具有外连接。这意味着这些函数或变量可以在其他源文件中使用。例如,在一个源文件中定义了一个全局变量或函数,并在另一个源文件中使用extern关键字声明它,那么后者就可以访问前者定义的变量或函数。

内部链接

  • 内连接意味着函数和变量只能在定义它们的源文件中使用。如果一个名称对编译单元来说是局部的,那么在链接的时候,其他的编译单元无法链接到它,且不会与其他编译单元中的同名标识符相冲突。
  • 默认情况下,如果没有使用extern标识符,函数和变量将具有内连接。此外,使用static关键字也可以明确指定内连接。这意味着即使在其他源文件中定义了具有相同名称的函数或变量,编译器也不会产生冲突,因为每个源文件都有自己的独立作用域。

2)修饰全局变量


概念
static修饰全局变量时,该全局变量的链接属性从外部链接变为内部链接。这意味着该全局变量仅在其定义的源文件中可见,而在其他源文件中是不可见的。

作用域
全局变量的作用域是整个程序,包括所有的源文件。但是,当全局变量被static修饰后,其作用域并没有改变,仍然是全局的。但是,它的可见性被限制在了定义它的源文件中。

链接属性
通常,全局变量具有外部链接属性,这意味着它们可以在多个源文件之间共享和访问。但是,当全局变量被static修饰后,其链接属性变为内部链接,这意味着该变量只在定义它的源文件中可见,其他源文件即使使用相同的变量名也不会冲突。

因此,static修饰全局变量的主要作用是限制其可见性,确保它在其他源文件中不会被误用或产生命名冲突。这对于创建只在特定源文件中使用的辅助变量或计数器非常有用。

3)修饰函数


概念
静态函数是指使用static关键字修饰的函数。它与普通函数的主要区别在于其链接属性。

作用域
静态函数的作用域与其定义位置有关。如果是在文件作用域(全局作用域)定义的静态函数,则它的作用域是全局的,即在整个程序中可见。但是,由于它是静态的,因此它的链接属性是内部链接,这意味着它只在其定义的源文件中可见,其他源文件无法链接到它。

如果是在局部作用域(如函数内部)定义的静态函数,这是不合法的,因为C++不允许在局部作用域中定义静态函数。

链接属性
通常,非静态函数具有外部链接属性,这意味着它们可以在多个源文件之间共享和访问。但是,当函数被static修饰后,其链接属性变为内部链接。这保证了即使在其他源文件中存在同名的函数,也不会发生链接时的冲突或混淆。

总结
使用static修饰函数的主要目的是限制函数的可见性,确保它只在定义它的源文件中被使用。这对于创建只在特定源文件中使用的辅助函数或隐藏实现细节非常有用。通过这样做,可以减少命名冲突的风险,并提高代码的可维护性和模块化。

需要注意的是,静态函数仍然可以被同一源文件中的其他函数或全局变量调用,但它们对于其他源文件是不可见的。

4) 修饰类的成员函数


您关于static修饰类的成员的描述是准确的。当static关键字用于修饰类的成员时,无论是数据成员还是成员函数,该成员就成为静态成员。以下是关于static修饰类的成员的详细解释:

概念
静态成员是类的所有对象共享的成员。它们不属于类的任何特定实例,而是属于类本身。静态成员可以是数据成员(变量)或成员函数。

数据成员
静态数据成员为类的所有对象共享一个存储空间。无论创建多少个类的对象,都只有一个静态数据成员的副本。静态数据成员可以在类的外部进行初始化,并且可以通过类名和作用域解析运算符(::)来访问,而不需要创建类的对象。

class MyClass {
public:
static int count; // 静态数据成员声明
};
int MyClass::count = 0; // 静态数据成员定义和初始化

在上面的例子中,count是一个静态数据成员,它可以在没有MyClass对象的情况下被访问和修改。

成员函数
静态成员函数只能访问静态成员(包括静态数据成员和其他静态成员函数),而不能直接访问类的非静态成员。这是因为静态成员函数不与类的任何特定对象关联,因此没有this指针。静态成员函数可以通过类名和作用域解析运算符来调用。

class MyClass {
public:
static int count;
static void incrementCount() { // 静态成员函数
count++;
}
};

int MyClass::count = 0;

int main() {
MyClass::incrementCount(); // 调用静态成员函数
std::cout << MyClass::count << std::endl; // 输出静态数据成员的值
return 0;
}

在上面的例子中,incrementCount是一个静态成员函数,它用于增加静态数据成员count的值。由于它是静态的,因此可以通过类名MyClass直接调用,而不需要创建MyClass的对象。

静态成员在类的所有对象之间共享它们的值,这对于统计对象数量、维护类级别的状态或实现与类本身相关而不是与特定对象相关的功能非常有用。它们提供了一种在类的所有实例之间共享信息的方式,而无需在每个实例中复制该信息。

2、C/C++中const的用途?

在C和C++编程语言中,const是一个非常重要的关键字,主要用于定义常量,即不可变的变量。

  1. 定义常量const可以用于定义常量,这些常量的值在初始化后不能被修改。这有助于创建只读的变量,增加代码的可读性和可维护性。

  2. 指针和constconst可以与指针一起使用,以限制指针本身或指针所指向的内容的修改。

    1. 指向常量的指针:指向常量的指针不能用于修改它所指向的值。const int *p;

    2. 常量指针:常量指针的值(即它所指向的地址)在初始化后不能被修改。int *const p;

    3. 指向常量的常量指针:这样的指针既不能修改它所指向的值,也不能修改它自己的值(即它指向的地址)。const int *const p;
  3. 函数参数:将const用于函数参数可以确保参数在函数体内不会被修改。这既可以保护传入的数据,也可以让调用者知道这个函数不会修改其参数。

  4. 类成员const可以用于类的成员变量或成员函数,以限制其修改。

    1. 常量成员变量:常量成员变量只能在类的构造函数初始化列表中初始化,之后不能被修改。
    2. 常量成员函数:常量成员函数不能修改类的任何成员变量(除非它们被声明为mutable
      1. 不能修改成员变量:当一个成员函数被声明为const时,它不能修改类的任何非static且非mutable的成员变量。这是因为const成员函数保证在调用该函数时不会改变对象的任何状态。

      2. 不能调用非const成员函数:如果一个成员函数被声明为const,那么它不能调用类的任何非const成员函数,因为非const成员函数可能会修改成员变量,从而违反const成员函数的承诺。

      3. 只能被const对象调用:一个const对象只能调用其const成员函数。这是因为const对象的内容是不可变的,因此只能调用那些不会修改对象状态的成员函数。

      4. const与staticconststatic关键字确实不能同时用于修饰成员函数。因为static成员函数不依赖于类的任何特定实例,它们属于类本身,因此没有this指针。而const成员函数则需要一个this指针来确保不修改对象的任何成员变量。因此,它们的用途和语义是互斥的。

  5. 提高程序的可读性和可维护性:使用const可以清晰地表明哪些变量或参数是只读的,从而帮助其他程序员更好地理解代码的功能和预期行为。

  6. const 修饰函数返回值:和修饰指针和变量的作用一样。

  7. const修饰类对象:

    1. 对象的任何成员都不能被修改。
    2. 只能调用const成员函数。

3、new和malloc的区别?

相同点:new和malloc都是在动态内存分配时使用的,它们的基本功能相同,都是在程序运行期间从堆中分配一段内存空间。

不同点

  1. 语法:new是C++特有的运算符,而malloc是C语言中的函数。
  2. 类型处理:new在创建并初始化对象时比malloc更便捷。new会自动调用构造函数并返回指向对象的指针,而malloc只是返回分配空间的地址,不会调用构造函数。此外,new运算符在开辟内存时需要指定类型,而malloc所分配的内存大小则是以字节为单位,且malloc的返回值需要强转成指定类型的地址。
  3. 异常处理:new在无法为程序提供所需大小的内存时会抛出bad_alloc异常,而malloc在内存不足的情况下只会返回null指针,不会抛出异常。
  4. 内存分配new不需要显式指定内存大小,在C++中,使用new操作符创建对象时不需要显式指定要分配的内存大小。编译器会根据对象的类型自动计算所需的大小,并调用相应的构造函数进行初始化,会分配一个足以存储int类型数据的内存空间,并返回指向这个空间的指针。。malloc需要显式指定内存大小,C语言中的malloc函数要求程序员显式指定要分配的内存大小(以字节为单位)。需要注意的是,malloc的返回值是void*,因此需要显式转换为所需类型的指针。
  5. 效率:在某些情况下,new的效率可能会稍低于malloc。这是因为new在执行时会先调用malloc分配内存,然后再调用对象的构造函数。而malloc只负责分配内存,不涉及构造函数的调用。
  6. 内存位置区别:malloc是从堆上动态地为对象分配内存,而new是从自由存储区上为对象动态地分配内存。自由存储区是C++基于new操作符的一个抽象概念,通过new操作符进行内存申请的内存称为自由存储区。自由存储区的位置取决于operator new的实现细节,它不仅可以是堆,也可以是静态存储区。

4、new和delete的实现原理,delete是如何实现释放内存的?

new 和 delete 是 C++ 中用于动态内存分配和释放的操作符。它们的实现原理依赖于底层的内存管理机制,通常涉及堆内存的分配和回收。

new的实现原理:

  1. 分配内存new 操作符首先调用底层的内存分配函数(通常是 operator new),在堆上分配足够大小的内存空间。这个大小是根据要创建的对象类型计算得出的。
  2. 调用构造函数:分配内存成功后,new 会调用对象的构造函数来初始化这块内存区域。这确保了对象在第一次使用前处于有效状态。

delete的实现原理:

  1. 调用析构函数delete 操作符首先调用对象的析构函数。析构函数负责执行对象销毁前的清理工作,比如释放对象持有的资源、关闭文件等。
  2. 释放内存:析构函数执行完毕后,delete 调用底层的内存释放函数(通常是 operator delete)来释放之前通过 new 分配的内存空间。这个过程将内存标记为可用,以便后续的内存分配请求可以使用。

注意事项:

  • 使用 new 分配的内存必须使用 delete 来释放,否则会导致内存泄漏。
  • 对于数组,应使用 new[] 和 delete[] 来分配和释放内存,以确保正确的内存管理。
  • 重载 operator new 和 operator delete 可以自定义内存分配和释放的行为,但需要注意正确地管理内存,避免引入新的问题。

new 和 delete 的实现原理依赖于底层的内存管理机制,它们通过调用构造函数和析构函数以及底层的内存分配和释放函数来确保对象的正确创建和销毁。

5、malloc和free的实现原理?

malloc 和 free 是 C 语言中用于动态内存分配和释放的函数。

malloc实现原理

  1. 查找合适的内存块:当调用 malloc 时,它会向操作系统请求分配指定大小的内存。首先,它会在一个称为堆(heap)的内存区域中查找一个足够大的空闲内存块。这个查找过程可能涉及遍历一个数据结构(如链表或树),该数据结构记录了堆中所有已分配和未分配的内存块的信息。
  2. 内存块分割:如果找到一个足够大的空闲内存块,malloc 会将其分割为两部分:一部分用于满足当前的请求(即返回给调用者),另一部分作为新的空闲内存块保留在堆中。这个分割过程可能会涉及更新堆中的数据结构。
  3. 返回内存地址:最后,malloc 返回指向新分配的内存块的指针。这个指针可以被用来在程序中存储数据。

free实现原理

  1. 合并空闲内存块:当调用 free 时,它会接收一个之前通过 malloc 分配的内存块的指针。free 的任务是释放这块内存,使其可以被其他程序或后续的 malloc 调用使用。为了实现这一点,free 会将这块内存标记为未分配状态,并更新堆中的数据结构。此外,如果这块内存与相邻的内存块都是未分配的,free 可能会将它们合并为一个更大的空闲内存块。
  2. 返回内存给操作系统(可选):在某些情况下,如果释放的内存块很大或者堆中的空闲内存过多,free 可能会选择将部分或全部空闲内存返回给操作系统。然而,这并不是必须的,因为操作系统通常有自己的内存管理机制来处理未使用的物理内存。

6、头文件的ifndef/define/endif是干什么用的?与program once的区别?

共同点:防止头文件被重复包含,提高编译效率的。

不同点

  1. #ifndef:这个指令检查某个宏是否已经定义。如果没有定义,那么接下来的代码(直到对应的 #endif 或另一个条件编译指令)会被包含在内。
  2. #define:这个指令用于定义一个宏。它通常用于定义一个唯一的标识符,以确保头文件的内容只被包含一次。
  3. #endif:这个指令标志着 #ifndef 或其他条件编译指令的结束

举例

#ifndef MY_HEADER_FILE_H

#define MY_HEADER_FILE_H

// 头文件的内容 // ...

#endif // MY_HEADER_FILE_H

7、构造函数和析构函数能否抛出异常?

构造函数和析构函数都可以抛出异常。

  1. 构造函数抛出异常

在C++中,如果构造函数在对象创建过程中抛出异常且未被捕获,那么程序将终止,并且任何已经成功构造的对象都会被析构。这意味着,如果构造函数抛出异常,那么它必须确保所有已分配的资源都被适当地清理。这通常是通过在构造函数中使用异常安全的代码和RAII(资源获取即初始化)技术来实现的。

在C#中,构造函数抛出异常通常是可以接受的,但开发者需要确保正确处理这些异常,并考虑它们对程序状态的影响。

  1. 析构函数抛出异常

析构函数的主要职责是清理对象在生命周期中分配的资源。因此,析构函数通常不应该抛出异常。如果析构函数抛出异常且未被捕获,那么程序的行为将是未定义的,并且可能导致资源泄漏或其他严重问题。在C++中,析构函数应设计为不抛出异常,或者至少应确保异常

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/754174.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端开发者如何打造自己的生态以及ip

作为独立开发者&#xff0c;在公司的岗位上面&#xff0c;经常面对的是页面&#xff0c;但我们不能局限页面&#xff0c;页面是切入点。 1在需求页面的过程中&#xff0c;我们会接触ui&#xff0c;原型&#xff0c;软件&#xff0c;需求&#xff0c; 2在接口对接的过程中&#…

Unity UGUI之Toggle基本了解

在Unity中&#xff0c;Toggle一般用于两种状态之间的切换&#xff0c;通常用于开关或复选框等功能。 它的基本属性如图&#xff1a; 其中&#xff0c; Interactable&#xff08;可交互&#xff09;&#xff1a;指示Toggle是否可以与用户交互。设置为false时&#xff0c;禁用To…

在Linux系统中如何查询日志?

在工作中&#xff0c;我们有时候会定位问题&#xff0c;这时候就需要查询日志了&#xff0c;那么查询日志的命令有哪些呢&#xff1f; cat 查看某个日志文件中的所有内容。 使用示例&#xff1a;cat file.txt 显示 file.txt 文件的所有内容。 如果要对查询的结果进行筛选&am…

Java发展简史

20世纪90年代,单片式计算机系统问世,这种系统不仅价格低廉,而且功能强大,大幅提高了消费电子产品的智能化水平。 为抢占市场,1991年Sun公司成立了由詹姆斯高斯林领导的"Green"项目组,旨在开发能在各种消费电子产品上运行的程序架构。最初考虑使用C编程,但由于其过于…

17双体系Java学习之数组的长度

数组的长度 //获取数组长度 arrays.lengthfor (int i 0; i <nums.length; i) {sum sum nums[i];}System.out.println("总和为&#xff1b;"sum);

2k_Day4:OpenFeign、Nacos、JSR303

SpringCloud-Alibaba Nacos 做为项目的注册中心、配置中心 OpenFeign 远程调用 声明式的HTTP访问 1.引入依赖OpenFeign 2.新增coupon项目被调的collection接口RequestMapping("/member/list") 3.新增member项目下feign/CouponFeignService调用的service接口 4.主函数…

免费阅读篇 | 芒果YOLOv8改进110:注意力机制GAM:用于保留信息以增强渠道空间互动

&#x1f4a1;&#x1f680;&#x1f680;&#x1f680;本博客 改进源代码改进 适用于 YOLOv8 按步骤操作运行改进后的代码即可 该专栏完整目录链接&#xff1a; 芒果YOLOv8深度改进教程 该篇博客为免费阅读内容&#xff0c;直接改进即可&#x1f680;&#x1f680;&#x1f…

c++算法学习笔记 (7) BFS

1.走迷宫 #include <iostream> #include <algorithm> #include <queue> #include <cstring> using namespace std; typedef pair<int, int> PII; const int N 105; int n, m; int g[N][N]; // 存图 int d[N][N]; // 每个点到起点的距离 queue&…

【每日一题】134. 加油站

在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发&#xff0c;开始时油箱为空。 给定两个整数数组 gas 和 cost &…

信号处理--基于正则化聚合的共空间模态(CSP)脑电信号分类

目录 理论 工具 方法实现 代码获取 参考文献 理论 传统的通用空间模式 (CSP) 是一种流行的算法,用于对脑电图 (EEG) 信号进行分类。本文主要介绍小样本设置 (SSS) 中 CSP 的正则化和聚合技术。传统的 CSP 基于样本协方差矩阵估计。如果训练样本数量较少,其脑电图分类的…

万字数据仓库面试题及参考答案

数仓架构设计的方法和原则&#xff1a; 数仓架构设计的方法主要包括需求驱动、数据驱动和技术驱动。需求驱动是指根据业务需求进行设计&#xff0c;数据驱动是指基于数据的特点和规律进行设计&#xff0c;技术驱动是指充分利用现有技术和工具进行设计。 数仓架构设计的原则包…

Java八股文(XXL-JOB)

Java八股文のXXL-JOB XXL-JOB XXL-JOB xxl-job 是什么&#xff1f;它的主要作用是什么&#xff1f; xxl-job 是一款分布式任务调度平台&#xff0c;用于解决分布式系统中的定时任务和异步任务调度问题。 它提供了任务的注册、调度、执行和监控等功能&#xff0c;能够帮助开发者…

MindGraph:文字生成知识图

欢迎来到MindGraph&#xff0c;这是一个概念验证、开源的、以API为先的基于图形的项目&#xff0c;旨在通过自然语言的交互&#xff08;输入和输出&#xff09;来构建和定制CRM解决方案。该原型旨在便于集成和扩展。以下是关于X的公告&#xff0c;提供更多背景信息。开始之前&a…

Python错题集-9PermissionError:[Errno 13] (权限错误)

1问题描述 Traceback (most recent call last): File "D:\pycharm\projects\5-《Python数学建模算法与应用》程序和数据\02第2章 Python使用入门\ex2_38_1.py", line 9, in <module> fpd.ExcelWriter(data2_38_3.xlsx) #创建文件对象 File "D:…

[Vue]路由

Vue路由 Vue中的路由&#xff1a;路径和组件的映射关系 路由基本使用 下载 VueRouter 模块到当前工程&#xff0c;版本3.6.5 (vue2) npm i vue-router3.6.5 main.js中引入VueRouter import VueRouter from vue-router 注册插件 App.use(VueRouter) 创建路由对象 const rou…

机器学习----特征缩放

目录 一、什么是特征缩放&#xff1a; 二、为什么要进行特征缩放&#xff1f; 三、如何进行特征缩放&#xff1a; 1、归一化&#xff1a; 2、均值归一化&#xff1a; 3、标准化&#xff08;数据需要符合正态分布&#xff09;&#xff1a; 一、什么是特征缩放&#xff1a; 通…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之二 素描画风格效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之二 素描画风格效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之二 素描画风格效果 一、简单介绍 二、素描画风格效果实现原理 三、案例简单实现步骤 一、简单介绍 Python是一种跨…

react native 实现自定义底部导航与路由文件配置

首先先把需要的一些库引入 yarn install react-navigation/native yarn install react-native-screens react-native-safe-area-context yarn install react-navigation/native-stack yarn add react-navigation/bottom-tabs 创建路由文件及四个底部导航页面 router文件下的bot…

opengl使用着色器的示例程序

使用了glew库和freeglut库 #include <GL/glew.h> #include <GL/freeglut.h> #include <iostream>// 窗口大小 const GLint WIDTH = 800, HEIGHT = 600;

python 深度学习 记录遇到的报错问题12

本篇继python 深度学习 记录遇到的报错问题11_undefined symbol: __nvjitlinkadddata_12_1, version-CSDN博客 目录 一、AttributeError: module ‘tensorflow‘ has no attribute ‘app‘ 二、AttributeError: module tensorflow has no attribute placeholder 三、Attribu…