最新C/C++经典面试题(50道附答案)

文章目录


前言

今天分享给大家的是比较基础全面的C/C++经典面试题,提供给有需要的同学们学习!


一、01-C/C++语言基础

1.32 位和 64 位系统有什么区别?

32位和64位系统是指计算机的处理器架构(或称为CPU架构)的不同。

主要区别如下:

1.内存支持:32位系统最多只能支持4GB的内存,而64位系统可以支持超过4GB的内存。这意味着64位系统可以更有效地利用大容量的内存,提供更好的性能和更高的系统响应速度。

2.寻址能力:32位系统使用32位寻址,即每个内存地址由32位二进制数字表示。这意味着32位系统最多可以寻址2^32个内存位置,约为4GB。而64位系统使用64位寻址,可以寻址2^64个内存位置,几乎无限大。

3.软件兼容性:32位软件通常可以在64位系统上运行,但64位软件不能在32位系统上运行。这是因为64位系统需要特定的64位指令集来执行,而这些指令在32位系统中是不支持的。

4.性能:64位系统相对于32位系统具有更好的性能,特别是在处理大量数据或进行复杂计算时。64位系统的处理器具有更大的寄存器和更广泛的指令集,可以更快地执行操作。

总结起来,64位系统相比32位系统具有更高的内存支持、更大的寻址能力、更好的性能和更广泛的软件兼容性。对于处理大量数据或需要更高性能的任务,64位系统是更好的选择。然而,在某些情况下,32位系统可能仍然适用,特别是在旧的硬件或需要与特定32位软件兼容的场景下。

2. 在不使用 sizeof 的情况下,如何判断操作系统是 32 位还是 64 位?

问题:
我们知道在 C/C++ 中使用运算符 sizeof 计算指针变量的大小,如果返回值为 4 字节则是 32 位,如果返回 8 字节,则表示 64 位系统。

现在要求不使用 sizeof 如何判断操作系统是 32 位还是 64 位。

解法:
指针变量位宽
根据栈指针变量宽度来判断。对指针变量地址相减时,须将其转换为 char* 或无符号长整型(unsigned long),否则相减的结果为 1,表示地址间隔内存放元素的个数。

#include <iostream>
using namespace std;

int main() {
   
   
	void* a;
	void* b;
	int scope = (char*)&a - (char*)&b;
	cout << "&a:" << &a << endl;
	cout << "&b:" << &b << endl;
	cout << "scope:" << scope << endl;
	if(scope==8) {
   
   
		cout << "64bits" << endl;
	} else {
   
   
		cout << "32bits" << endl;
	}
}

使用g++ -m64 main.cpp -o a64.out编译执行输出:
&a:0x7fffcc84b650
&b:0x7fffcc84b648
scope:8
64bits

使用g++ -m32 main.cpp -o a32.out编译执行输出:

&a:0xffbb42e8
&b:0xffbb42e4
scope:4
32bits

查看环境变量(Windows):在Windows系统中,可以查看PROCESSOR_ARCHITECTURE环境变量来确定系统的架构。如果其值为"x86",则表示32位系统;如果其值为"AMD64"或"IA64",则表示64位系统。

查看系统路径(Windows):在Windows系统中,32位和64位应用程序通常会安装到不同的目录下。例如,32位应用程序默认安装到C:\Program Files (x86)目录下,而64位应用程序默认安装到C:\Program Files目录下。通过检查这些默认安装路径,可以判断系统的架构。

3. 你用过哪些编程软件?

Qt Creator、VS、VC、Dev C++、IntelliJ IDEA、PyCharm等等...

4. QtCreator 调试所用的快捷键是哪些,简述每个快捷键功能?

  Qt Creator常用快捷键
    运行  ctrl +R
    编译  ctrl +B
    帮助文档  F1 ,点击F1两次跳到帮助界面
    跳到符号定义 F2 或者ctrl + 鼠标点击
    注释 ctrl+/
    字体缩放  ctrl + 鼠标滚轮
    整行移动代码 ctrl + shift + ↑或↓
    自动对齐   ctrl + i
    同名之间的.h和.cpp文件跳转 F4

