腾讯C++面试题分享

面试专栏:http://t.csdnimg.cn/0i089

目录

1.引言

2.分析

2.1.在C语言中定义一个全局变量,但不初始化,它默认的值是多少?

2.2.-2的源码,反码、补码分别是什么?-3呢?它的公式是什么?

2.3.一个数组有n个元素,找到前k个最大的?

2.4.简历上写了双指针和二分查找算法,能否具体讲一下思路?

2.5.Linux中是怎样用C语言实现面向对象的封装、继承、多态的?

2.6.C++中的class和C语言中的struct有什么区别?

2.7.UDP数据包的最大长度是多少?为什么?

2.8.TCP通信中,read函数的返回值返回0代表什么?

2.9.写一个while(1)的死循环,一直使用malloc申请空间,程序会崩溃吗?

2.10.进程退出时,假设存在没有释放的资源,此时应该怎么做?

2.11.你使用过这个项目和Google的TCmalloc项目做过对比吗?

2.12.项目中是怎么解决内碎片和外碎片问题的?

2.13.项目中如果用户忘记释放内存或多次释放内存,有没有做特殊处理?


1.引言

        在过去的几年里,互联网行业经历了一系列的调整和变革,许多企业都缩减了招聘规模。前两天腾讯放出了5000个实习岗位,网上评论已炸锅。回暖了?互联网又行了?腾讯前两年秋招基本上都没怎么招,今天放出这么多岗位,也可能意味着互联网行业的景气度有所回升。

        今儿给大家分享一下这个面经。

2.分析

2.1.在C语言中定义一个全局变量,但不初始化,它默认的值是多少?

        在 C 语言中,如果定义一个全局变量但不进行显式初始化,那么该全局变量会被默认初始化为零值。具体的默认值取决于变量的类型:

  • 对于整型(int、char、long 等)和枚举类型,在未显式初始化时,默认值为 0。

  • 对于浮点型(float、double 等),默认值为 0.0。

  • 对于指针类型,默认值为 NULL。

2.2.-2的源码,反码、补码分别是什么?-3呢?它的公式是什么?

计算方法如下:

  1. 原码:正数的原码就是其本身,负数的原码是将其绝对值的原码的符号位取反。

  2. 反码:正数的反码就是其本身,负数的反码是将其绝对值的原码的除符号位外的其他位取反。

  3. 补码:正数的补码就是其本身,负数的补码是将其绝对值的原码取反后加 1。

对于正数,补码等于原码。

对于负数,补码等于反码加 1。

-2 的二进制表示:

  • 原码:1000 0010

  • 反码:1111 1101

  • 补码:1111 1110

-3 的二进制表示:

  • 原码:1000 0011

  • 反码:1111 1100

  • 补码:1111 1101

2.3.一个数组有n个元素,找到前k个最大的?

方法一:使用堆

  1. 建立最小堆:首先将数组的前 k 个元素建立一个包含 k 个元素的最小堆。

  2. 遍历数组:从第 k+1 个元素开始遍历数组,对于每个元素,如果比堆顶元素大,则将堆顶元素替换为当前元素,并对堆进行一次调整,使得堆顶元素仍然是堆中的最小值。

  3. 返回结果:遍历完成后,堆中的元素就是前 k 个最大的元素。

方法二:使用快速排序的思想

  1. 快速选择算法:可以使用类似快速排序的思想,选取一个枢轴元素,将数组分为两部分,一部分比枢轴元素大,一部分比枢轴元素小。如果枢轴元素的位置恰好是 k,则找到了前 k 个最大的元素。如果枢轴元素的位置小于 k,则在右侧部分继续查找。如果枢轴元素的位置大于 k,则在左侧部分继续查找。

  2. 优化:在快速选择算法中,可以对快速排序进行一些优化,例如随机选择枢轴元素,或者使用三数取中法选择枢轴元素,以提高算法的效率。

2.4.简历上写了双指针和二分查找算法,能否具体讲一下思路?

双指针

双指针算法是指在数组或链表等数据结构中,使用两个指针分别指向不同位置,通过移动这两个指针来解决问题的一种算法。

思路:

  1. 设定两个指针,一般初始化为数组或链表的头部或尾部。

  2. 根据问题要求,移动指针并进行相应的处理,直至两个指针相遇或达到特定条件。

应用场景:

  1. 数组中的两数之和:通过双指针遍历数组,找到两个数使它们的和等于目标值。

  2. 链表中的环检测:使用快慢指针,快指针每次移动两步,慢指针每次移动一步,如果存在环,两个指针最终会相遇。

  3. 归并两个有序数组:使用双指针分别指向两个数组的开头,比较两个指针所指元素的大小,将较小的元素放入新数组中。

