嵌入式面经篇四——内存管理

news2024/11/14 1:25:44

文章目录

  • 前言
  • 一、内存管理&编程题
    • 1、由gcc编译的C语言程序占用的内存分为哪几个部分?
    • 2、大小端
    • 3、全局变量和局部变量的区别?
    • 4、以下程序中,主函数能否成功申请到内存空间?
    • 5、请问运行下面的 Test() 函数会有什么样的后果?
    • 6、 请问运行下面的 Test() 函数会有什么样的后果?
    • 7、请问运行下面的 Test() 函数会有什么样的后果?
    • 8、在C语言中 memcpy 和 memmove 是一样的吗?
    • 9、malloc 的底层是如何实现的?
    • 10、在1G内存的计算机中能否通过malloc申请大于1G的内存?为什么?
    • 11、内存泄漏是什么?
    • 12、内存溢出是什么?与内存泄漏有何关系?
    • 13、堆栈溢出一般是由什么原因导致的?
    • 14、编译和链接有什么不同?(如对外部符号的处理)
    • 15、一个32位的指针,如何按8字节的整数倍向下对齐,请写出代码。
    • 16、gcc 优化代码执行速度的编译选项是?
    • 17、new 和 malloc 有什么区别?
    • 18、指针与引用的区别?


前言

记录一些招聘公司在招聘嵌入式软件岗位时的一些问题,此文为第四篇。


一、内存管理&编程题

1、由gcc编译的C语言程序占用的内存分为哪几个部分?

在这里插入图片描述

2、大小端

小端:一个数据的低位字节数据存储在低地址
大端:一个数据的高位字节数据存储在低地址

例如:int a=0x12345678; //a首地址为0x200,大端存储格式如下:

数据0x120x340x560x78
地址0x2000x2010x2020x203

如何判读一个系统的大小端存储模式?

  • 方法一:int * 强制类型转换为 char *,用 “[]” 解引用
    void checkCpuMode(void)  
    {  
        int c = 0x12345678;  
        char *p = (char *)&c;  
        if(p[0] == 0x12)  
            printf("Big endian.\n");  
        else if(p[0] == 0x78)  
            printf("Little endian.\n");  
        else  
            printf("Uncertain.\n");  
    } 
    
  • 方法二:int *强制类型转换为char ,用“”解引用
    void checkCpuMode(void)  
    {  
        int c = 0x12345678;  
        char *p = (char *)&c;  
        if(*p == 0x12)  
            printf("Big endian.\n");  
        else if(*p == 0x78)  
            printf("Little endian.\n");  
        else  
            printf("Uncertain.\n");  
    } 
    
  • 方法三:包含 short 跟 char 的共用体
    void checkCpuMode(void)  
    {  
        union Data  
        {  
            short a;  
            char b[sizeof(short)];  
        }data;  
        data.a = 0x1234;  
      
        if(data.b[0] == 0x12)  
            printf("Big endian.\n");  
        else if(data.b[0] == 0x34)  
            printf("Little endian.\n");  
        else  
            printf("uncertain.\n");  
    } 
    

3、全局变量和局部变量的区别?

  • 全局变量储存在静态区,进入 main 函数之前就被创建,生命周期为整个源程序。
  • 局部变量在栈中分配,在函数被调用时才被创建,在函数退出时销毁,生命周期为函数内。

4、以下程序中,主函数能否成功申请到内存空间?

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
void getmemory(char *p)  
{  
    p = (char *)malloc(100);  
    strcpy(p, "hello world");  
}  
int main()  
{  
    char *str = NULL;  
    getmemory(str);  
    printf("%s\n", str);  
    free(str);  
    return 0;  
} 

答:不能。
解读:getmemory(str) 没能改变 str 的值,因为传递给子函数的只是 str 的复制值 NULL,main 函数中的 str 一直都是 NULL。正确的 getmemory() 如下:

①传递的是二重指针,即str的指针
void getmemory(char **p)   
{  
    *p = (char *)malloc(100);  
    strcpy(*p, "hello world");  
}  
②传递的是指针别名,即str的别名,C++void getmemory(char * &p)   
{  
    p = (char *)malloc(100);  
    strcpy(p, "hello world");  
}  

5、请问运行下面的 Test() 函数会有什么样的后果?

void GetMemory(char **p, int num)  
{  
    *p = (char *)malloc(num);  
}  
void Test(void)  
{  
    char *str = NULL;  
    GetMemory(&str, 100);  
    strcpy(str, "hello");   
    printf("%s\n", str);   
}  

答:内存泄漏。
解读:调用 malloc() 申请内存空间,使用完毕之后没有调用 free() 释放内存空间并使指针指向 NULL。

6、 请问运行下面的 Test() 函数会有什么样的后果?

char *GetMemory(void)  
{   
    char p[] = "hello world";  
    return p;  
}  
void Test(void)  
{  
    char *str = NULL;  
    str = GetMemory();   
    printf("%s\n", str);  
}  

答:打印野指针内容,可能是乱码。
解读:GetMemory() 返回的是指向栈内存的指针,但该栈内存已被释放,该指针的地址不是 NULL,成为野指针,新内容不可知。

7、请问运行下面的 Test() 函数会有什么样的后果?

void Test(void)  
{  
    char *str = (char *) malloc(100);  
    strcpy(str,"hello");  
    free(str);       
    if(str != NULL)  
    {  
        strcpy(str, "world");   
        printf("%s\n", str);  
    }  
}  

答:篡改堆区野指针指向的内容,后果难以预料,非常危险。
解读:

  • free(str); 之后,str 成为野指针,没有置为 NULL,if(str != NULL) 语句不能阻止篡改操作。
  • 野指针不是 NULL指针,是指向被释放的或者访问受限的内存的指针。
  • 造成野指针原因:①指针变量没有被初始化,任何刚创建的指针不会自动成为NULL;②指针被free或delete之后,没有置NULL;③指针操作超越了变量的作用范围,比如要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。

8、在C语言中 memcpy 和 memmove 是一样的吗?

答:

  • memcpy() 与 memmove() 一样都是用来拷贝 src 所指向内存内容前 n 个字节到 dest 所指的地址上。
  • 不同的是,当 src 和 dest 所指的内存区域重叠时,memcpy 可能无法正确处理,而 memmove() 仍然可以正确处理,不过执行效率上略慢些。

解读:

  • memcpy() 无论什么情况下,都是从前往后拷贝内存。当源地址在前,目的地址在后,且两个区域有重叠时,会造成拷贝错误,达不到理想中的效果。
void *memcpy(void *dest, const void *src, size_t count)  
{  
    if(dest == NULL || src == NULL || count <= 0)  return NULL;  
    char *d = (char *)dest;  
    char *s = (char *)src;  
    while(count--)  
    {  
        *d++ = *s++;  
    }  
    return dest;  
}  
  • memmove() 则分两种情况:目的地址在前,源地址在后的情况下,从前往后拷贝内容。否则从后往前拷贝内容。无论什么情况都能达到理想中的效果。
void *memmove(void *dest, const void *src, size_t count)  
{  
    if(dest == NULL || src == NULL || count <= 0)  return NULL;  
    if(dest < src)  
    {  
        char *d = (char *)dest;  
        char *s = (char *)src;  
        while (count--)  
        {  
            *d++ = *s++;  
        }  
    }  
    else  
    {  
        char *d = (char *)dest + count;  
        char *s = (char *)src + count;  
        while (count--)  
        {  
            *--d = *--s;  
        }  
    }      
    return dest;  
}  

9、malloc 的底层是如何实现的?

  • malloc 函数的底层实现是操作系统有一个由可用内存块连接成的空闲链表。调用 malloc 时,它将遍历该链表寻找足够大的内存空间,将该块一分为二(一块与用户申请的大小相等,另一块为剩下来的碎片,会返回链表),调用 free 函数时,内存块重新连接回链表。
  • 若内存块过于琐碎无法满足用户需求,则操作系统会合并相邻的内存块。