5. 编译生成的 Debug 版本和 Release 版本有什么区别?

Debug版本和Release版本是在Qt编译过程中产生的两种不同类型的可执行文件。

Debug版本主要用于开发和调试阶段,它包含了大量的调试信息,使得程序员可以方便地进行代码调试、错误定位和内存泄漏检测等。此外,Debug版本通常会禁用一些优化选项,以便更好地支持调试工具和断点设置。由于包含了额外的调试信息和运行时检查,Debug版本的程序体积较大,执行速度相对较慢。

而Release版本则是最终发布给用户的版本,它经过了优化和精简处理,以提高程序的性能和执行效率。在Release版本中,通常会启用各种优化选项,如代码优化、去除无用的符号和函数等。此外,Release版本还会省略或减少一些调试相关的代码和功能,进一步提升程序的执行速度和资源利用率。相比于Debug版本,Release版本的程序体积更小,执行速度更快。

总结起来,Debug版本适合开发和调试阶段,可以方便地进行代码调试和错误定位;而Release版本适合最终发布给用户使用,具有更高的执行效率和性能。

6. define、typedef 和 const 有什么关系和区别?

在C语言中,define、typedef和const是三个不同的关键字,它们具有不同的作用和用法。

1、#define:#define是一个预处理指令,用于定义宏。通过#define可以创建一个宏定义,将一个标识符与一个值或一段代码进行关联。在预处理阶段,所有的宏定义会被替换为相应的值或代码。例如:

#define MAX_SIZE 100
int array[MAX_SIZE];

在上述例子中,MAX_SIZE被定义为宏,它的值为100。在编译时,所有的MAX_SIZE会被替换为100。

2、typedef:typedef用于创建自定义的类型别名。通过typedef可以给已有的类型起一个新的名称,使得代码更易读且具备自说明性。例如:

typedef unsigned int uint;
uint num = 10;

在这里,typedef将unsigned int定义为别名uint,之后就可以直接使用uint作为无符号整型的类型。

3、const:const关键字用于声明常量。通过const关键字修饰的变量表示其值在程序运行期间不可被修改。例如:

const int MAX_SIZE = 100;

这里,MAX_SIZE被声明为常量,其值为100,在程序运行期间不可修改。

关系和区别:
define是一个预处理指令,用于简单的文本替换,可以定义宏。
typedef用于创建自定义类型别名,使代码更易读且具备自说明性。
const用于声明常量,使得变量的值在程序执行期间不可修改。
这三个关键字在功能和使用上有所不同,但都能在编程中提供一些便利。

7. continue、break 和 return 的区别?

在C语言中,continue、break和return是三个控制流程的关键字,它们具有不同的作用和使用场景。

continue:continue关键字用于循环语句(如for、while、do-while)中,用于跳过当前迭代并进入下一次迭代。当程序执行到continue语句时,会立即结束当前迭代,并直接跳转到循环条件判断处开始下一次迭代。例如:

for (int i = 0; i < 10; i++) {
   
   
    if (i % 2 == 0) {
   
   
        continue;  // 如果i是偶数,则跳过本次迭代
    }
    printf("%d ", i);
}

在上述例子中,当i为偶数时,continue语句会跳过printf语句继续下一次迭代。

break:break关键字用于循环语句和switch语句中,用于提前终止当前循环或跳出switch语句。当程序执行到break语句时,会立即结束所在的循环或switch语句,然后继续执行后续的代码。例如:

for (int i = 0; i < 10; i++) {
   
   
    if (i == 5) {
   
   
        break;  // 当i等于5时,提前终止循环
    }
    printf("%d ", i);
}

在上述例子中,当i等于5时,break语句会立即结束循环。

return:return关键字用于函数中,用于返回函数的执行结果,并终止当前函数的执行。当程序执行到return语句时,会将指定的返回值(如果有)返回给调用者,并结束当前函数的执行。例如:

int add(int a, int b) {
   
   
    return a + b;  // 返回a和b的和
}

