C/C++面试题之语言基础篇(一)

简介: C/C++面试题之语言基础篇(一)



准备C/C++面试需要深入研究语言基础知识,掌握控制流结构、函数、指针和标准库,同时准备好回答各种与C/C++编程相关的问题,这将有助于你在面试中脱颖而出。希望这些建议对你有所帮助,祝你面试顺利!

简述下C++语言的特点和对象的特点

C++特点:

  1. 面向对象
  2. 封装和数据隐藏:把相关的数据封装成一个“类”组件
  3. 继承和重写:是子类自动共享父类属性和方法,这是类之间的一种关系
  4. 多态:增强软件的灵活性和重用性,通过virtual关键字

对象特点:

  1. 状态:用来描述对象的基本特征
  2. 行为:为用来描述对象的功能
  3. 标识:指对象在内存中都有一个唯一的地址值用来和其他对象区分开来

OOP 三大特点和继承中三个修饰符

c的三大特点是:

  1. 封装:封装是将数据和操作数据的方法封装在一个单元(类)内部,然后通过公共接口暴露有限的访问权限。
  2. 继承:继承允许一个类继承另一个类的属性和方法。
  3. 多态:多态允许不同类的对象对相同的消息(方法调用)作出不同的响应。

继承中的三个修饰符

  1. public:公有继承,派生类继承基类的公有成员,这些成员在派生类中仍然是公有的。
  2. protected:保护继承,派生类继承基类的保护成员,这些成员在派生类中变为保护或私有的。
  3. private:私有继承,派生类继承基类的私有成员,这些成员在派生类中变为私有的,不能被外部访问。

C语言和C++的区别

与C语言区别:

  1. C语言是面对过程的,而C++是面对对象的。C和C++都有结构的概念,但是在C语言中结构只有成员变量没有成员方法,而在C++结构中,它可以有自己的成员变量以及成员方法。
  2. C语言中结构的成员是默认是公共的,而在C++中没有加限定符则默认是私有的
  3. C++中有bool类型,而C语言可没有bool类型
  4. 定义常量C语言使用#define,而C++使用const
  5. 在C中,强制类型转换通常例如:(int)float_variable
    在C++中,有四种类型转换操作符:static_cast<double>(float_variable)
  6. malloc/free和new/delete区别:

6.1 malloc()与free ()是C语言的标准库函数,new/delete是C++的运算符,所以new/delete不        需要头文件进行声明;

6.2 new/delete可以调用构造函数和析构函数;

new 和 malloc 的区别

  1. new 是运算符,而 malloc 是库函数
  2. new 返回的是指针,不需要进行类型转换;malloc 返回的是void *(无类型指针)。需要手动将其转换为适当的类型
  3. new 会调用构造函数来初始化对象(如果是自定义类的对象),而 malloc 不会执行构造函数。

void *

void * 是通用指针类型,被称为"无类型指针"。可以用来指向任何数据类型的内存地址。使用 void * 指针时需要谨慎,必须进行类型转换

示例(int 型转换):

int * intPtr=static_case<int *>(ptr);

因为不提供类型检查,可能导致运行时类型错误。

#include <iostream>
using namespace std;
int main()
{
    int x = 42;
    double y = 3.14;
    char c = 'A';
    void *ptr; // 声明一个无类型指针
    ptr = &x; // 指向整数
    //cout << *ptr << endl; //报错
    int *intPtr = static_cast<int *>(ptr);//类型转换语句
    cout << "*intPtr = "<<*intPtr << endl; // 42
    ptr = &y; // 指向双精度浮点数
    double *doublePtr = static_cast<double *>(ptr);
    cout << "*doublePtr = "<<*doublePtr << endl; // 3.14
    ptr = &c; // 指向字符
    char *charPtr = static_cast<char *>(ptr);
    cout << "*charPtr = "<<*charPtr << endl; // 'A'
}

C++中 struct 和 class 的区别