10、在1G内存的计算机中能否通过malloc申请大于1G的内存?为什么?

答:可以。因为 malloc 函数是在程序的虚拟地址空间申请的内存,与物理内存没有直接的关系。虚拟地址与物理地址之间的映射是由操作系统完成的,操作系统可通过虚拟内存技术扩大内存。

11、内存泄漏是什么?

  • 内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
  • 分类
    • 常发性内存泄漏:发生泄漏的代码会被多次执行到。
    • 偶发性内存泄漏:发生泄漏的代码在某些环境或操作下才会发生。
    • 一次性内存泄漏:只会被执行一次。
    • 隐式内存泄漏:程序在运行过程中不停地分配内存,直到结束时才释放。严格来讲这不算内存泄漏,但服务器运行时间很长,可能会耗尽所有内存。

12、内存溢出是什么?与内存泄漏有何关系?

  • 内存溢出(Out Of Memory)是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于系统能提供的最大内存。此时程序无法运行,系统提示内存溢出。有时候会自动关闭软件。
  • 造成内存溢出的原因:
    • 内存泄漏的堆积最终导致内存溢出。
    • 需要保存多个耗用内存过大的对象或加载单个超大的对象时,其大小超过了当前剩余的可用内存空间。

13、堆栈溢出一般是由什么原因导致的?

  • 堆栈溢出一般包括堆内存溢出和栈内存溢出,两者都属于缓冲区溢出。
  • 堆内存溢出可能是堆的尺寸设置得过小/动态申请的内存没有释放。

14、编译和链接有什么不同?(如对外部符号的处理)

  • 编译(+汇编)生成的是目标文件(*.o)。编译过程中对于外部符号(如用extern跨文件引用的全局变量)不做任何解释和处理,外部符号对应的就是“符号”。
  • 链接生成的是可执行程序。链接将会解释和处理外部符号,外部符号对应的是地址。

15、一个32位的指针,如何按8字节的整数倍向下对齐,请写出代码。

答:设该指针为p,则代码为:

p &= ~(8 -1); 
  • 在存储的时候,为了提高效率,一般都会让地址偏移量落在2的m次方的位置上,而且经常有向上取整和向下取整两种需求。
  • 向下取整:
    #define  PALIGN_DOWN(x, align)  ((x) & ~((align) -1))  
    
  • 向上取整:
    #define  PALIGN_UP(x, align)  ((x) + ((align) - 1)) & ~((align) - 1)  
    

16、gcc 优化代码执行速度的编译选项是?

在这里插入图片描述

17、new 和 malloc 有什么区别?

  • new 与 delete 是 C++ 的操作符;而 malloc 与 free 是 C/C++ 的标准库函数。
  • C++ 允许重载 new/delete 操作符;而不允许重载 malloc/free。
  • new 返回的是对象类型的指针,严格与对象匹配;而 malloc 返回的是 void* 类型的指针,需要进行强制类型转换。
  • new 可以自动计算所申请内存的大小;而 malloc 需要显式指出所需内存的大小。
  • new 操作符从自由存储区上动态分配内存;而 malloc 函数从堆上动态分配内存。
  • new 内存分配失败会抛出 bac_alloc 异常;malloc 内存分配失败会返回 NULL。
  • new/delete 会调用对象的构造函数/析构函数,以完成对象的构造/析构;而 malloc 不会。

18、指针与引用的区别?

  • 指针是变量,存储的是地址;而引用跟原变量是同一个东西,是原变量的别名。
  • 指针有 const;而引用没有。
  • 指针的值可以为 NULL;而引用不行。
  • 非 const 指针可以改变;引用只能在定义时被初始化,之后不可改变。
  • 指针可以有多级,如二重指针;而引用只能有一级。
  • 指针和引用自增(++)的意义不一样,指针自增是地址增加,引用自增是原变量增加。
  • sizeof指针和引用得到的大小不一样,sizeof(指针)得到的是指针本身的大小,sizeof(引用)得到的是原变量的大小。