在上述例子中,return语句将计算得到的a + b的结果作为函数的返回值返回给调用者。

区别总结:
continue用于循环语句内部,跳过当前迭代继续下一次迭代。
break用于循环语句或switch语句内部,提前终止循环或跳出switch语句。
return用于函数内部,返回函数的执行结果并终止函数的执行。

8. 初始化和赋值的区别?

初始化,是在程序运行前又系统将变量赋值.
赋值,是在程序开始运行之后完成,动作属于程序完成的.(变量定义后要初始化)

9. 声明和定义的区别?

声明:指定一个变量的标识符,用来描述变量的类型,用于编译器识别变量名所引用的实体.
定义:是对声明的实现或者实例化,连接器需要他来引用内存实体.定义操作只能做一次.

声明可以声明很多次,在很多地方声明
定义只能定义一次

10. 全局变量、局部变量、 static 变量的区别?

全局变量:生命周期为从声明处到整个程序,程序运行结束全局变量生命周期结束.可以进行多次赋值,可以作为返回值.
局部变量: 从函数被调用的时刻算起到函数返回调用处的时刻结束,可以多次赋值,生命结束,系统回收,不可作为返回值.可以和全局变量重名,但是会屏蔽全局变量.
static变量:分配在静态存储区,在整个程序期间不会释放,全局变量用static生命作用域只限于本文件模块.

11. 变量的生命周期和作用域分别是?

变量的生命周期(lifetime)和作用域(scope)是两个关键概念,用于描述变量在程序中存在的时间和可见范围。

变量的生命周期(lifetime):变量的生命周期指的是变量存在的时间段,即从创建到销毁的整个过程。变量的生命周期由其作用域和存储期决定。
变量的作用域(scope):变量的作用域指的是变量在程序中可见的范围,即变量可以被访问和使用的区域。作用域由变量的声明位置决定。
总结:
生命周期描述了变量从创建到销毁的时间段,包括静态存储期、自动存储期和动态存储期。
作用域描述了变量在程序中可见的范围,包括全局作用域、文件作用域和块作用域。

12. 在 C++程序中调用被 C 编译器编译后的函数,为什么要加 extern “C” ?

C++为了支持重载,对编译时函数的命名规则进行更改.使用extern “c”的方式在c++程序中声明C语言文件中的函数,在编译时告诉编译器使用C语言的规则对该函数的函数名进行重命名.
在C++中,如果需要调用被C编译器编译后的函数(也就是C语言函数),需要使用extern "C"语法来指定函数按照C的命名和调用约定进行编译和链接。这是由于C++与C在函数命名和调用约定上存在差异导致的。
通过添加extern "C"语法,可以告知C++编译器以C的命名和调用约定来处理函数,从而保证正确的链接和调用。

示例用法:

cpp
// C语言编译后的源文件(例如:example.c)
#ifdef __cplusplus
extern "C" {
   
   
#endif

void someFunction(); // 声明一个C语言函数

#ifdef __cplusplus
}
#endif

// C++源文件(例如:main.cpp)
extern "C" void someFunction(); // 使用extern "C"声明C语言函数的调用

int main() {
   
   
    someFunction(); // 调用C语言函数
    return 0;
}

在上述示例中,使用extern "C"告知C++编译器来处理C语言函数的链接和调用。这样就能够在C++程序中正确地调用C编译器编译后的函数。

13. 动态库和静态库的主要区别是什么?

动态库(Dynamic Library)和静态库(Static Library)是两种常见的代码库,它们在程序开发中有一些主要区别。

链接方式:
静态库:静态库在编译链接时会被完整地复制到可执行文件中。在使用静态库时,编译器会将库的代码和可执行文件的代码合并成一个独立的可执行文件。因此,静态库在编译时就被链接到可执行文件中,独立于运行时。
动态库:动态库在编译链接时不会被复制到可执行文件中,而是在运行时被加载到内存中。可执行文件只包含对动态库的引用,然后在运行时从系统或指定的路径加载动态库。这意味着多个应用程序可以
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值