二分查找

二分查找算法是一种在有序数组中查找目标值的高效算法。

思路:

  1. 设定左右边界指针,一般初始化为数组的起始和结束位置。

  2. 每次取中间位置的值与目标值比较,如果相等则返回,如果小于目标值,则在右半部分继续查找,如果大于目标值,则在左半部分继续查找。

  3. 重复以上步骤,直到找到目标值或左右边界指针相遇。

应用场景:

  1. 有序数组中的查找:通过二分查找可以在 O(logn) 的时间复杂度内找到目标值。

  2. 旋转数组的查找:可以先找到旋转点,然后再在两个有序子数组中分别进行二分查找。

2.5.Linux中是怎样用C语言实现面向对象的封装、继承、多态的?

在 Linux 中使用 C 语言实现面向对象的封装、继承和多态需要一些技巧,因为 C 语言本身并不直接支持面向对象的特性。可以通过结构体和函数指针等特性来模拟实现面向对象的概念。

封装

可以使用结构体来封装数据,并通过函数来操作这些数据,实现封装的效果。

#include <stdio.h>

// 定义一个封装数据的结构体
typedef struct {
    int data; // 数据成员
} Encapsulation;

// 设置数据的函数
void setData(Encapsulation *obj, int value) {
    obj->data = value;
}

// 获取数据的函数
int getData(Encapsulation *obj) {
    return obj->data;
}

int main() {
    Encapsulation obj; // 创建一个 Encapsulation 类型的对象
    setData(&obj, 42); // 设置数据为 42
    printf("%d\n", getData(&obj)); // 打印数据
    return 0;
}

结构体 Encapsulation 封装了一个整数 data,并通过 setData 和 getData 函数对其进行操作,实现了数据的封装。

继承

可以通过在子类中包含父类的结构体来实现继承的效果。

#include <stdio.h>

// 父类结构体
typedef struct {
    int data; // 父类数据成员
} Parent;

// 子类结构体,包含了父类的结构体
typedef struct {
    Parent parent; // 包含父类对象
    int childData; // 子类自己的数据成员
} Child;

// 设置子类数据的函数
void setChildData(Child *obj, int value) {
    obj->childData = value;
}

int main() {
    Child obj; // 创建一个 Child 类型的对象
    obj.parent.data = 42; // 设置父类数据
    setChildData(&obj, 24); // 设置子类数据
    printf("%d %d\n", obj.parent.data, obj.childData); // 打印父类数据和子类数据
    return 0;
}

子类 Child 包含了父类 Parent 的结构体,并且可以通过操作子类对象来操作父类对象,实现了继承的效果。

多态

可以通过函数指针来实现多态的效果

#include <stdio.h>

// 定义一个包含函数指针的结构体,实现多态
typedef struct {
    int data; // 数据成员
    void (*print)(void *); // 函数指针
} Polymorphism;

// 打印整数的函数
void printInt(void *obj) {
    printf("%d\n", ((Polymorphism *)obj)->data);
}

int main() {
    Polymorphism obj; // 创建一个 Polymorphism 类型的对象
    obj.data = 42; // 设置数据
    obj.print = printInt; // 设置函数指针为打印整数的函数
    obj.print(&obj); // 调用函数指针打印数据
    return 0;
}

Polymorphism 结构体包含了一个函数指针 print,可以指向不同的打印函数,实现了多态的效果。

2.6.C++中的class和C语言中的struct有什么区别?

  1. 访问权限:

    • 在 C++ 中,class 的默认成员访问权限是 private,而 struct 的默认成员访问权限是 public

    • 这意味着,如果不显式指定成员的访问权限,使用 class 定义的成员默认是 private 的,而使用 struct 定义的成员默认是 public 的。

  2. 默认继承权限:

    • 在 C++ 中,class 默认继承权限是 private,而 struct 默认继承权限是 public

    • 这意味着,如果不显式指定继承关系,使用 class 继承的成员默认是 private 继承,而使用 struct 继承的成员默认是 public 继承。

  3. 成员函数:

    • 在 C++ 中,class 中的成员函数默认是 private 的,而 struct 中的成员函数默认是 public 的。

    • 这意味着,在 class 中定义的成员函数需要通过 public 成员函数来访问,而在 struct 中定义的成员函数可以直接访问。

参考代码:

