C++面试题目汇总

C++常见面试题总结 阅读详情

参考链接:https://mp.weixin.qq.com/s/RD2Hm9L22VV6CSWNvCWhdQ

1:变量的声明和定义有什么区别?

定义(Definition):为变量分配存储空间和地址,是创建变量的实际过程。一个变量只能被定义一次。

声明(Declaration):用于告诉编译器该变量已经存在,不会分配存储空间。变量可以多次声明。

关键区别:

类型是否分配内存是否可重复
定义是否
声明否是
extern int a;    // 声明,不分配内存空间
int a;           // 定义,分配内存空间
int a = 10;      // 定义并初始化

2:如何用if语句正确判断bool、int、float和指针变量是否为零值?

bool型数据:  if(flag) { A; } else { B;}
int型数据:   if(0==flag) { A; } else { B; }
指针变量:     if(NULL==flag) { A; } else { B; }
float型数据: #define NORM (0.000001) 
             if((flag>=-NORM) && (flag<=NORM)) { A; } else { B; }

3:sizeof 和 strlen 的主要区别是什么?

  1. sizeof 是一个操作符,而 strlen 是 C 标准库中定义的一个函数。

  2. sizeof 的操作对象既可以是数据类型,也可以是变量;而 strlen 只能接受以 \0 结尾的字符串作为输入参数。

  3. sizeof 在编译阶段就会被计算出结果,而 strlen 必须等到程序运行时才能得出结果。此外,sizeof 计算的是数据类型或变量所占内存的大小,而 strlen 测量的是字符串实际字符的数量(不包括结尾的 \0)。

  4. 当数组作为 sizeof 的参数时,它表示整个数组的大小,不会退化为指针;而当数组传递给 strlen 时,则会退化为指向数组首地址的指针。

注意: 有些操作符(如 sizeof)看起来像函数,而有些函数名又类似操作符,这类名称容易引起混淆,使用时需要特别注意区分。尤其是在处理数组名等特殊类型时,这种差异可能导致意料之外的错误。

4:C 语言中的 static 和 C++ 中的 static 有什么区别?

在 C 语言中,static 主要用于修饰:

  • 局部静态变量:延长局部变量的生命周期,使其在程序运行期间一直存在。

  • 外部静态变量和函数:限制变量或函数的作用域为当前文件,实现封装和信息隐藏。

而在 C++ 中,除了具备 C 语言中所有的功能之外,static 还被扩展用于:

  • 定义类中的静态成员变量和静态成员函数。这些静态成员属于整个类,而不是类的某个对象,可以在多个对象之间共享。

注意: 在编程中,static 所具有的“记忆性”和“全局性”特点,使得不同调用之间可以共享数据、传递信息。在 C++ 中,类的静态成员则能够在不同的对象实例之间进行通信和数据共享。

5:C 中的 malloc 和 C++ 中的 new 有什么区别?

  1. new 和 delete 是 C++ 中的操作符,支持重载,只能在 C++ 程序中使用;而 malloc 和 free 是标准库函数,可以在 C 和 C++ 中通用,并且可以被覆盖(如自定义内存管理)。

  2. new 在分配内存的同时会自动调用对象的构造函数,完成初始化;相应的,delete 在释放内存时会调用对象的析构函数。而 malloc 只负责分配内存空间,free 仅用于释放内存,它们都不会触发构造函数或析构函数的执行。

  3. new 返回的是具体类型的指针,具有类型安全性;而 malloc 返回的是 void* 类型,需要显式地进行类型转换才能使用。

注意: 使用 malloc 分配的内存必须通过 free 来释放,而使用 new 分配的内存则必须使用 delete 来释放,两者不可混用。因为它们底层实现机制不同,混用可能导致未定义行为或内存泄漏。

6:写一个“标准”宏 MIN

#define MIN(a,b) ((a)<=(b)?(a):(b))

注意:在调用时一定要注意这个宏定义的副作用。

7:指针可以被声明为 volatile 吗?

