C/C++ 代码风格推荐

C/C++ 代码风格推荐

Contents

代码风格的重要性

你听说过大括号圣战吗?

没错,就是指大括号是否换行。

虽然到底换不换行双方各执一词,但其各自内部的风格统一性却不可否认。

一个风格混乱的代码,首先就会让阅读程序的人感到厌烦,而且也会造成理解上的困难(包括写程序的人)。

C/C++ 常见代码风格介绍

一、代码缩进

这个非常重要,因为缩进有助于理解代码的结构。

缩进主要是由大括号带来的代码块带来,但是对于 ifforwhile 等只有一个语句但换行的情况,也应有对应缩进。

可以看一下示例(大括号换行版本):

#include <bits/stdc++.h>
using namespace std;
struct node
{
public: //这类标识符建议不缩进
    int l, r; //结构体、类、命名空间的缩进
private:
    int len;
};
int x, y; //全局变量定义不缩进
int get(int x)
{
    //函数代码块缩进
}
int main()
{
    int n, m; //局部变量定义与普通语句无差别
    cin >> x >> y;
    if (x > y)
    {
        for (int i = y; i <= x; i++)
            get(i); //单个语句换行依然需要缩进
    }
    else //else 应该跟对应的 if 缩进相同
    {
        for (int i = x;i <= y; i++)
        {
            get(i); //for 语句代码块的缩进
            //do something..
        }
    }
    return 0;
}

特别地,对于缩进使用制表符还是空格,取决于个人喜好。(这又是另一个圣战了)

二、大括号问题

主要分为两派:

#include <bits/stdc++.h>
using namespace std;
struct node
{
    int l, r;
};
int x, y;
int get(int x)
{
    //do something..
}
int main()
{
    cin >> x >> y;
    if (x > y)
    {
        for (int i = y; i <= x; i++)
        {
            get(i);
            //do something..
        }
    }
    else
    {
        for (int i = x; i <= y; i++)
        {
            get(i);
            //do something..
        }
    }
    return 0;
}

这是典型的大括号换行写法。

#include <bits/stdc++.h>
using namespace std;
int x, y;
struct node {
    int l, r;
};
int get(int x) {
    //do something..
}
int main() {
    cin >> x >> y;
    if (x > y) {
        for (int i = y; i <= x; i++) {
            get(i);
            //do something..
        }
    }
    else {
        for (int i = x; i <= y; i++) {
            get(i);
            //do something..
        }
    }
    return 0;
}

这是典型的大括号不换行写法(建议大括号与前面的代码中隔开一个空格)。

两者优劣我们暂且不讨论(也不敢讨论),选择哪种都可以,但关键是要从一而终,也就是要换行就都换行,不能两种风格相互夹杂,不伦不类。

当然有时候当函数或者代码块过于简短,有可能整个放在一行,比如:

int min(int x, int y) { return x > y ? y : x; }

(但我从来不这么干)

(吐槽不忘自己,我好像都是 C++ 用前一种,JavaScript 跟 PHP 用后一种,所以好像我自己都不知道推荐哪种。)

三、多语句同行问题

很多人喜欢进行这么写代码:

c = a; a = b; b = c;

这种一行多个 ; 的写法十分不美观,纯粹是为了缩短代码,“充分”利用一行的空间。

所以我们提供两种方案:

c = a;
a = b;
b = c;
c = a, a = b, b = c;

因为 , 在 C/C++ 中也是一种运算符,所以第二种可以被看作一个语句,我个人认为更美观。

四、变量定义方式问题

有很多人喜欢对于每个变量都在需要使用时才定义。

然而有些变量本应是全局变量,却定义在了 main 函数中,这一是有可能增加代码编写复杂度,二是可能导致出错。

所以我们建议要严格区分局部跟全局变量。

比如一道题输入里涉及的 $n,m$ 这种变量,一般定义为全局变量,因为往往在整个代码中都会被使用到,而循环变量 $i,j,k$ 以及一些只在 iffor 代码块中临时用到的变量(比如交换用变量,临时读入变量,较大较小变量)则适合在对应位置局部定义,毕竟在不同的地方可能会被重复用到,这样方便于内存的释放。

而对于以后可能接触的一些工程代码的编写,这主要体现在 classstructpublicprivateprotected 这些不同的限定,可以用于防范一些变量的不合理调用。

五、空格问题

首先除了缩进以外,请不要出现连续的空格。

比如 int x; 正常情况下千万不要写成 int x;。(此处应有两个空格,我相信大家也看得出来有多丑)