// C++中的class
class MyClass {
private:
    int privateMember;

public:
    void publicMethod() {
        // 可以直接访问privateMember
        privateMember = 10;
    }
};

// C语言中的struct
struct MyStruct {
    int publicMember;

private:
    void privateMethod() {
        // 不能在外部直接访问privateMethod
    }

public:
    void publicMethod() {
        // 可以直接访问publicMember
        publicMember = 20;
        // 不能在外部直接访问privateMethod
    }
};

2.7.UDP数据包的最大长度是多少?为什么?

UDP 数据包的最大长度是 65507 字节(64KB - 8 字节 UDP 头 - 20 字节 IP 头),这是由于 UDP 协议的设计和底层网络的限制所决定的。

UDP(用户数据报协议)是一种无连接、不可靠的传输协议,它将数据作为数据报发送,不提供可靠性保证和流量控制。UDP 的设计目标之一是尽可能简单和高效,因此没有像 TCP 那样的拥塞控制、重传机制等复杂特性。

UDP 数据包的最大长度受到以下因素的限制:

  1. IPv4 和 IPv6 的数据报长度限制:IPv4 数据报的最大长度是 65535 字节,IPv6 数据报的最大长度是 65535 字节。其中,IPv4 头部占用 20 字节,IPv6 头部占用 40 字节,因此 UDP 数据报的数据部分最大长度为 65535 - 20 = 65515 字节(IPv4)或 65535 - 40 = 65515 字节(IPv6)。

  2. UDP 头部长度:UDP 头部占用 8 个字节,包含源端口、目的端口、长度和校验和字段。

  3. 网络传输的 MTU(最大传输单元):MTU 是网络中能够传输的最大数据包长度。不同网络类型(如以太网、Wi-Fi 等)的 MTU 不同,通常以太网的 MTU 是 1500 字节。如果 UDP 数据包超过了 MTU,就会被分片发送,增加了网络传输的开销和复杂性。

2.8.TCP通信中,read函数的返回值返回0代表什么?

TCP 通信中,read 函数用于从已连接的 TCP 套接字中读取数据。当read函数返回 0 时,表示对端已关闭连接,即对端发送了一个正常的连接关闭请求。这种情况通常称为“对端正常关闭连接”。

详细讲解如下:

  1. 对端正常关闭连接:当对端主动调用 close 关闭连接时,TCP 协议会发送一个正常的连接关闭请求,告知本端关闭连接。当本端的 read 函数读取到这个关闭请求时,返回值为 0,表示对端已经关闭连接。

  2. 调用 read 函数返回值的含义:调用 read 函数后,返回值表示实际读取到的字节数。如果返回值为 0,表示对端已经关闭连接,没有数据可读取了。

  3. 处理对端关闭连接:当 read 函数返回 0 时,表示对端已经关闭连接,本端应当做相应的清理工作,如关闭本端的套接字,并释放资源。

代码

char buffer[1024];
int bytesRead = read(socket_fd, buffer, sizeof(buffer));
if (bytesRead == 0) {
    // 对端已关闭连接
    printf("对端已关闭连接\n");
    close(socket_fd);
    exit(0);
} else if (bytesRead < 0) {
    // 读取出错
    perror("读取出错");
    exit(1);
} else {
    // 处理读取到的数据
    printf("读取到 %d 字节数据\n", bytesRead);
    // ...
}

2.9.写一个while(1)的死循环,一直使用malloc申请空间,程序会崩溃吗?

        如果在一个 while(1) 的死循环中不断使用 malloc 来申请内存空间,程序最终会因为内存耗尽而崩溃。这种情况称为内存泄漏,即程序在动态分配内存后没有释放该内存,导致程序持续占用内存直至耗尽系统资源。

详细讲解:

  1. 内存泄漏原因:每次调用 malloc 函数分配内存后,如果没有调用 free 函数释放该内存,这块内存就会一直被程序占用,直到程序结束或系统资源耗尽。

  2. 死循环中的内存泄漏:在 while(1) 的死循环中不断调用 malloc 分配内存,但没有释放,会导致程序持续占用内存,最终导致内存耗尽。

  3. 程序崩溃:当系统内存耗尽时,操作系统无法满足程序对内存的需求,会导致程序崩溃。这种情况在不同操作系统下表现形式可能不同,例如 Windows 可能弹出内存不足的错误提示,而 Linux 下可能会直接导致程序崩溃。

代码

#include <stdlib.h>

