1.3 基本格式
1.3.1 总体
对于完整的代码,我们常常先包含头文件,再进行宏定义,然后是命名空间,类型别名,接下来是全局常量,类型定义,按照结构体,类的顺序,最后是函数声明,函数定义,主函数,并且一定要return 0。
#include<iostream>
#define ll long long int
using namespace std;
int main(){
return 0;
}
1.3.2 头文件
一般而言,只应该包含需要用到的头文件即可。
算法竞赛中,可以使用bits/stdc++.h头文件,这个头文件俗称万能头文件,里面包含了很大数量的标准库头文件。
但好处并不多,其一,少敲两行头文件不能帮助你省下很多的时间,这对运行时间造成的影响可能更值得考虑,而且明确使用的头文件对于编写也是非常有利的;其二,包含过多的头文件可能会造成命名时的困扰,你常用的名字也许会在某个头文件里被使用。
1.3.3 宏定义
使用宏定义,可以预处理一段文本,将其进行替换。使用宏定义后,除了完整的变量或者字符串以外,在编译器读到需要被替换的文本的时候,会将这些文本全部替换成给定的文本。
#define A B,即会将所有的A看作是B。
需要注意,宏定义的结尾不应该写分号,头文件结尾也不应该有分号。
最为常用的宏定义,是#define ll long long int,可以帮助我们少敲几个字符,还有人会使用#define int long long int,这在空间复杂度压力不大时可以使用,但必须注意,此时主函数就不能写作int main了,而是signed main。
实际使用中,宏不是类型安全的,因此应减少使用。
1.3.4 命名空间
命名空间是一种特殊的作用域,将逻辑相关的标示符限定在一起,主要用于防止命名冲突。
using namespace std,这个代码非常常用,它的作用就是引入命名空间std,使该命名空间中的标识符与定义在全局中一致,可以直接调用,而不需要每次都使用名称空间标示符"std::"。
这显然是不安全的,我们为了防止命名冲突引入了命名空间,却要在写代码时不去使用,那当然就会遇到命名冲突的问题。
相比完全不使用命名空间,一个折中的办法是:
using std::cout;
using std::cin;
1.3.5 类型别名
宏的使用是不安全的,使用类型别名会更好。
typedef long long int ll,就是给long long int取了一个别名,别名和原类型名在编译器看来是一样的,并且也是类型安全的。
也可以使用using ll = long long int,这和上述方式是完全一致的。
除了long long int以外,偷懒时都建议使用这样的方式:
typedef pair<int, int> pii;
需要注意,类型别名的结尾必须写分号,使用命名空间的结尾也必须写分号。
1.3.6 全局常量
全局常量的使用非常少,最常见的是题目中出现,或者需要使用常数,例如最大值,取模,圆周率:
const int N = 1e5 + 2;
const int MOD = 1e9 + 7;
const double PI = 3.1415926535;
变量不推荐在函数外定义,但如果你必须定义一个大数组,那么也应该写在此处。
1.3.7 结构体,类,函数
先定义,后使用。当你写的代码非常庞大,那么你应该先统一声明,然后再进行定义。
在结构体和类中定义函数时,构造函数和析构函数在原则上不可递归,同时应防止使用时访问私有成员。
1.3.8 主函数
在主函数中,我们常会使用:
ios::sync_with_stdio(false);
cin.tie(0);
第一行代码会关闭C++的标准输入输出流和C风格输入输出的同步,第二行则会解除cin和cout的绑定,起到提升性能的作用。
这不会改变程序的逻辑,但应当避免使用C风格的输入输出方式。
其余代码书写时,可以适当进行空行,可以帮助自己区分代码块的作用。
主函数的最后一定要返回0,否则可能会产生返回非零的错误。