可以,指针可以被声明为 volatile 类型。因为从本质上讲,指针本质上也是一种变量,它保存的是一个内存地址(即整型数值),这一点与普通变量并没有本质区别。

在某些特殊场景下,比如硬件寄存器访问、中断服务程序中共享的数据等,指针的值可能会被程序之外的因素修改,此时就需要使用 volatile 来告诉编译器不要对该指针进行优化,确保每次访问都直接从内存中读取最新值。

例如,在中断服务程序中修改一个指向缓冲区(buffer)的指针时,就必须将该指针声明为 volatile,以防止编译器因优化而忽略其变化。

说明: 虽然指针具有特殊的用途——用于访问内存地址,但从变量访问的角度来看,它和其他变量一样具备可变性,因此也可以像普通变量一样使用 volatile 进行修饰。在 C++ 中,volatile 是一个类型修饰符(type qualifier),用于告诉编译器:该变量的值可能会在程序不知情的情况下被改变。因此,编译器不能对该变量进行某些优化(如缓存、重排等)。

8:a 和 &a 有什么区别?请写出以下 C 程序的运行结果

#include <stdio.h>

int main(void)
{
    int a[5] = {1, 2, 3, 4, 5};
    int *ptr = (int *)(&a + 1);
    printf("%d, %d", *(a + 1), *(ptr - 1));
    
    return 0;
}

数组名a和&a的区别

表达式类型含义
aint*指向数组首元素 a[0] 的指针
&aint (*)[5]指向整个数组 a 的指针

虽然它们的地址值相同,但类型不同,因此在进行指针运算时步长也不同:

  • a + 1 是以 sizeof(int) 为单位移动(即跳过一个 int)。

  • &a + 1 是以 sizeof(int[5]) 为单位移动(即跳过整个数组)。

输出结果:2, 5

9:简述 C/C++ 程序编译时的内存分配情况(重要)

从内存分配机制角度,C/C++ 的内存管理还可以分为以下三种方式:

分配方式特点描述
静态分配在程序编译阶段完成,如全局变量、静态变量。在整个程序运行过程中有效,速度最快,不易出错。
栈上分配函数调用时在栈中为局部变量分配空间,函数返回后自动释放。速度快但容量有限。
堆上分配使用 malloc / new 动态申请内存,程序员负责手动释放。灵活性强但容易出错,如内存泄漏、碎片等问题。

10:简述strcpy*、sprintf 与memcpy的区别(重要)

1、操作对象不同

函数源对象类型目标对象类型说明
strcpy字符串(以 \0 结尾)字符串用于字符串之间的拷贝
sprintf可为任意基本数据类型字符串格式化输出到字符串
memcpy任意可操作的内存地址任意可操作的内存地址用于任意内存块之间的拷贝

2、功能用途不同

  • strcpy 专门用于字符串之间的拷贝,遇到 \0 停止拷贝,因此只适用于以 \0 结尾的字符串。

  • sprintf 将各种类型的数据格式化后写入字符串中,功能强大但主要用于字符串格式化拼接,不是纯粹的拷贝函数。

  • memcpy 用于两个内存块之间的直接拷贝,不依赖 \0,也不关心数据类型,适用于任意类型的数据拷贝。

3、执行效率不同

函数效率评价
memcpy最高。直接进行内存拷贝,没有格式转换或终止判断
strcpy中等。需要逐字节判断是否到达 \0
sprintf最低。涉及格式解析和字符转换,开销较大

4、使用注意事项

  • strcpy 不检查目标缓冲区大小,容易造成缓冲区溢出,建议使用 strncpy。

  • sprintf 同样不检查缓冲区边界,推荐使用更安全的 snprintf。

  • memcpy 虽然高效,但如果源和目标内存区域有重叠,应使用 memmove 替代。

11:如何将地址为0x67a9的整型变量赋值为0xaa66?

volatile int *ptr = (volatile int *)0x67a9;
*ptr = 0xaa66;

12:面向对象编程的三大基本特征是什么?