int main() {
    while(1) {
        // 不断申请内存但不释放,导致内存泄漏
        int *ptr = (int *)malloc(sizeof(int));
        // 如果需要持续运行,应在适当的时候释放内存,如下所示
        // free(ptr);
    }
    return 0;
}

要避免内存泄漏,应该在动态分配内存后,在不需要使用该内存时调用 free 函数释放内存。

2.10.进程退出时,假设存在没有释放的资源,此时应该怎么做?

当一个进程退出时,如果存在没有释放的资源(如内存、文件描述符等),应该尽量避免资源泄漏,确保资源能够正确释放。

常见的处理方式:

1.显式释放资源:在进程退出之前,尽量显式释放所有未释放的资源,包括内存、文件描述符、网络连接等。例如,对于动态分配的内存,可以使用 free 函数释放;对于打开的文件描述符,可以使用 close 函数关闭文件。

2.注册退出处理函数:可以使用 atexit 函数注册一个退出处理函数,在进程退出时自动调用。在退出处理函数中可以释放资源。

3.利用操作系统的资源回收机制:在现代操作系统中,当一个进程退出时,操作系统会回收进程占用的所有资源,包括内存、文件描述符等。但是,依赖操作系统的资源回收机制并不是一个良好的实践,因为它可能导致资源泄漏或者资源释放的时机不确定。

4.检查内存泄漏:可以使用内存泄漏检测工具(如 Valgrind)来检查程序是否存在内存泄漏问题,及时修复。

代码:

#include <stdlib.h>

void cleanup() {
    // 释放资源的代码
}

int main() {
    // 注册退出处理函数
    atexit(cleanup);

    // 其他代码

    return 0;
}

2.11.你使用过这个项目和Google的TCmalloc项目做过对比吗?

2.12.项目中是怎么解决内碎片和外碎片问题的?

2.13.项目中如果用户忘记释放内存或多次释放内存,有没有做特殊处理?

总的来说,问的东西不是一些简单的概念,需要对目标足够熟悉才能回答上来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/511060.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java | Leetcode Java题解之第4题寻找两个正序数组的中位数

题目&#xff1a; 题解&#xff1a; class Solution {public double findMedianSortedArrays(int[] A, int[] B) {int m A.length;int n B.length;if (m > n) { return findMedianSortedArrays(B,A); // 保证 m < n}int iMin 0, iMax m;while (iMin < iMax) {int…

二维相位解包理论算法和软件【全文翻译-二维相位解缠的离散形式 (2.5)】

我们已经指出,二维相位解包相当于在覆盖相关领域的路径上对相位梯度进行积分。在实践中,我们当然必须处理采样数据。然而,为了做到这一点,我们必须定义离散域中的二维相位解包问题,并明确本书中将会用到的相关术语。 从最一般、限制最少的意义上讲,二维相位解包是一个不…

实验四 微信小程序智能手机互联网程序设计(微信程序方向)实验报告

请编写一个用户登录界面&#xff0c;提示输入用户名和密码进行登录&#xff1b; 代码 index.wxml <view class"user"> <form bindreset""> <view>用户名&#xff1a;</view><input type"text"name""/>…

mysql锁表问题

问题描述 偶尔应用日志会打印锁表超时回滚 org.springframework.dao.CannotAcquireLockException: ### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transactionmysql锁…

C刊级 | Matlab实现GWO-BiTCN-BiGRU-Attention灰狼算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测

C刊级 | Matlab实现GWO-BiTCN-BiGRU-Attention灰狼算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测 目录 C刊级 | Matlab实现GWO-BiTCN-BiGRU-Attention灰狼算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测效果一览基本介绍程序设计参考…

ArcGIS Pro打不开Excel?Microsoft驱动程序安装不上?

刚用ArcGIS pro的朋友们可能经常在打开xls或者xlsx文件的时候都会提示&#xff0c;未安装所需的Microsoft驱动程序。 怎么办呢&#xff1f;当然&#xff0c;按照提示装一下驱动就会好吗&#xff1f;有什么状况会出现&#xff1f;有什么临时替代方案呢&#xff1f; 全文目录&a…

C++的并发世界(二)——初识多线程

0.引言 C的并发世界&#xff08;零&#xff09;和C的并发世界&#xff08;一&#xff09;的东西真的对于我这种初学者难以理解&#xff0c;我确定从第一个多线程案例进行学习归纳总结。 1.多线程的目的 ①将耗时的任务进行分解&#xff0c;进行实时响应;   ②充分利用多核CP…

ICMP,ARP协议,免费ARP

