C/C++面试常问问题总结

1、C/C++语言区别

从机制上:C是面向过程的;C++是面向对象的,提供了类,侧重于类的设计而不是逻辑的设计。

从适用的方向:C适合要求代码体积小的,效率高的场合,如嵌入式;C++适合更上层的,复杂的项目;

从内容上,C++比C来说扩充的东西太多了,比如类、继承、多态、模板等。

出处:https://blog.csdn.net/kyrie_sakura/article/details/129431998

2、存储类型关键字之const

  • 语法:
    1、修饰变量:变量值不变。初始化后的赋值都是非法的。举例:
    const int a=5;
    a = 6; //非法,程序报错
    2、修饰指针(指针常量与常量指针):const在左边,const在右边含义不同。
    常量指针:const在左边:const int p; 或int const *p; //修饰的是指针所指向的内容(*p),指针所指向的内容不能不通过指针来改变,指针变量本身可以改变。举例:
int main()
{
   const int num = 10;
   const int *p = #
   *p = 20;     //报错,*P被修饰后,指针指向的值无法修改
}

指针常量:const在右边: int const p;; //修饰的是指针, 指针所指向的内容可以改变,指针变量本身不可以改变。举例:

int main()
{
    int num2 = 1; 
    const int num = 10;
    int* const p = #
   *p = 20;    //*p可以改变
    p =  &num2   //报错,指针p无法修改
}

3、修饰函数

  • 常函数:
    1、定义:成员函数后加const称为常函数
    2、常函数内不可以修改成员属性
    3、成员属性声明时加关键字mutable,在常函数中依然可以修改。

  • 常对象:
    1、声明对象前加const称该对象为常对象
    2、常对象只能调用常函数。
    -常函数举例:

class Person
{
public:
    void showPerson()
   {
        m_A = 100;
   }
    int m_A;
}
此时m_A值可以被修改为100。如果改为
class Person
{
public:
    void showPerson() const
   {
        m_A = 100;
   }
    int m_A;
}

此时m_A值不可以被修改为100。因为函数后面加const,成员函数showPerson();变为常函数,不可以修改成员属性。

  • 出处:https://blog.csdn.net/weixin_47257473/article/details/122633926 、黑马程序员

3、const 相对 #define 的优点

1、 const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。
而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应) 。
2、有些集成化的调试工具可以对 const 常量进行调试,但是不能对宏常量进行调试。

4、存储类型关键字之Static

1、修饰局部变量:改变变量存储区域,由栈区变成全局区。应用举例:

void Add()
{
   static int a = 0;
    a++;
}

每次函数执行完,a加1,且不被释放,下一次进入在原来值的基础上再加1。
2、修饰全局变量:限制了全局变量的外部性。应用举例:原本可以用extern在其它文件中调用全局变量,被static修饰之后,用extern也无法调用使用。
3、修饰函数:限制了函数的外部性。只能在自己源文件中使用,其它文件无法调用。

  • 出处:https://blog.csdn.net/m0_62588419/article/details/127427782

5、存储类型关键字之extern

-语法:变量在其它文件定义过,当前文件需使用该变量时,用extern。

-extern “C”:

1.C代码被C++代码调用时,表明这是C代码,要按照C语言的规则去解读,而不是按照C++的规则去解析

#ifdef __cplusplus extern "C" {  #endif

// C代码

#ifdef  __cplusplus }#endif
  • 出处:https://blog.csdn.net/z702143700/article/details/46805241

6、其他关键字之volatile

  • 作用:用volatile修饰变量,确保系统每次都从变量所在内存读取数据。编译器对变量不进行优化,不提供其他方式获取变量值,确保每次获取的变量都是最新的。

  • 应用场景:
    1、中断服务程序修改的变量需加volatile
    当变量在触发中断程序中修改,而编译器判断主函数里没有修改该变量,系统不会执行从内存到寄存器读取变量操作,因此中断程序修改的值没有被利用。

2、多线程应用中被几个任务共享的变量应该加volatile
当读取一个变量时,编译器优化有时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存器中取值;当变量因别的线程等而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致 。

3、并行设备的硬件寄存器
存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写可能都有意义。如果不加volatile,编译器会优化成只保留变量最后一次变化值。

参考:https://blog.csdn.net/qq_41709234/article/details/123028868?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-2-123028868-blog-129496826.235%5Ev38%5Epc_relevant_sort_base1&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-2-123028868-blog-129496826.235%5Ev38%5Epc_relevant_sort_base1&utm_relevant_index=3

7、数字类型关键字之Struct()声明、初始化

第一种:不加变量列表

struct 结构体名
{
    成员列表
};

举例:

struct book
{
  float price;
  char name[40];
    int id[20]};//

此结构体包含三个成员,分别是价格price,书名name,书籍序列号id
说明:
book test; 结构体名book,变量名test。

第二种:加变量列表

struct book
{

    float price;
    char name[40];
    int id[20];
}test,test1;

//结构体名book,2个变量名分别为test、test1。

第三种:tyepdef

 typedef struct(结构体名,可删)
{
    成员列表
}结构体名;

举例:

 typedef struct
{
 uint32_t USART_BaudRate; // 波特率
 uint16_t USART_WordLength; // 字长
 } USART_InitTypeDef;

USART_InitTypeDef usart1; USART_InitTypeDef 是结构体名,usart1是 变量名。
-初始化:
第一种:定义时赋值
举例:

struct book
{

    float price;
    char name[40];
    int id[4];
};
book test =3.14"version",{1,2,3,4}; //顺序需对应声明顺序

第二种:定义时乱序赋值(C风格)