面向对象编程(OOP)的三大核心特征是:

  • 封装性(Encapsulation)

  • 继承性(Inheritance)

  • 多态性(Polymorphism)

这三大特性是构建面向对象系统的基础,它们共同支持代码的模块化、可重用性和灵活性。

特征含义核心作用
封装隐藏实现细节,提供统一接口提高安全性、简化使用
继承类之间共享属性和方法代码复用、建立类的层级关系
多态父类引用指向子类对象,动态绑定实现灵活调用、提升程序扩展性

13:C++ 的空类默认包含哪些成员函数?(重要)

缺省构造函数:用于创建对象实例时初始化对象。

缺省拷贝构造函数:当对象通过另一个同类对象进行初始化时调用。

缺省析构函数:在对象生命周期结束时自动调用,用于清理资源。

缺省赋值运算符:将一个对象的内容赋值给另一个同类的对象。

缺省取址运算符:返回对象的内存地址。

缺省取址运算符 const:对于常量对象,返回其内存地址。

注意要点:

  • 仅在需要时生成:只有当程序中实际使用了这些函数时,编译器才会为其生成相应的实现。

  • 覆盖默认行为:如果需要自定义上述任何一种行为,可以通过显式定义相应的成员函数来覆盖默认实现。

  • 全面了解默认函数:尽管有些资料可能只提及前四个默认函数,但后两个(取址运算符及其 const 版本)同样是重要的,默认情况下它们也是存在的。

14:请谈谈你对拷贝构造函数和赋值运算符的理解

拷贝构造函数与赋值运算符重载在功能上都用于对象之间的复制操作,但它们在使用场景和实现逻辑上有以下两个主要区别:

(1)拷贝构造函数用于生成一个新的类对象,而赋值运算符则用于已有对象的重新赋值。

(2)由于拷贝构造函数是用于构造新对象的过程,因此在初始化之前无需判断源对象是否与新建对象相同;而赋值运算符必须进行这种判断(即自赋值检查),以避免不必要的错误。此外,在赋值操作中,如果目标对象已经分配了内存资源,则需要先释放原有资源,再进行新的内存分配和数据复制。

注意:当类中包含指针类型的成员变量时,必须显式重写拷贝构造函数和赋值运算符,避免使用编译器默认生成的版本。否则可能会导致浅拷贝问题,引发内存泄漏或重复释放等问题。

15:如何用 C++ 设计一个不能被继承的类?

✅ 方法一:使用 final 关键字(推荐,C++11 及以上)

从 C++11 开始,你可以使用关键字 final 来标记一个类为“最终类”,表示它不能被继承。

class Base final {
public:
    void sayHello() {
        std::cout << "Hello from Base!" << std::endl;
    }
};

// 编译错误!无法继承 final 类
class Derived : public Base { };  // ❌ Error: cannot derive from 'final' class 'Base'

✅ 方法二:私有构造函数 + 静态工厂方法(适用于 C++98/03)

如果你使用的是 C++98 或 C++03,没有 final 关键字,可以通过将基类的构造函数设为私有,并提供静态工厂方法来创建对象,从而阻止继承。

原理:

  • 派生类在构造时必须调用基类的构造函数;
  • 如果基类的构造函数是私有的,派生类就无法访问;
  • 因此无法完成继承。
class SealedClass {
private:
    SealedClass() {}  // 私有构造函数

public:
    static SealedClass createInstance() {
        return SealedClass();
    }

    void doSomething() {
        std::cout << "Doing something..." << std::endl;
    }
};

// 编译错误!无法访问基类的私有构造函数
class Derived : public SealedClass {};  // ❌ Error: cannot access private constructor

✅ 方法三:使用友元和空类(更高级技巧)

还有一种更巧妙的方式是利用模板和友元机制,让只有特定类才能继承自己。这种技术常用于实现“密封类”。

//使用 CRTP 技术
template <typename T>
class MakeSealed {
    friend T;
private:
    MakeSealed() {}
};