ICMP:ping检测链路通断&#xff0c;到目的地的连通性。 internet网控制消息协议&#xff0c;工作在网络层。 ttl超时&#xff0c;也是icmp报文。

LeetCode刷题记(一):1~30题

1. 两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以…

直流电源电路(下)

直流电源电路&#xff08;下&#xff09; 综述&#xff1a;本篇文章讲述了直流电源电路的BOOST电路以及DC-DC电路的组成原理。 四、BOOST电路 原理&#xff1a;当mos导通时&#xff0c;电源上的电流给电感充电&#xff0c;通过mos管构成回路&#xff0c;电容放电给负载供电&…

从零实现一个Http服务器

HttpServer HTTPServer项目是一个基于C编写的简单的HTTP服务器实现&#xff0c;用于处理客户端的HTTP请求并提供相应的服务。该项目使用了Socket编程来实现服务器与客户端之间的通信&#xff0c;通过监听指定的端口并接受客户端连接&#xff0c;然后解析HTTP请求并生成对应的H…

Octavia Venture 成立,打造数十亿美元规模的 AI 价值体系

​随着 OpenAI 相继发布 ChatGPT、Sora 等 AIGC 大模型后&#xff0c;AI 赛道的发展迎来了一轮又一轮的热潮&#xff0c;这也让极具想象力的 AI 赛道涌入大量资金&#xff0c;比如英伟达股票市值短时间内从 1 万亿美元暴涨至 2 万亿美元&#xff0c;就是最好的佐证。当然&#…

Maven依赖管理项目构建工具

一、Maven简介 1、为什么学习Maven 1.1、Maven是一个依赖管理工具 ①jar 包的规模 随着我们使用越来越多的框架&#xff0c;或者框架封装程度越来越高&#xff0c;项目中使用的jar包也越来越多。项目中&#xff0c;一个模块里面用到上百个jar包是非常正常的。 比如下面的例…

表白墙项目(JAVA实现)

1、在html里 class使用. id使用# 2、记得引入响应依赖&#xff08;举例lombok&#xff09; 3、messageController package com.example.demo.demos.web; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; i…

惊喜!这一国产数据库认证考试限免了!

今年第一个季度过去了&#xff0c;又到春暖花开时&#xff0c;群里的小伙伴开始躁动不安&#xff0c;焦虑加倍。 有考虑被 cloud 淘汰的&#xff0c;有考虑被共享 emp 的&#xff0c;还有问粗粮 car 能不能当专车开的。 但技术人&#xff0c;更多时间还是在讨论正能量&#xff…

使用纯注解的方式管理bean对象

前置知识&#xff1a; Component , Repository , Controller , Service 这些注解只局限于自己编写的类&#xff0c;而Bean注解能把第三方库中的类实例加入IOC容器中并交给spring管理。 其中&#xff1a; Component一般用于公共类 Repository 用于dao数据访问层 Service 用…

基本电路理论入门讲解系列-电路和电路模型

&#x1f308;个人主页&#xff1a;会编程的果子君 &#x1f4ab;个人格言:“成为自己未来的主人~” 电路 电路概念&#xff1a;把若干个电气设备和电气元件按照一定的方式组合起来&#xff0c;构成电流的通路&#xff0c;此路径的总体称为电路。在电子通信&#xff0c;自…

Spring IoCDI(2)

IoC详解 通过上面的案例, 我们已经知道了IoC和DI的基本操作, 接下来我们来系统地学习Spring IoC和DI的操作. 前面我们提到的IoC控制反转, 就是将对象的控制权交给Spring的IoC容器, 由IoC容器创建及管理对象. (也就是Bean的存储). Bean的存储 我们之前只讲到了Component注解…

SpringBoot项目使用SpringSecurity和JWT实现登录功能

使用SpringSecurity,Redis实现登录功能 首先&#xff0c;思路如下&#xff1a; 登录 ①自定义登录接口 调用ProviderManager的方法进行认证 如果认证通过生成jwt 把用户信息存入redis中 ②自定义UserDetailsService 在这个实现类中去查询数据库 注意配置passwordEncoder为BCry…

数据结构进阶篇 之 【插入排序】详细讲解(直接插入排序,希尔排序)

千万不要因为一件事不会做而失去信心&#xff0c;你又不是只有这一件事不会&#xff0c;你还有很多呢 一、插入排序 1.直接插入排序 InsertSort 1.1 基本思想 1.2 实现原理 1.3 代码实现 1.4 直接插入排序的特性总结 2.希尔排序 ShellSort 2.1 基本思想 2.2 实现原理 …