经过刷其他人的面经和回顾自己的面试经历,在面试中C/C++常问问题总结如下:
C程序的存储空间布局
一个编译链接之后生成的可执行程序,在存储时分为代码段(text)、数据段(data)、未初始化数据段(BSS)
- text段:存放程序的执行代码和一些常量,该存储区域是只读的
- data段:存放程序中已初始化的全局变量,静态内存分配
- BSS段:存放程序中未初始化的全局变量,静态内存分配
需要注意的是BSS段只记录大小并不分配空间,加载进内存执行时才根据记录的大小分配空间并清0
程序运行之后就多了三个内存区域:堆区、栈区和存储命令行参数、环境变量的区域
- 栈区:存放局部变量和函数参数,由编译器释放内存,无需手动释放。内存由高地址向低地址增长,内存大小由系统提前设定好,容易爆栈。栈的内存分配有两种:静态分配是编译器完成的,比如局部变量的分配。动态分配由函数alloca进行分配
- 堆区:堆内存都需要动态分配,并且需要手动释放。堆内存由低地址向高地址增长,采用链式存储结构,每次分配的内存块不一定是连续的,所以按照一定的算法搜索可用的足够大的空间,所以效率比栈低
因此,C程序空间布局如下图所示:
malloc和free原理
malloc()和free()原型
#include <stdlib.h>
void* malloc(size_t size);
void free(void *ptr);
原理说明
https://www.cnblogs.com/zpcoding/p/10808969.html,很详细
为什么free()不需要指定内存块大小
因为使用malloc分配内存之后会记录下分配的大小,释放的时候就知道要释放多大的内存
动态编译链接和静态编译链接
区别在于编译时对库文件的处理
- 动态编链是指不将库文件链接进最后的可执行文件当中,可执行文件需要调用动态链接库(linux中是.so文件)才能正常运行,优点:编译快,可执行文件小,缺点:运行时需附带链接库静态编链
- 静态编链则是在编译链接时将库文件链接进可执行文件,这样单独的可执行文件即可运行,缺点:不够灵活
volatile关键字
首先要明确编译器的一种优化:程序在执行期间,如果两次读取一个变量中间没有对该变量做修改的话,则优先从寄存器中读取该变量的值,而不是内存。volatile关键字就是用来告诉编译器不对该关键字修饰的变量做优化,也就是该变量的值总是要读取内存获取
实现memcpy
void* Memcpy(void *dst, const void *src, size_t len){
if(!dst || !src || !len) return NULL;
auto pdst = (char*)dst, psrc = (char*)src;
if(dst >= src && (char*)dst - (char*)src < len){
pdst += len - 1;
psrc += len - 1;
while(len){
*pdst = *psrc;
-- pdst;
-- psrc;
-- len;
}
}
else{
while(len){
*pdst = *psrc;
++ pdst;
++ psrc;
-- len;
}
}
}
C和C++区别
最主要的区别就是C是面向过程的,C++在C的基础上增加了类,既可以面向过程也可以面向对象还有一些细节上的不同:
- C++支持模板编程,C不支持
- C++支持函数重载,C不支持
- 异常处理的方式不同
- 动态内存管理的方式不同
- …
指针和引用的区别
- 指针时一个变量,可以用来存储变量的地址,引用只是一个变量的别名,必须依附其他变量存在,内部实现是只读指针
- 指针在定义是可以不用初始化,但引用必须要初始化
- 没有空引用有空指针
- sizeof(引用)返回的是变量的大小,而sizeof(指针)返回的是指针变量的大小,在32位系统上占4字节,64位系统上占8字节
const用法
- 定义只读变量,即常量