class SealedClass : public MakeSealed<SealedClass> {
public:
    void sayHi() {
        std::cout << "Hi!" << std::endl;
    }
};

// 编译错误!无法访问基类的私有构造函数
class Derived : public SealedClass {};  // ❌ Error

//解释:
//MakeSealed<T> 的构造函数是私有的;
//只有 T 是它的友元,所以只有 T 能访问构造函数;
//所以只有 SealedClass 能继承 MakeSealed<SealedClass>;
//其他类(如 Derived)无法访问构造函数,也就无法继承。

✅ 总结对比

方法是否标准支持是否推荐说明
final 关键字✅ C++11+✅ 推荐最简单、最直观
私有构造函数✅ C++98+⚠️ 可选适用于旧版本
模板 + 友元✅ C++98+⚠️ 高级技巧更灵活但复杂

✅ 实际建议

  • 如果你使用的是 C++11 或更新版本,请直接使用 final 关键字;
  • 如果你维护的是 旧项目(C++98/03),可以考虑使用私有构造函数或模板友元方式;
  • 在现代 C++ 中,final 是最清晰、最安全的方式。

16:访问基类的私有虚函数。请写出以下 C++ 程序的输出结果

#include <iostream.h>

class A 
{
public:
    virtual void g() 
    {
        cout << "A::g" << endl;
    }

private:
    virtual void f()
    {
        cout << "A::f" << endl;
    }
};

class B : public A 
{
public:
    void g()
    {
        cout << "B::g" << endl;
    }

    virtual void h()
    {
        cout << "B::h" << endl;
    }
};

typedef void (*Fun)(void);

int main(void)
{
    B b;

    Fun pFun;

    for (int i = 0; i < 3; i++)
    {
        pFun = (Fun)*((int*)*(int*)(&b) + i);
        pFun();
    }

    return 0;
}

程序输出结果:

//程序输出结果:
B::g
A::f
B::h

注意:本题主要考察了面试者对虚函数的理解程度。一个对虚函数不了解的人很难正确的做出本题。 在学习面向对象的多态性时一定要深刻理解虚函数表的工作原理。

17:简述类成员函数的重写、重载和隐藏的区别

1)重写 和 重载 的主要区别如下:

  • 作用范围不同: 重写的函数位于两个不同的类中(基类和派生类),而重载的函数始终在同一个类中。

  • 参数列表不同: 重写函数与被重写函数的参数列表必须完全相同;而重载函数与被重载函数的参数列表必须不同(包括参数个数、类型或顺序)。

  • virtual 关键字要求不同: 基类中的被重写函数必须使用 virtual 关键字进行修饰,才能实现多态;而重载函数无论是否使用 virtual 都不影响其重载特性。

(2)隐藏 与 重写、重载 的区别如下:

  • 作用范围不同: 与重写类似,隐藏也发生在基类与派生类之间,而不是像重载那样在同一类中。

  • 参数列表不同: 隐藏函数与被隐藏函数的参数列表可以相同,也可以不同,但它们的函数名必须相同。当参数列表不同时,不论基类中的函数是否为虚函数,都会导致基类函数被隐藏,而不是被重写。

说明: 虽然重载和重写都是实现多态性的基础,但它们的技术实现方式完全不同,所达成的目的也有本质区别。其中,重写支持的是运行时多态(动态绑定),而重载实现的是编译时多态(静态绑定)。

C/C++笔试面试题目汇总3——各种排序算法 <br /> 原文:blog.chinaunix.net/u/1222/showart_318070.html<br /><br />排序算法是一种基本并且常用的算法。由于实际工作中处理的数量巨大,所以排序算法对算法本身的速度要求很高。而一般我们所谓的算法的性能主要是指算法的复杂度,一般用O方法来表示。在后面我将给出详细的说明。对于排序的算法我想先做一点简单的介绍,也是给这篇文章理一个提纲。<br /><br />我将按照算法的复杂度,从简单到难来分析算法。<br />第一部分是简单排序算法,后面你将看到他 阅读详情

