文章目录
- 前言
- 1.内存泄露和野指针出现的可能原因?
- 2.C语言自动转换原则
- 3.介绍一下堆栈
- 4.c语言中什么是内联函数,它有什么特点?
- 5.c语言中动态库和静态库有什么区别?
- 6.什么是交叉编译,为什么需要交叉编译
- 7.阐述一下C的编译过程
- 8.void *malloc( size_t size );其中void *表示什么
- 9.C语言中变量声明有哪些?它们又有什么区别?
- 10.define和const声明的常量有什么区别?
- 11.strlen()和sizeof()的区别
- 12.memcpy()和strcpy()的区别是什么?
- 13.全局变量与局部变量在内存中的区别?
- 14.C语言是如何进行存储管理的
- 15.static的作用
- 16.register关键字的作用
- 17.inline关键词的作用
- 18.C语言头文件是否可以定义一个变量?
- 19.define和typedef的区别
- 20.define的用处
- 21.define的缺点
- 22.include <file.h> 和 #include "file.h"的区别
- 23.堆栈溢出的情况有哪些?
- 24.if判断语句笔试题
- 25.交换两个变量的值,不使用第三个变量
- 26.数组指针和指针数组的区别
- 27.数组指针中a+1和&a+1的区别
- 28.调用free(ptr)对指针进行释放就可以了吗?
- 29.C语言预编译三大功能
- 30.不同数据类型值域范围
- 31.动态库和静态库有什么区别
- 32.*++p 和 *p++有什么区别?
前言
前言:
本文章由俺三年电赛队友兼队长撰写,源文章:蓝牙模块HC05主从配置与连接
队友博客:一个牛逼哄哄的嵌入式软件大佬,长期更新嵌入式软件开发干货
1.内存泄露和野指针出现的可能原因?
内存泄露:
1.未正确使用free函数:在动态分配内存后,如果忘记调用free函数来释放内存,会导致内存泄露。
2.误用指针:将指针指向新的内存块后,如果没有释放之前分配的内存,会导致内存泄露。
3.指针丢失:如果保存了某个指针的地址,但后续无法再找到这个指针来释放内存,也会导致内存泄露。
野指针
1.指针未初始化:声明指针变量但没有初始化,会导致指针指向未知的地址。
2.指针指向已释放的内存:如果指针指向的内存被释放后,没有将指针置为NULL,会导致野指针。
3.函数返回局部变量的地址:如果将函数内部的局部变量地址返回,但该局部变量已经被销毁,会导致野指针
2.C语言自动转换原则
当表达式中存在有符号类型和无符号类型时所有的数都自动转换为无符号类型。
3.介绍一下堆栈
存储内容不同
栈:在函数调用时,栈中存放的是函数中各个参数(局部变量)。栈底下是函数调用后的下一条指令。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。
管理方式上不同
栈:由系统自动分配空间,同时系统自动释放空间。例如,声明在函数中一个局部变量“int b“。系统自动在栈中为b开辟空间,当对应的生存周期结束后栈空间自动释放。
堆:需要程序员手动申请并且手动释放,并指明大小。在C语言中malloc函数申请,释放free函数,在C++中new和delete实现。
空间大小不同
栈:获取空间较小。在Windows下,一般大小是1M或2M,当剩余栈空间不足时,分配失败overflow。
堆:获得空间根据系统的有效虚拟内存有关,比较灵活,比较大。
能否产生碎片不同
栈:不会产生碎片,空间连续。
堆:采用的是链表的存储方式,会产生碎片。
生长方向不同
栈:向低地址扩展的数据结构,是一块连续的内存的区域。
堆:向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。
分配方式不同
栈:有2种分配方式——静态分配和动态分配。静态由编译器完成,例如局部变量;动态由alloca函数实现,并且编译器会进行释放。
堆:都是动态分配的,没有静态分配的堆。
分配效率不同
栈:由系统自动分配,速度较快。但程序员是无法控制的。
堆:由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来方便。
总的来说就是栈存储的数据又系统决定,堆就比较随意。栈时由系统自动分配释放,堆是由开发人员进行分配释放。栈的可获取空间较小,堆可获取的大小较大,但堆的分配效率较低。由于栈先入后出的特性,使得它不会出现内存碎片。
4.c语言中什么是内联函数,它有什么特点?
在C语言中,内联函数是指将函数的代码直接嵌入到调用该函数的地方,以避免函数调用的开销。这种优化方法被称为“内联扩展”。内联函数的特点包括:
- 提高程序的执行效率:由于内联函数的代码被直接嵌入到调用它的地方,避免了函数调用的开销,因此在一些需要频繁调用的函数中使用内联可以提高程序的执行效率。
- 减少函数调用的开销:内联函数的代码被直接嵌入到调用它的地方,因此不需要进行参数传递和返回值处理,减少了函数调用的开销。
- 编译器自动优化:内联函数的使用是由编译器自动优化的,编译器会根据函数的调用次数、函数体的大小等因素来决定是否使用内联扩展。
- 可能出现空间和时间上的开销:内联函数的代码被直接嵌入到调用它的地方,因此可能会出现代码膨胀的情况,增加了程序的空间开销。同时,由于内联函数的代码被直接嵌入到调用它的地方,也可能会增加程序的执行时间。
需要注意的是,内联函数并不是在所有情况下都是最优的选择,具体是否使用内联函数需要根据实际情况进行权衡。
5.c语言中动态库和静态库有什么区别?
在C语言中,动态库和静态库是两种不同的库文件,它们的主要区别在于编译时和运行时的处理方式不同。
静态库(Static Library)是一种在编译时链接的库文件,它包含了一组预编译的目标文件(通常是.o或.obj文件)。在编译时,静态库会被链接到可执行文件中,并成为可执行文件的一部分。因此,静态库在运行时不再需要额外的库文件支持。静态库的主要优点是编译后的可执行文件可以独立运行,不再依赖外部库文件。但是,静态库的缺点是会增加可执行文件的大小,并且如果静态库更新,需要重新编译链接所有使用了该库的可执行文件。
动态库(Dynamic Library)是一种在运行时链接的库文件,它包含了一组可重用的代码和数据。在编译时,动态库并不会被链接到可执行文件中,而是在运行时由操作系统动态加载到内存中。因此,动态库在运行时需要额外的库文件支持。动态库的主要优点是可以减少可执行文件的大小,并且如果多个程序使用了同一个动态库,它们可以共享该库的代码和数据。但是,动态库的缺点是需要额外的运行时开销,并且如果动态库更新,需要重新部署所有使用了该库的程序。
6.什么是交叉编译,为什么需要交叉编译
交叉编译是指在一个平台上生成另一个平台上的可执行代码。简单来说,就是将源代码编译成适应不同体系结构或操作系统的目标代码。对应的还有本地编译,本地编译就是在编译平台下编译的代码只能在本平台进行运行。交叉编译是为了适应不同平台主频、内存等等之间的差异而产生的。
交叉编译的出现主要是为了满足特定需求,例如在嵌入式系统开发中,目标系统可能内存较小、显示设备简陋甚至没有,无法在其上进行本地编译,或者编译所需的编译器无法在目标系统上运行。另外,如果目标平台的CPU架构或操作系统与源平台不同,也需要进行交叉编译。
要进行交叉编译,我们需要在主机平台上安装对应的交叉编译工具链(cross compilation tool chain),然后用这个交叉编译工具链编译源代码,最终生成可在目标平台上运行的代码。
7.阐述一下C的编译过程
1)预处理:宏定义展开(#define)、头文件展开(#include)、条件编译(#ifdef #ifndef #endif)等,同时将代码中的注释删除,这里并不会检查语法
2)编译:检查语法,将预处理后文件编译生成汇编文件
3)汇编:将汇编文件生成目标文件(二进制文件)
4)链接:C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去
.c转.i .i转.s .s转.o .o转可执行文件,这个可执行文件在windows中通常是.exe
8.void *malloc( size_t size );其中void *表示什么
表示返回指向 void 的指针,可以转换为任何数据类型
9.C语言中变量声明有哪些?它们又有什么区别?
在C语言中,变量声明的方式主要有以下几种:
- 1.静态变量声明:使用static关键字声明的变量为静态变量。静态变量在程序运行期间一直存在,其生命周期为整个程序运行期间。静态变量在编译时被分配内存,并在程序运行期间一直存在,直到程序结束才被释放。静态变量在函数调用时也可以保持其值。
- 2.全局变量声明:在函数外部声明的变量为全局变量。全局变量在程序运行期间一直存在,其生命周期为整个程序运行期间。全局变量在编译时被分配内存,并在程序运行期间一直存在,直到程序结束才被释放。全局变量在函数调用时也可以保持其值。
- 3.局部变量声明:在函数内部

本文围绕C语言面试常见问题展开,涵盖内存泄露、野指针、自动转换原则、堆栈、内联函数、动态库与静态库区别等内容。详细分析各问题产生原因、特点及区别,如内存泄露可能因未正确使用free函数等,为嵌入式开发面试者提供参考。
最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