我的qq:2442391036,欢迎交流!


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Anaconda安装jupyter notebook、jupyterlab及体验

Anaconda安装jupyter 1.前言2.创建虚拟环境3.激活虚拟环境4.安装jupyter notebook5.启动6.快捷方式7.jupyterlab插件安装8.报错的处理9.总结1.前言 手贱,不小心将Anaconda自带得jupyter给卸载了,没法子了查了好多资料都比较麻烦,所以自己摸索着重新安装,记录一下心得。 说…

87.SAP Transaction SM31 and SM30

目录 1.SM30是什么 2.SM30维护表的前提条件&#xff1a; 3.用途 维护表数据 查看SAP表的配置点 4.SM31和SM30的区别 1.SM30是什么 Transaction code SM30 can be used to display and update table data. The input field on the first screen of SM30 is long enough t…

企业通用报表平台代码审计

1 第三方组件漏洞审计 本项目是基于Maven构建的。对于Maven项目,我们首先从 pom.xml 文件开始审计引入的第三方组件是 否存在漏洞版本,然后进一步验证该组件是否存在漏洞点。 本项目引入的组件以及组件版本整理如下。 组件名称组件版本SpringBoot2.2.4.RELEASEFastjson1.2…

CDP问卷填报手册指南

CDP认证的作用是向消费者和利益相关者提供一个可信的证明&#xff0c;证明该组织正在采取行动&#xff0c;以减少其对气候变化的影响并提高可持续发展。CDP认证是一个独立的评估过程&#xff0c;通过评估组织在应对气候变化和可持续发展方面的表现和策略&#xff0c;评估其对气…

免费下载专利

给大家提供一个可以免费下载专利的地方 链接&#xff1a;https://www.drugfuture.com/cnpat/cn_patent.asp

玩转生产环境全链路压测

一、什么是生产环境全链路压测 生产环境全链路压力测试&#xff08;Production Environment Full-Link Stress Testing&#xff09;是一种针对线上系统进行的综合性性能测试方法。这个过程涉及模拟实际用户行为&#xff0c;从用户界面到后端数据库的整个应用链路上施加预定的高…

考拉悠然完成自研国内首台玻璃基Micro LED晶圆量检测设备出货

近日&#xff0c;考拉悠然自主研发的国内首台玻璃基Micro LED晶圆量检测设备正式完成出货&#xff0c;这不仅标志着考拉悠然在Micro LED核心检测技术上的重大突破&#xff0c;也展现了公司在高端制造领域的技术创新能力。 Micro LED显示技术被认为是未来的“终极显示技术”&am…

stm32—GPIO

0. 引入 在单片机产品中,我们常常可以见到三种模块:LCD灯、KEY按键、BEEP蜂鸣器 LED灯: 一个比较常见的LED电路LED0 ---------- 通过控制LED0引脚(电线) 给它一个低电平(低电压),LED灯就会亮 给它一个高电平(高电压),LED灯就会灭 …

Spring——AOP前言(写一个小demo为了好学习AOP)

1.AOP的概念 1.1 AOP简单样例 我们来先通过一个例子来对AOP进行理解&#xff0c;这个例子就是有关Spring的事务的一个样例&#xff0c;有关Spring是怎么实现事务的&#xff0c;这个事务其实本质上就是对于我们代码的一个增强。废话不多说&#xff0c;上程序&#xff0c;请各位…

【Datawhale AI夏令营第四期】魔搭-AIGC方向 Task02笔记 Scepter工具箱, 精读BaseLine代码

【Datawhale AI夏令营第四期】魔搭-AIGC方向 Task02笔记 Task02学习任务&#xff1a; https://linklearner.com/activity/14/10/32 传送门 我们继续看网课&#xff0c;并且在Kimi.AI的帮助下读一下BaseLine示例代码。 网课链接&#xff1a;https://space.bilibili.com/1069874…

如何创建一个SpringBoot项目呢?SpringBoot有什么优点呢?

