C/C++基本语言相关面试题

  • [1. malloc、free和new、delete的区别](#1. malloc、free和new、delete的区别)
  • [2. 引用与指针作用以及区别](#2. 引用与指针作用以及区别)
  • [3. const 关键字的作用](#3. const 关键字的作用)
  • [4. c++什么时候生成构造函数?](#4. c++什么时候生成构造函数?)
  • [5. extern 关键字作用](#5. extern 关键字作用)
  • [6. c_c++中强制类型转换使用场景](#6. c_c++中强制类型转换使用场景)
  • [7. 如何避免野指针?](#7. 如何避免野指针?)
  • [8. static关键字的作用](#8. static关键字的作用)
  • [9. c++ 什么是深拷贝?什么是浅拷贝?](#9. c++ 什么是深拷贝?什么是浅拷贝?)
  • [10. 简述strcpy、sprintf与memcpy的区别?](#10. 简述strcpy、sprintf与memcpy的区别?)

1. malloc、free和new、delete的区别

c++ 复制代码
语言关联:

malloc 和 free 是C语言中的标准库函数。
new 和 delete 是C++中的操作符。

类型安全:

malloc 返回的是 void* 类型,需要显式类型转换。
new 返回的是确切类型的指针,不需要类型转换,因此更类型安全。

构造和析构:

malloc 只分配内存,不调用构造函数。
new 不仅分配内存,还会调用对象的构造函数。
free 只释放内存,不调用析构函数。
delete 不仅释放内存,还会调用对象的析构函数。

错误处理:

malloc 在内存分配失败时返回 
#include <boost/beast/http.hpp>
#include <boost/beast.hpp>
#include <boost/asio.hpp>
#include <memory>
#include <shared_mutex>
#include <iostream>
// 简化作用域声明
namespace beast = boost::beast;         // from <boost/beast.hpp>
namespace http = beast::http;           // from <boost/beast/http.hpp>
namespace net = boost::asio;            // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>NULL。
new 在内存分配失败时抛出 std::bad_alloc 异常。

2. 引用与指针作用以及区别

c++ 复制代码
指针更灵活,可以指向nullptr,可以修改指向,
指针通过某个指针变量指向一个变量,对它所指的变量进行简介的操作
指针是对象,指针有地址,可以定义指针的指针(二级指针)


引用更安全,必须在定义时初始化,且与原类型保持一致,且不分配内存。声明关系,一经声明,不可变更。
可对引用,再次引用。多次引用的结果,是某一变量具有多个别名,多个别名间是平行关系。
对引用操作就是直接对目标对象的操作
引用不是对象,没有实际的地址,不能定义引用指针,也不能定义引用的引用(二级引用:没有这种说法)

作用:
引用 : 用在传参时候,避免内存分配,以及对象数据的复制  ;  用在函数返回值,避免对象数据的复制,提高效率
指针 : 用在传参时候,避免对象数据的复制 
        基类指针可以指向基类对象,也可以指向派生类对象。这种灵活性使得可以通过同一个接口操作不同类型的对象。
        通过基类指针调用虚函数时,实际调用的函数是在运行时根据指针所指向的对象类型决定的,这就是动态绑定(dynamic binding)。通过指针调用虚函数比直接调用函数稍微慢一些
        代码复用

3. const 关键字的作用

c++ 复制代码
一. 定义变量 : 
    1.c语言里 : 局部的const (分配到了栈去) 可以使用指针修改 全局的const (分配到了全局区去) 不能修改 (段错误)
    2.c++里 : 都不能修改,和符号表有关 (局部const变量在符号表中通常不会占用实际的内存地址,编译器会尽可能将其优化为立即数。全局const变量在符号表中会有一个固定的内存地址,但这个地址指向的是只读数据段。)
    作用:1. 避免修改 2. 避免次的内存分配 3. 类型检查 ,作用域检查
    
二. 修饰指针 : (前定值,后定向)  const在*前定值 在*后定向  
    1. char * const p; 
        const修饰指针p,表示指针p本身是常量,不能修改指针的指向。
        这意味着一旦p被初始化指向某个地址,就不能再指向其他地址。
        但是,指针p指向的地址的内容是可以修改的。
    2. const char * p; 
        const修饰char,表示指针p指向的地址的内容是常量,不能修改。
        这意味着不能通过指针p修改它所指向的地址的内容。
        但是,指针p本身是可以修改的,可以指向其他地址。
    3. char const * p; 
        这种写法与const char * p;是等价的,const修饰char,表示指针p指向的地址的内容是常量,不能修改。
        这意味着不能通过指针p修改它所指向的地址的内容。
        但是,指针p本身是可以修改的,可以指向其他地址。
    4. const char * const p;
        const修饰指针p和char,表示指针p本身和指针p指向的地址的内容都是常量,不能修改。
        这意味着指针p不能修改指向,也不能通过指针p修改它所指向的地址的内容。
        
三. 修饰函数参数
    可以防止函数内部修改传入的参数。
四. 修饰函数返回值
    1. 当函数返回值为基本数据类型(如int、char等)时,使用const修饰返回值通常没有实际意义,
    因为基本数据类型的返回值是按值传递的,函数返回后,返回值的副本可以被随意修改。
    2. 当函数返回值为指针或引用时,使用const修饰返回值可以防止返回值被修改。
    (c++运算符+重载时,const修饰返回值可以防止返回值被修改,避免返回的值是左值,禁止  const a + b = c 这种操作)
    
四. 修饰类成员函数
    1. 常量对象只能调用其const常成员函数。 普通对象可以调用所有成员函数。
    2. const修饰类成员函数,表示该成员函数不能修改类成员变量的值。
    3. const常成员函数只能调用const常成员函数,不能调用普通成员函数。
    (const用来函数重载,const修饰了函数,就视为重载那个函数,形成const版本)
五. 修饰类成员变量
    1. 常量成员变量必须在声明时 或 在构造函数的初始化列表中进行初始化(常用),之后不能被修改。 (不能在构造函数体中初始化常量成员变量)
    2. 如果常量成员变量是静态的,即属于类而不是对象,那么它的声明和定义方式略有不同。静态常量成员变量需要在类外部进行定义和初始化。
        class MyClass {
        public:
            static const int staticConstValue; // 静态常量成员变量声明
        };
        // 静态常量成员变量定义和初始化
        const int MyClass::staticConstValue = 10;

4. c++什么时候生成构造函数?

c++ 复制代码
1. 空的类定义不会生成构造函数
2. 如果一个类没有显式定义任何构造函数,编译器会自动生成一个默认构造函数。
3. 如果一个类定义了一个带有默认参数的构造函数,编译器不会自动生成默认构造函数。但是,如果该构造函数的所有参数都有默认值,那么它可以被视为默认构造函数。

1. 类a内数据成员是对象b ,而b提供了默认构造函数,为了让b的构造函数
2. 类A的基类提供了默认构造函数,A必须生成构造函数
3. 类内定义了虚函数 为了实现多态机制,需要为类维护虚函数表 ,类所有对象保存一个指向虚函数表的指针,这将在构造函数初始化;

5. extern 关键字作用

c++ 复制代码
extern关键字主要用于声明变量或函数是定义在另一个文件中,或者在同一个文件的其他位置。它告诉编译器该变量或函数在其他地方有定义。

extern的主要作用是管理跨文件的符号可见性,是在多文件程序中引用全局变量和函数的关键工具。

extern常用于在一个源文件中引用另一个源文件中定义的全局变量。

对于函数,extern通常是隐式的,因为默认情况下,函数的声明和定义都具有extern链接特性。因此,我们一般不需要显式地使用extern,但是在某些情况下,可以使用它来强调函数的外部链接。

c++调用 c 

// C++文件
extern "C" {
    void cFunction();  // 声明一个C风格的函数
}

6. c_c++中强制类型转换使用场景

c++ 复制代码
staic_cast : 用于基本数据类型之间的转换,如int转float,double转int等
    空指针转换为目标类型的空指针
    将非const转换为const
    不安全的向下转型

const_cast : 用于去除常量性,如将const int转为int  去掉指针引用的const;目的用于修改指针引用的权限

reinterpret_cast : 用于指针之间的转换,如将int*转为char*等
    改变引用,指针的类型 转换为整形  , 将整形转换引用或指针 
    (指针,整形,引用,函数指针,成员指针)
    无安全检查
    
dynamic_cast : 用于类之间的转换,如基类转派生类等
    向下转型,运行时进行检测的类型转换,  引用 转换失败会抛出bad_cast异常
    作用于指针引用 
                基类指针 指向派生类对象

7. 如何避免野指针?

c++ 复制代码
1. 初始化指针:在声明指针变量时,尽量立即对其进行初始化。如果暂时没有合适的初始值,可以将其初始化为NULL或nullptr(在C++11及以后)。
2. 使用指针操作对象之前,检查是否为指针对象分配内存
3. 及时释放内存:在使用动态内存分配函数(如malloc、calloc、realloc、new等)分配内存后,如果不再需要这些内存,应及时使用free或delete释放内存,并将指针设置为NULL或nullptr。
4. 在C种需要对空间数据置空 memset
5. 避免重复释放:确保每个动态分配的内存只被释放一次,重复释放同一块内存会导致未定义行为。
6. 使用智能指针:在C++中,可以使用智能指针(如std::unique_ptr、std::shared_ptr)来自动管理内存,避免手动管理内存带来的风险。
7. 避免返回局部变量的地址:函数内部声明的局部变量在函数返回后会被销毁,因此不要返回这些变量的地址。

8. static关键字的作用

c++ 复制代码
static关键字修饰的东西 : 变量 函数 
        
1. static 修饰的东西在函数体中时,其作用范围只存在此函数体中,其他函数不能访问到
2. static 修饰的东西在模块内(cpp/h) ,
    在cpp源文件声明,作用范围是此源文件,其他模块源文件声明相同名称的static不冲突;
    声明在头文件(.h),其他包含 此头文件的都可以访问statc修饰的东西
    
3. static在类中 : 
    以下都为整个类所有:(属于类而不是类的实例)
    (1),修饰成员变量  所有对象共享同一个静态成员变量。
    (2),修饰成员函数 (不接收this指针)  静态成员函数不能访问非静态成员变量和非静态成员函数。
    

9. c++ 什么是深拷贝?什么是浅拷贝?

c++ 复制代码
浅拷贝:
浅拷贝在复制对象时,只复制对象中的基本数据类型成员和指针值,而不复制指针指向的内存内容。这意味着复制后的对象中的指针将与原对象共享同一块内存。
如果某个对象被析构,而该对象的指针指向的内存也被释放,那么其他共享同一内存的对象可能会访问已释放的内存,导致未定义行为甚至程序崩溃。这种情况称为"双重释放"(double free)。
在C++中,如果没有为类定义自定义的拷贝构造函数,编译器提供的默认拷贝构造函数就是浅拷贝。

深拷贝:
深拷贝不仅复制对象中的基本数据类型成员,还会为指针指向的内存区域分配新内存,并复制内存中的实际内容。这样,复制后的对象拥有独立的内存,不与原对象共享。
需要自定义拷贝构造函数和赋值操作符,以实现深拷贝逻辑,对每个指针成员做内存分配和内容复制。
避免了浅拷贝中的重复释放问题,因为每个对象拥有自己的内存副本。

10. 简述strcpy、sprintf与memcpy的区别?

c++ 复制代码
他们都能实现字符串拷贝功能
strcpy 将源字符串复制到目标字符串中,只适用于以\0结尾的字符串,复制时会自动添加终止符\0。
目标字符串必须有足够的空间来容纳源字符串及其终止符。

sprintf 将格式化的数据写入字符串中。类似于printf,但输出到字符串而不是标准输出。
支持多种格式化选项,如整数、浮点数、字符串等。 目标字符串必须有足够的空间来容纳格式化后的数据及其终止符。

memcpy 复制源内存块到目标内存块中。适用于任意类型的数据,不仅仅是字符串。 
不会自动添加终止符\0。 目标内存块必须有足够的空间来容纳源内存块。
相关推荐
BanLul1 分钟前
进程与线程 (三)——线程间通信
c语言·开发语言·算法
落羽的落羽7 分钟前
【落羽的落羽 数据结构篇】栈和队列
c语言·数据结构
一个 00 后的码农12 分钟前
25林业研究生复试面试问题汇总 林业专业知识问题很全! 林业复试全流程攻略 林业考研复试真题汇总
考研·面试·面试问题·考研复试·考研调剂·面试真题·林业考研
ChoSeitaku1 小时前
12.重复内容去重|添加日志|部署服务到Linux上(C++)
linux·c++·windows
挣扎与觉醒中的技术人1 小时前
网络安全入门持续学习与进阶路径(一)
网络·c++·学习·程序人生·安全·web安全
OTWOL2 小时前
【C++编程入门基础(一)】
c++·算法
谏君之2 小时前
C语言实现的常见算法示例
c语言·算法·排序算法
曾浩轩2 小时前
51单片机学习之旅——C语言小知识
c语言·学习·51单片机
宇寒风暖2 小时前
侯捷 C++ 课程学习笔记:内存管理与工具应用
c++·笔记·学习
Smile丶凉轩3 小时前
数据库面试知识点总结
数据库·c++·mysql