换个问法:说说C++结构体和C结构体的区别

  1. struct默认为public类型,而class默认为private类型
  2. struct只有public类型,而class支持public、protect以及private
  3. struct不支持成员函数,而class支持
  4. struct无法做到继承和重写,而class可以

include头文件的顺序以及双引号""和尖括号<>的区别

对于#include <a.h>,编译器从标准库路径开始搜索a.h

对于#include "a.h",编译器从用户的工作路径开始搜索a.h

导入C函数的关键字是什么,C++编译时和C有什么不同?

  1. 关键字:在C++中,导入C函数的关键字是extern,表达形式为extern “C”
    extern是C/C++语言中的一个关键字,用于声明一个变量或函数具有外部链接性,即这些变量或函数可以被其他文件访问。
  2. 编译区别:由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时一般只包括函数名

简述C++从代码到可执行二进制文件.exe的过程

有四个过程,预编译、编译、汇编、链接

C++函数只声明,不定义会在哪步报错

实际的错误通常发生在链接阶段,当链接器尝试将所有编译单元(源文件)组合在一起时。如果在链接过程中找不到函数的定义,链接器会生成一个"未定义的引用"错误。

static关键字的作用

  1. 隐藏。当同时编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性,故使用static在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。
  2. static的第二个作用是保持变量内容的持久。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。
  3. static的第三个作用是默认初始化为0.和全局变量一样存储在静态数据区。

说说静态变量什么时候初始化?

对于C语言的全局和静态变量,初始化发生在代码执行之前,属于编译期初始化

对于C++:全局或静态对象对象首次用到时才进行构造。

静态局部变量,全局变量,局部变量的特点

  1. 首先从作用域考虑
    全局变量:全局作用域,可以通过extern作用于其他非定义的源文件。
    静态全局变量 :全局作用域+文件作用域,所以无法在其他文件中使用。
    局部变量:局部作用域,比如函数的参数,函数内的局部变量等等。
    静态局部变量 :局部作用域,只被初始化一次,直到程序结束。
  2. 从所在空间考虑:除了局部变量在栈上外,其他都在静态存储区。
  3. 生命周期: 局部变量在栈上,出了作用域就回收内存;而全局变量、静态全局变量、静态局部变量都在静态存储区,直到程序结束才会回收内存。

内联函数和宏函数的区别

区别:

  1. 宏定义不是函数,无返回值、参数列表等。而内联函数本质上是一个函数,比如有返回值、参数列表等
  2. 宏函数是在预编译期做简单字符串替换 ;而内联函数则是在编译期进行代码插入
  3. 宏定义是没有类型检查的,无论对还是错都是直接替换;而内联函数在编译的时候会进行类型的检查

说说内联函数和函数的区别,内联函数的作用。

  1. 关键字不同: 内联函数使用 inline 关键字进行声明,而普通函数不需要。
  2. 编译时展开: 内联函数在编译时展开,而普通函数则在运行时进行函数调用。
  3. 是否需要寻址:内联函数不需要寻址,而普通函数需要寻址;
  4. 复杂程序不同:内联函数要求代码简单,不能包含switch、while语句以及递归。

内联函数的作用:提高程序的性能。

说说运算符i++和++i的区别

先看到实现代码:

int i = 5;
int a = i++; // a = 5, i = 6
int i = 5;
int b = ++i; // b = 6, i = 6

赋值顺序不同:++ i 是先加后赋值;i ++ 是先赋值后加;

说说const和define的区别

查看链接:const与define详解

C++多态与虚函数

查看链接:虚函数实现多态详解

简述C++有几种传值方式,区别是什么?

传参方式有这三种:值传递、引用传递、指针传递

  1. 值传递:形参即使在函数体内值发生变化,也不会影响实参的值;
void foo(int x) {
    x = x * 2; // 修改的是副本,不会影响原始数据
}
  1. 引用传递:形参在函数体内值发生变化,会影响实参的值;
