文章目录
C++ 编译四个过程:预处理、编译、汇编、链接
一、预处理,宏
- ifndef ifdef endif 分别是什么?什么作用?
这些都是预处理命令,预处理命令不是C++语言的组成部分,是在编译之间执行的。
C++提供三种预处理功能:宏定义、文件包含、条件编译。上面三个是条件编译的命令。
// 如果所指定的标识符已经被 #define 定义过,则只编译程序段1,否则编译程序段2. #endif 用来限制 #ifdef 命令范围
#ifdef 标识符
程序段1
#else
程序段2
#endif
// n代表not,作用与上述逻辑相反
#ifndef 标识符
程序段1
#else
程序段2
#endif
内联函数和宏定义的区别
- 内联函数在编译时展开,而宏在预编译时展开
- 在编译的时候,内联函数直接被嵌入到目标代码中去,而宏只是一个简单的文本替换。
- 内联函数可以进行诸如类型安全检查、语句是否正确等编译功能,宏不具有这样的功能。
- 宏不是函数,而inline是函数
- 宏在定义时要小心处理宏参数,一般用括号括起来,否则容易出现二义性。而内联函数不会出现二义性。
inline函数一般用于比较小的,频繁调用的函数,这样可以减少函数调用带来的开销。只需要在函数返回类型前加上关键字inline,即可将函数指定为inline函数。
inline有点类似于宏定义,但是它和宏定义不同的是,宏定义只是简单的文本替换,是在预编译阶段进行的。而inline的引入正是为了取消这种复杂的宏定义的。
同其它函数不同的是,最好将inline函数定义在头文件,而不仅仅是声明,因为编译器在处理inline函数时,需要在调用点内联展开该函数,所以仅需要函数声明是不够的。
https://blog.csdn.net/u013321328/article/details/19838145
二、const, constexpr, static
- const关键字的作用?const和constexpr区别?const和static区别?
const(constant):告诉编译器约束某个值不改变。在 C++ 中用来修饰内置类型变量,自定义对象,成员函数,返回值,函数参数。
被const修饰的变量变成常量,不能被再次赋值。不允许被修改。如果取它的地址再重新赋值,可能会发生意想不到的行为。在其前面再加 volatile,可以让编译器忽略 const的修饰。
// 举例:const修饰函数形参:https://blog.csdn.net/qxqxqzzz/article/details/127342899
函数参数为结构体时:地址传递减少内存(比如结构体有多个属性或成员),同时使用const修饰结构体指针形参防止误操作修改结构体属性
// void printS(student s) { // 值传递会拷贝数据占用内存
void printS(const student* s) {
// 地址传递
// s->name = 'aa' // 错误:不允许修改
}
void main {
// printS(s); // 值传递
printS(&s); // 地址传递,如果函数形参不加const会导致外面main函数中结构体s的属性也被修改!!
}
constexpr: 使指定的常量表达式获得在程序编译阶段计算出结果的能力,而不必等到程序运行阶段。 C++ 11 标准中,constexpr 可用于修饰普通变量、函数(包括模板函数)以及类的构造函数。
const,只读的全局变量,其值不可修改.
static,规定此全局变量只在当前模块(文件)中可见.
static const,既是只读的,又是只在当前模块中可见的.
// 修饰变量
const int a = 7;
// 撤销修饰
volatile const int a = 7;
// 修饰指针
const int *p = 7; // 常量指针:修饰指针指向的内容:指针指向的内容为不变量
int* const p = 7; // 指针常量:修饰指针地址:指针p指向的内存地址不变,内容可变
const int* const p = 7; // const既修饰指针又修饰常量:内容和地址都不可变
常量指针,const修饰的是取*操作,所以指针指向的值不可以改,指向可以改;
指针常量,const修饰的是常量(地址),所以指针指向不可以修改,指向的值可以改
- const定义成员函数有什么作用?
const int& fun(int& a); //修饰返回值
int& fun(const int& a); //修饰形参
int& fun(int& a) const{
} //const成员函数.const 修饰成员函数, 根本上是修饰了 this 指针。
// 任何不会修改数据成员的函数都应该声明为const 类型。如果在编写const 成员函数时,不慎修改了数据成员,或者调用了其它非const 成员函数,编译器将指出错误,这无疑会提高程序的健壮性。
https://blog.csdn.net/lz20120808/article/details/46662569
https://zhuanlan.zhihu.com/p/110159656
三、vector
- 传递vector作为函数参数的时候,什么时候使用引用、什么时候使用指针?传引用的时候也可以对值进行改变,如何避免?
- C++ Vector如何扩容?如何增加元素,有哪些方法?如何删除元素,有哪些方法?同时删除多个位置的元素有什么问题?扩容是在原地操作吗?
- vector的容量限制?在增加元素的时候,内存是如何变化的?
在调用push_back时,若当前容量已经不能够放入心得元素(capacity=size),那么vector会重新申请一块内存,把之前的内存里的元素拷贝到新的内存当中,然后把push_back的元素拷贝到新的内存中,最后要析构原有的vector并释放原有的内存
- C++数组如果不单调(但是单调性最多改变一次),怎么快速找到最大和最小值?如何遍历?如何减少时间复杂度?空间复杂度是多少?
https://www.bilibili.com/video/BV1zG4y1h71H
vector和list的区别:
1)vector(顺序表-直接存储): 连续存储,动态数组,在堆上分配空间;底层实现:数组;顺序内存
- 两倍容量增长:插入新元素时,如未超过容量,则直接添加到最后,然后调整迭代器;如没有剩余空间,则重新分配原有元素个数两倍空间,然后将原空间元素复制到新空间,进行初始化,再向新空间添加新元素。最后析构释放原空间,之前迭代器失效
- 访问:O(1),插入/删除:空间够的情况下在最后插入/删除 很快,在中间插入/删除都需要内存拷贝;空间不够的情况下在中间/最后 插入 都需要内存申请和释放,并拷贝之前数据;
- 适用于:经常随机访问,不经常对尾节点进行插入/删除
2)list(顺序表-链式存储): 动态链表,在堆上分配空间,每插入一个元素都会分配空间,每删除一个元素都会释放空间。底层:双向链表
- 访问:O(n) 随机访问性能差,只能快速访问头尾节点;插入/删除:O(1),适用于:经常插入删除大量数据
四、map
C++ map和 unordered_map 区别
文章评论