block test =
{
     .price= 3.14,
    .name= "version",
    .id= {1,2,3,4}
};  //不考虑顺序

第三种:定义时乱序赋值(C++风格)

block test =
{
    price:3.14,
    name: "version",
    id:{1,2,3,4}
};

参考:https://blog.csdn.net/m0_62588419/article/details/127427782

8、内存分区模型

  • 内存分区:
    C语言开发对内存使用有区域划分,分别是栈区(stack)、堆区(heap)、BSS、数据段(data)、代码段(text)。
    1、栈区:存放函数参数值及局部变量编译器管理
    2、堆区:程序员分配和释放。若程序员不释放,由操作系统回收。
    3、BSS段 未初始化全局变量,未初始化全局静态变量
    4、数据段 已初始化全局变量、已初始化全局静态变量、局部静态变量、常量数据
    5、代码区:存放函数体的二进制代码、字符串常量,由操作系统管理(低地址)
  • 分区意义:
    不同数据赋予生命周期,更灵活。
  • 备注:程序运行后才有栈区和堆区。

9、堆和栈的区别(程序内存布局)

堆和栈都是操作系统对内存管理的方式

-管理方式:
1.栈是由操作系统自动分配释放,用于存放函数的参数值、局部变量等
2.堆是由开发人员分配释放,若开发人员不释放,最后由OS回收,例如C语言用malloc()函数申请,free()函数释放;C++用new运算符申 请,用delete运算符释放
-空间大小:每个进程所拥有的栈的大小要远远大于堆
-生长方向:栈的内存地址由高到低;堆的内存地址由低到高。
-分配效率:栈比堆效率高的多。因为栈由操作系统分配,有专门寄存器存放栈地址,压栈出栈有专门的指令

10、有malloc和free,为什么需要new和delete

思路:从两者的区别中,寻找new和delete的优势,正是因为拥有了malloc和free没有的优势,所以才会被需要。
1、本质:malloc和free是C语言标准库中的函数,,需要调用头文件#include <stdlib.h>;new和delete是C++关键字,不需要调用头文件。
2、调用方式:malloc()和free()以函数调用形式调用,并指定分配的内存大小;new和delete直接在类型后面添加括号即可,可不显示指定内存大小。
举例:(帮助理解、使用)

//malloc()和free()
char *p = (char*)malloc( sizeof(char) );  //分配1个char型空间
free(p);
或
int*p = (int*)malloc( sizeof(int) *100);  //分配100个int型空间
free(p);

//new和delete
char *p = new char;  ,分配大小为sizeof(char);
delete p;
或
char *p = new char[10];  ,分配大小为sizeof(char)*10;
delete[] p;  //注意删除数组时,需要加[]

3、内存分配方式:malloc只负责分配内存空间,并返回该内存空间的起始地址,但不会进行初始化。而new除了分配内存空间外,还会自动调用构造函数对对象进行初始化。delete会自动调用对象的析构函数来清理资源;而free只是简单地释放指针所指向的内存块。

11、函数传参方式

1、值传递函数——值传递
2、地址传递
3、引用传递
(c语言没有引用传递,只有c++有)

12、虚函数

定义:被virtual关键字修饰的成员函数是虚函数。

声明:virtual 类型 函数名(参数列表);
例:virtual BOOL ReadStateProcess(void);

作用:实现多态性(同一个函数(函数名、形参和返回值都相同)可以被定义多次),将接口与实现分离

13、纯虚函数

定义:申明成以下格式的是纯虚函数。

声明:virtual 类型 函数名(参数列表)= 0;
例:virtual BOOL ReadStateProcess(void) = 0;

备注:
1、最后面的“=0”并不表示函数返回值为0,它只起形式上的作用,告诉编译系统“这是纯虚函数。
2、包含纯虚函数的类叫抽象类,只能被继承,不能被实例化。继承该抽象类的子类,可以实例化。

实例化方法:
1、重新声明纯虚函数为虚函数(如果声明为纯虚函数,不能够实例化对象的)
2、定义所有虚函数(注意成员函数定义需要在前面加上类名)。
举例:(帮助理解、使用)

class CFather
{
   CFather();

//成员变量
    INT8U uch_test1;
//成员函数
  virtual BOOL ReadStateProcess(void) = 0;

   ~CFather();
}
CFather类为抽象类,因为他包含纯虚函数,他不能实例化对象,如father classTest; 是不允许的。

class CSon:CFather
{
   CSon(){};

//成员变量
    INT8U uch_test2;
//成员函数
  virtual BOOL ReadStateProcess(void) ;

   ~CSon(){};
}

CSon继承了CFather类,在CSon类中重新声明ReadStateProcess函数为虚函数,因此CSon类可以实例化对象。且ReadStateProcess()可以实现。
BOOL CSon::ReadStateProcess(void)
{
    return TRUE;
}

14、引用与指针的区别

1、指针就是内存地址,指针变量用来存放内存地址的变量;引用是给变量起别名,编译器不会给被引用的变量开辟空间。
举例:int a =10;
int&b = a; 变量b没有独立的内存空间,与a共用内存空间。
int * b = &a; 指针变量b是变量a的内存地址,编译器开辟内存地址空间 给指针变量b
2、引用必须初始化,且初始化后不可以更改。即指定为某个量的别名,就不能成为另一个量的别名。指针不强制初始化,但为了预防野指针,一般进行初始化。
3、引用比指针使用起来相对安全
4、在sizeof中含义不同: 引用结果为引用类型的大小,但指针始终是地址空间,所占字节个数(32位平台占4个字节)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值