目录 一、SpringBoot的优点 二、SpringBoot项目的创建 &#xff08;一&#xff09;通过Idea创建 &#xff08;二&#xff09;通过网页来创建Spring Boot项目 三、SpringBoot的目录 拓展知识 Spring的诞生是为了简化Java代码的开发&#xff0c;而Spring Boot的诞生是为了简…

剪映怎么剪辑视频?2024年剪辑软件精选!

在短视频风靡的时代&#xff0c;越来越多的人开始尝试自己制作短视频。而剪辑视频是短视频制作过程中至关重要的一环。很多小伙伴问剪映怎么剪辑视频&#xff1f;其实除了剪映&#xff0c;市面上还有不少剪辑软件操作简便&#xff0c;值得推荐&#xff01; 福昕视频剪辑 链接…

Dubbo源码深度解析(四)

接上篇博客《Dubbo源码深度解析(三)》&#xff0c;上篇博文&#xff0c;主要讲的是DubboBootstrap#start()方法中调用到的其他方法&#xff0c;以及讲到ServiceConfig#export()方法的调用链路。其中讲到最核心的方法为ServiceConfig#doExportUrlsFor1Protocol()&#xff0c;还没…

LVS详细解析及其NAT模式与DR模式部署(理论+实验全方位指导)

目录 1. 集群 2. 分布式系统 3. 集群与分布式的比较 4.通俗的解释 集群 分布式系统 总结 LVS&#xff08;Linux Virtual Server&#xff09;简介 LVS专业术语 工作原理 LVS调度算法 静态调度算法 动态调度算法 ipvsadm脑图 NAT模式集群 LVS的配置 在LVS主机内打开…

数据结构之顺序表的实现

主要参考&#xff1a; 【王道考研】王道数据结构与算法详细笔记&#xff08;全&#xff09;_王道数据结构笔记-CSDN博客 顺序表的概念 顺序表&#xff1a;用顺序存储的方式实现线性表顺序存储。把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中&#xff0c;元素之间的关系…

1Panel配置

1. 脚本安装 curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sh quick_start.sh2. 配置镜像加速 在容器-> 配置中设置&#xff0c;否则安装软件会失败。 https://docker.211678.top https://docker.1panel.live …

面对复杂订单统计,如何用这款工具化整为零?

最近制作报表时遇到了个问题&#xff0c;怎么把整合到一起的订单统计数据拆分成一个个单独的订单统计报表呢&#xff1f;经过一段时间的探索后&#xff0c;我找到了一款完全免费的报表软件&#xff0c;能够解决这个问题&#xff0c;这款软件叫作山海鲸可视化&#xff0c;我会在…

python 已知x+y=8 求x*y*(x-y)的最大值

先用导数求解 已知xy8 求xy(x-y)的最大值 令y8-x 则 f(x)x⋅(8−x)⋅(x−(8−x))x⋅(8−x)⋅(2x−8) 导数方程为 f(x)-3x^2 24x - 32 求方程 − 3 x 2 24 x − 32 0 -3x^2 24x - 32 0 −3x224x−320 的根。 首先&#xff0c;我们可以尝试对方程进行因式分解。观察…

Maven系列(一):Maven下载安装配置【Maven使Java构建事半功倍】

前言 ​ 作为Java开发工程师&#xff0c;那么Maven现已成为不可或缺的一部分&#xff0c;从最开始的依赖管理到编译运行及打包&#xff0c;可以说使伴随了Java项目的整个生命周期。那么这篇文章&#xff0c;将带你去认识Maven以及Maven的下载、安装、配置等等。 1. 什么是Mav…

RCE复现问题和研究

目录 先了解一些常见的知识点 PHP常见命令执行函数 call_user_func eval&#xff08;&#xff09; call_user_func_array array_filter 实战演练&#xff08;RCE&#xff09;PHP Eval函数参数限制在16个字符的情况下 &#xff0c;如何拿到Webshell&#xff1f; 1、长度…