void bar(int &x) {
    x = x * 2; // 修改原始数据
}
  1. 指针传递:在指针指向没有发生改变的前提下,形参在函数体内值发生变化,会影响实参的值;
void baz(int *x) {
    *x = *x * 2; // 修改原始数据
}

堆和栈的区别

C++ 有几种构造函数

  1. 默认构造函数:默认构造函数没有参数,它用于创建对象的默认初始化。如果你没有为类定义构造函数,并且没有提供初始化值,编译器会自动生成一个默认构造函数。
class MyClass {
public:
    MyClass() {
        // 默认构造函数
    }
};
  1. 带参数的构造函数 :带参数的构造函数接受一个或多个参数,用于初始化对象的成员变量。
class MyClass {
public:
    MyClass(int x, double y) {
        // 带参数的构造函数
    }
};
  1. 拷贝构造函数:拷贝构造函数用于在创建一个对象时,将另一个对象的值复制到新对象中。它通常以引用参数传递另一个对象。
class MyClass {
public:
    MyClass(const MyClass& other) {
        // 拷贝构造函数
    }
};

什么是拷贝构造函数

它是单个参数的构造函数,其参数是与它同属一类的对象的(常)引用;类定义中,如果未提供自己的拷贝构造函数,C++提供一个默认拷贝构造函数,该默认拷贝构造函数完成一个成员到一个成员的拷贝,属于浅拷贝

深拷贝和浅拷贝区别

浅拷贝(默认拷贝函数)︰将原对象或原数组的引用直接赋给新对象,新数组,新对象/新数组只是原对象的一个引用。

深拷贝∶创建一个新的对象和数组,将原对象的各项属性的"值”(数组的所有元素)拷贝过来,是“值",深拷贝会在堆内存Q中另外申请空间来储存数据,从而解决了指针悬挂问题。

注意:当数据成员中有指针时,必须要用深拷贝

左值引用和右值引用区别和目的

左值是能够出现在表达式左边的值如变量,右值是只能出现在等号右边的值,如常量。

  1. 左值可以取地址,右值不可。
  2. 左值引用表达式结束后对象依然存在。右值引用赋值表达式结束后对象会被销毁
  3. 左值引用后可以利用别名修改左值对象;右值引用绑定的值不能修改

目的

  1. 左值引用目的是为了传递和操纵数据
  2. 右值引用的目的是为了实现完美转发(传递参数的数据类型+左右值属性)+移动语义
  • 完美转发(Perfect Forwarding):右值引用允许在函数参数中精确传递参数的值类别(左值或右值)。
  • 移动语义(Move Semantics):移动语义允许将资源从一个对象移动到另一个对象,而不是进行昂贵的数据复制。
template <typename T>
void wrapper(T&& arg) {
    // 在这里使用 std::forward 来实现完美转发
    some_function(std::forward<T>(arg));
}
void some_function(int& x) {
    // 处理左值引用
}
void some_function(int&& x) {
    // 处理右值引用
}

std::move 是什么

std::move用于将左值强制转换为右值引用,然后原来的x变成空串。

示例中,source 最初指向”hello,world!“。使用 std::move 后,source 的内容被移动到了 destination,而 source 变成了一个空字符串。

#include <iostream>
#include <string>
using namespace std;
int main() {
    string x = "Hello, World!";
    string y;
    y = std::move(x);
    cout << "x: " << x << endl; // 输出为空字符串
    cout << "y: " << y << endl; // 输出"Hello, World!"
    return 0;
}

strcpy存在什么安全问题?

strcpy 是标准C库函数,用于将一个字符串复制到另一个字符串中。然而它不检查源字符串的长度,可能会导致缓冲区溢出,引发安全漏洞。

结构体的比较,怎么判断两个对象是否相等

需要逐个比较它们的成员变量(字段)

继承关系中的子类能访问父类哪些成员变量以及成员函数