然后个人建议对于 ifwhilefor 等关键字和其之后的 ( 之间尽量打一个空格。(纯属习惯)

并且 #include 跟后面的头文件之间最好也加一个空格,比如 #include <cmath>#include "stdio.h" 这样。

顺便讲一下常见的头文件的引用问题:

  • 一般系统头文件应该用 #include <>,并且引用先于自定义头文件。
  • 自定义头文件应该用 #include ""
  • 不需要的头文件尽量不引用。

六、常量定义、类型别名问题

一般常量定义建议使用(仅适用于 C++):

const int N = 100009;

另一种我个人选择尽量不用:

#define M 233

类型别名同理:

typedef long long ll;

一般不用:

#define pii pair<int, int>

七、冗余代码的减少

对于重复代码尽量使用循环或者函数的方法减少。

比如某位同学的作业里面的两个点坐标之间的判断就可以写个函数。

还有一些废话可以缩短,比如:

//1
if (F) c = a;
else c = b;

//2
if (F) return true;
else false;

//3
b += a;
a++;

//4
if (a > b) b = a;

分别可以缩短为:

//1
c = F ? a : b;

//2
return F;

//3
b += (a++);

//4
b = max(a, b);

还有很多种,具体情况需要你对代码有一个清晰的理解。

此处第二种默认其中是一个布尔表达式。

当然这些情况的缩减代码,也有可能降低可读性,更重要的是掌握好分寸。(只是 a = a + 1; 这种改成 ++a; 我觉得不需要犹豫)

八、变量定义问题

这个国际上有很多种标准。

对于做题(非工程),主要讲求一个能让自己和别人看懂。

比如 cnt 用于计数,Max 用于最大值,val 表示值,nextprev 表示前后一个(指针)。

当然对于工程,有更多的要求,这个主要要适应他人的命名规则。

比如说用下划线分别连接变量类型、变量从属范围、变量含义,i_List_length 可能就表示一个 List 类(结构体)的 int 型变量 length(长度)。(当然我也很支持驼峰命名法)

总结

代码风格存在的必要性是为了可读性的增强。

很多时候并不是代码写对就是好的,只要自己看懂就是好的,更重要的是增强代码可理解性,可移植性,而这些都是优良的代码风格可以带来的。

所以千万不能轻视代码风格

随便附上一份我最近的代码:

#include <iostream>
#include <cstring>
#include <cmath>

using namespace std;

// Input optimization
inline int read()
{
    int f = 1;
    char ch;
    while (ch = getchar(), ch < '0' || ch > '9')
        if (ch == '-') f = -1;
    int x = ch - '0';
    while (ch = getchar(), ch >= '0' && ch <= '9')
        x = x * 10 + ch - '0';
    return x * f;
}

// Output optimization, dicussed with Zhouyan
void print_not_zero(int x)
{
    if (x == 0) return;
    if (x < 0)
    {
        putchar('-');
        print_not_zero(-x);
        return;
    }
    print_not_zero(x / 10);
    putchar(x % 10 + '0');
}

inline void print(int x)
{
    x == 0 ? putchar('0') : (print_not_zero(x), 0);
}

const int N = 501009;
const int M = 109;

// Use scrolling array to reduce space complexity
int n, m, K, dp[2][M << 1] = {};

char A[N], B[N];

int main()
{
    n = read(), m = read(), K = read();
    scanf("%s", A + 1);
    scanf("%s", B + 1);
    // Terminate when the length difference is too large
    if (abs(n - m) > K)
    {
        puts("-1");
        return 0;
    }
    // Initialize state array
    int now = 1, pre = 0;
    for (int i = 0; i < 100; i++)
        dp[now][i] = K + 1;
    for (int i = 100; i <= 200; i++)
        dp[now][i] = i - 100;
    for (int i = 1; i <= n; i++)
    {
        /*
        * We define dp[i][j],which means the minimum cost to turn A[1..i] into B[1..j].
        * When the difference between i and j is greater than K, the minimum cost must not be lower than k.
        * So we just need the state when j falls in the interval [i - K, i + K].
        * Since K is no larger than 100, we can use dp[now][j] to substitute the original dp[i][i + j - 100].
        * I discussed this part of optimization with Zhouyan.
        */
        pre = now, now ^= 1;
        memset(dp[now], 0x3f, sizeof(dp[now]));
        for (int j = 100 - K; j <= 100 + K; j++)
        {
            if (dp[pre][j] > K) continue;
            if (i + j > 100 && i + j - 100 <= m && A[i] == B[i + j - 100])
                dp[now][j] = min(dp[now][j], dp[pre][j]);
            if (j)
                dp[now][j - 1] = min(dp[now][j - 1], dp[pre][j] + 1);
        }
        for (int j = 100 - K; j < 100 + K; j++)
            dp[now][j + 1] = min(dp[now][j + 1], dp[now][j] + 1);
    }
    print(dp[now][m - n + 100] <= K ? dp[now][m - n + 100] : -1);
    putchar('\n');
    return 0;
}

 

点赞 9

Comments: 5

  1. MatrixBi说道:

    海蜇棒棒!

  2. Thorin说道:

    王海我男神!!!!!!!!

  3. skylee03说道:

    int x;int x;有什麼區別?

Add your comment