相关推荐

C++经典面试题100例及答案

答:把一些具有共性的对象归类后形成一个集合,也就是所谓的类。答:这样可以提高编译效率,因为分开的话只需要编译一次生成对应的.obj文件后,再次应用该类的地方,这个类就不会被再次编译,从而大大的提高了编译效率。答:这种函数会自动为内联函数,这种函数在函数调用的地方在编译阶段都会进行代码替换。答:常对象是指在任何场合都不能对其成员的值进行修改的对象。答:所谓的回调函数,就是预先在系统的对函数进行注册,让系统知道这个函数的存在,以后,当某个事件发生时,再调用这个函数对事件进行响应。

usstmiracle的博客 3万+

50个C/C++面试题

面试题1:变量的声明和定义有什么区别  为变量分配地址和存储空间的称为定义,不分配地址的称为声明。一个变量可以在多个地方声明,但是只在一个地方定义。加入extern修饰的是变量的声明,说明此变量将在文件以外或在文件后面部分定义。  说明:很多时候一个变量,只是声明不分配内存空间,直到具体使用时才初始化,分配内存空间,如外部变量。  面试题2:写出bool 、int、 float、

沙漠中的一粒沙 1万+

C++面试题集锦(非常详细)

面试题集锦,网上摘抄到一些,自己整理一部分,形成文档。看完面试基本能通过一半。

【附答案】C/C++ 最常见50道面试题

在编程中,变量的声明指的是告知编译器变量的名称和类型,但不分配内存空间。声明可以多次,常见于头文件中,用于模块间的接口声明。使用extern关键字声明的变量,意味着其定义在别处,通常在另一个文件中。相对地,定义则是创建一个具有存储空间的变量实例。定义只能有一次,通常在源文件中,确保为变量分配内存空间。例如,全局变量和局部变量的定义就是分配内存并初始化的过程。

叫好与叫座虽然不是对立面,但想在同一个作品中达到双重效果很难。 1万+

Sony DPT RP1/CP1破解攻略

前言 自己有一台Sony DPT CP1和一台kindle,两个都已经用了很多年。直到最近发现微信读书上经常可以找到一些免费而且不错的书,所以就萌生了在两台机器上使用微信读书的想法。kindle比较容易实现,直接打开内置浏览器,进入微信读书网页版就行了,而Sony的电纸书则只能通过破解+安装微信读书的方式实现。大概弄了两三个小时吧,也遇到了一些问题,所以这里记录一下整个过程,希望能方便后来的使用者。 首先感谢HappyZ, osc_t5nbj8ds。前者是提供公开破解的方法的大神,后者则是解决了我遇到的问题

weixin_43467572的博客 1万+

如何适配自定义激光雷达数据到LIO-SAM:解决ring和time参数缺失问题

本文详细解析了如何将非标准激光雷达(如速腾、Livox)适配到LIO-SAM框架中,重点解决ring和time参数缺失问题。提供了从源码修改到通用适配中间件的多层级解决方案,并包含实机测试与性能调优指南,帮助开发者高效完成雷达数据适配。

weixin_42551227的博客 421

C/C++ 笔试、面试题目大汇总

  C/C++ 笔试、面试题目大汇总           .

weixin_34366546的博客 114

【JavaSE】之流程控制与方法

Java基础之Java流程控制与方法相关知识介绍~

小新要变强的博客 5795

C/C++面试题目汇总

 C/C++面试题目汇总 最近因为找工作,收集了很多C语言方面方面的面试题以及答案。现在新工作搞定了,决定把这些资料发出来,送给有需要的朋友,免得再象我一样到处搜寻,实在辛苦。发布之前先申明两点:    1 所有资料来自网络(主要是优快云),本人只是收集和转发。    2 所有问题解答(尤其是代码)只是参考,不保证正确。先发基本问题,再发编程问题..........想成为

龙思 5283

CH341的I2C流模式(StreamI2C)到底怎么用?从EEPROM读写到自定义设备,一篇讲清参数配置逻辑