在继承关系中,子类(派生类)通常可以访问父类(基类)的以下成员变量和成员函数,具体访问权限取决于这些成员的访问控制修饰符:

  1. 公有成员(public):子类可以访问父类的公有型成员变量和函数。
  2. 受保护成员(protected):子类可以访问父类的受保护成员变量和函数。
  3. 私有成员(private):子类不能访问父类的私有成员变量和函数。
  4. 构造函数和析构函数:如果基类的构造函数和析构函数是公有的,子类可以直接访问它们;如果基类的构造函数和析构函数是受保护或私有的,子类仍然可以访问它们,但只能在子类的构造函数和析构函数内部调用它们,不能在类外部使用。

c++中A类访问B类中的私有成员的解决方法

  1. 使用友元函数或友元类:B类中声明A类为友元,或者在A类中声明B类为友元
  2. 提供公有成员函数或接口:如果希望B类的私有成员被A类间接访问,可以在B类中提供一些公有成员函数或接口,以允许A类通过这些函数来访问B类的私有成员。

数组和链表的区别

目录
相关文章
|
30天前
|
C++
C++ 语言异常处理实战:在编程潮流中坚守稳定,开启代码可靠之旅
【8月更文挑战第22天】C++的异常处理机制是确保程序稳定的关键特性。它允许程序在遇到错误时优雅地响应而非直接崩溃。通过`throw`抛出异常,并用`catch`捕获处理,可使程序控制流跳转至错误处理代码。例如,在进行除法运算或文件读取时,若发生除数为零或文件无法打开等错误,则可通过抛出异常并在调用处捕获来妥善处理这些情况。恰当使用异常处理能显著提升程序的健壮性和维护性。
45 2
|
30天前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
45 0
|
11天前
|
算法 程序员 Go
PHP 程序员学会了 Go 语言就能唬住面试官吗?
【9月更文挑战第8天】学会Go语言可提升PHP程序员的面试印象,但不足以 solely “唬住” 面试官。学习新语言能展现学习能力、拓宽技术视野,并增加就业机会。然而,实际项目经验、深入理解语言特性和综合能力更为关键。全面展示这些方面才能真正提升面试成功率。
35 10
|
8天前
|
JavaScript 前端开发 测试技术
一个google Test文件C++语言案例
这篇文章我们来介绍一下真正的C++语言如何用GTest来实现单元测试。
9 0
|
1月前
|
编译器 C++ 容器
C++语言的基本语法
想掌握一门编程语言,第一步就是需要熟悉基本的环境,然后就是最重要的语法知识。 C++ 程序可以定义为对象的集合,这些对象通过调用彼此的方法进行交互。现在让我们简要地看一下什么是类、对象,方法、即时变量。 对象 - 对象具有状态和行为。例如:一只狗的状态 - 颜色、名称、品种,行为 - 摇动、叫唤、吃。对象是类的实例。 类 - 类可以定义为描述对象行为/状态的模板/蓝图。 方法 - 从基本上说,一个方法表示一种行为。一个类可以包含多个方法。可以在方法中写入逻辑、操作数据以及执行所有的动作。 即时变量 - 每个对象都有其独特的即时变量。对象的状态是由这些即时变量的值创建的。 完整关键字
46 2
|
2月前
|
前端开发 编译器 程序员
协程问题之为什么 C++20 的协程代码比其他语言的协程 demo 长很多如何解决
协程问题之为什么 C++20 的协程代码比其他语言的协程 demo 长很多如何解决
|
3月前
|
程序员 编译器 C++
探索C++语言宝库:解锁基础知识与实用技能(类型变量+条件循环+函数模块+OOP+异常处理)
探索C++语言宝库:解锁基础知识与实用技能(类型变量+条件循环+函数模块+OOP+异常处理)
33 0
|
3月前
|
存储 编译器 开发工具
C++语言教程分享
C++语言教程分享
|
3月前
|
自然语言处理 编译器 C语言
C++语言入门教程
C++语言入门教程
|
3月前
|
存储 编译器 程序员
C++语言基础学习
C++语言基础学习