本文详细解析了CH341的I2C流模式(StreamI2C)的使用方法,从EEPROM读写到自定义设备的参数配置逻辑。通过深入分析I2C协议基础、StreamI2C参数映射关系及典型设备配置示例,帮助开发者快速掌握StreamI2C的应用技巧,解决实际开发中的常见问题。

weixin_30932215的博客 447

RustFS vs MinIO:深入对比分布式存储的性能、功能与选型指南

RustFS与MinIO是两款热门分布式存储系统,分别针对高性能与通用场景设计。RustFS基于Rust语言,在吞吐量(最高提升46%)、延迟(降低37%)和资源效率(内存占用减少67%)上显著优于MinIO,适合AI训练、金融级应用等高性能需求。MinIO凭借成熟的S3兼容性、云原生集成和企业级功能,更适用于混合云及现有S3生态。许可方面,RustFS采用Apache 2.0,MinIO为AGPLv3。选型建议:优先RustFS应对性能敏感场景,选择MinIO注重生态兼容性,也可考虑混合架构策略。

分布式存储与RustFS的博客 2022

经典C/C++面试题目大汇总:助你轻松应对技术面试

经典C/C++面试题目大汇总:助你轻松应对技术面试 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 在技术面试中,C/C++语言的掌握程度往往是衡量一个开发者技术水平的重要标准。为了帮助广大求职者和开发者更好地准备面试,我们推出了《经典C/C++面试题目大汇总(全附答案)》资源文件。这份文件包含了数百道经典的C/C++面试题目及其详细答案,涵盖了从基础知识到高级概念的各...

gitblog_09721的博客 529

C/C++跳动的爱心(完整代码)

C语言实现跳动的爱心的完整代码。

AIGC 5842

C/C++笔试、面试题目大汇总

C/C++笔试、面试题目大汇总1.求下面函数的返回值(微软)  int func(x)  {  int countx = 0;  while(x)  {  countx ++;  x = x&(x-1);  }  return countx;  }  假定x = 9999。 答案:8  思路:将x转化为2进制,看含有的1的个数。  2. 什么是“引用”?申明和使用“引用”要注意哪些问题?  答

Wave的专栏 1252

VTK GPU 加速渲染技术

/ 创建颜色工具// 创建立方体数据// 创建OpenGL映射器(注意使用vtkOpenGLPolyDataMapper而不是常规的vtkPolyDataMapper)// 启用VBO(顶点缓冲对象)// 声明几何体是静态的以获得最佳性能// 创建actor// 创建渲染器、渲染窗口和交互器renderWindow->SetWindowName("VTK自定义着色器示例");// 添加actor到渲染器。

深之JohnChen的专栏 1240

番外篇 | 复现HIC-YOLOv5,助力小目标物体的检测

在本文中提出了一种改进的YOLOv5算法:HIC-YOLOv5,用于小目标检测,具有更好的性能和较低的计算成本。🌈

小哥谈 1129

C++面试常见题目问与答(汇总一)

[置顶] C++面试常见题目问与答(汇总一) 标签: C++面试笔试 2015-08-22 13:31 6450人阅读 评论(3) 收藏 举报 本文章已收录于: 分类: 面试题(1) 作者同类文章X C++(22) 作者同类文章X 笔试题(2) 作者同类文章X

shikelang_pp的博客 1197

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

C++面试题目汇总 基础知识

C++面试题目汇总 基础知识基本语言说一下static关键字的作用C++和C的区别c++中四种cast转换C/C++ 中指针和引用的区别给定三角形ABC和一点P(x,y,z),判断点P是否在ABC内,给出思路并手写代码c++中的smart pointer四个智能指针: shared_ptr,unique_ptr,weak_ptr,auto_ptr 基本语言 说一下static关键字的作用 全局...

zzxiaozhao的博客 951

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

上一篇: C++ memset函数
下一篇: C++ 重写、重载、隐藏
绕树三匝寻枝依
博客等级 码龄11年 0粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值