相关知识

  1. 对于一个字符串,如何在最后追加一个字符或多个相同字符? 用append(size_type n, char c)最好。比如,s.append(1, 'x')是在s后补充1个x,t.append(2, 'y')是在t后补充2个y,

第一轮

最后一版(AC)

#include <iostream>
using namespace std;

int main() {
    string s;
    getline(cin, s);

    int i = 0;
    while(i < s.size()){
        string segment = s.substr(i, 8);
        if(segment.size() < 8){
            segment.append(8 - segment.size() % 8, '0');
        }
        cout << segment << endl;
        i += 8;
    }
}

  1. 这版的基本逻辑是,从s中切割一个长度为8的字符串,然后输出,循环这个过程。
  2. 那么在切割和输出之间,存在一个要做选择的情况——如果这个字符串长度不够8,那么需要补足8位,这里用的是append(size_type n, char c)

第二轮

第一版(5/27)

#include <iostream>
using namespace std;

int main() {
    string s;
    cin >> s;

    for(int i = 0; i < s.size(); i += 8){
        string temp = s.substr(i, 8);
        if(temp.size() == 8){
            cout << temp << endl;
        }else {
            string output(8, 0);
            int j = 0;
            for (char c : temp) {
                output[j] = temp[j];
                j++;
            }
            cout << output;
        }
    }
}
// 64 位输出请用 printf("%lld")

  1. 这里犯了哪些错误呢?由于忘记了可以用append(),笔者在这里声明了一个string output(8, 0)
  2. 在这里,笔者混淆了字符的ASCII码值(0)和字面量('0')。 string output(8, 0)的意思是创建一个字符串,里面用ASCII码值为0的字符(字面量为'\0',即空字符)填充。string output(8, '0')才是正确的写法,意思是创建一个字符串,里面用字面量为0的字符(ASCII码值为48)填充。
  3. 这里的写法错了,会导致一个问题——当切割出来的字符串长度恰好为8时,没有问题,当切割出来的字符串长度不够8时,就有问题。
  4. 于是,当整个字符串长度恰好为8的倍数时,测试用例就会通过;当整个字符串的长度不是8的倍数,测试用例就会报错。这就是5/27这个数字的来源。
  5. 笔者将这个错误修改以后,顺利通过。

第二版(5/27)

#include <iostream>
using namespace std;

int main() {
    string s;
    cin >> s;

    for(int i = 0; i < s.size(); i += 8){
        string temp = s.substr(i, 8);
        if(temp.size() < 8){
            string tail(8 - temp.size(), 0);
            temp += tail;
        }
        cout << temp << endl;
    }
}
// 64 位输出请用 printf("%lld")

  1. 这一版犯了和上一版犯了相同的错误,修改后直接通过。

第三版(0/27)

#include <iostream>
using namespace std;

int main() {
    string s;
    cin >> s;

    int a = s.size() % 8;
    for (int i = 0; i < s.size() - a; i += 8) {
        string temp = s.substr(i, 8);
        cout << temp << endl;
    }
    string tail(8 - a, 0);
    cout << s.substr(s.size() - a, a) + tail << endl;
}
// 64 位输出请用 printf("%lld")

  1. 这一版一个测试用例都没通过,那么除了和之前两个版本有相同的问题(错误1)以外,应该还有其他问题。
  2. 这一版有个额外的错误(错误2)——本意是希望把最后一行输出和前面若干行输出区分开来,但是并没有起到这一效果。 以一个长为16的字符串为例。它在进入循环后会输出两行,从循环出来后又会输出一行。如果是一个长为15的字符串呢?它在进入循环后会输出一行,从循环出来后又会输出一行。
  3. 基于上述分析,如果我们把错误1改掉,通过的测试用例应为22/27。这个猜测经验证是正确的。

第三轮

第一版(0/27)

#include <iostream>
using namespace std;

int main() {
    string s;
    int a = s.size() % 8;
    if(a != 0) s.append(8 - a, '0');

    for(int i = 0; i < s.size(); i += 8){
        cout << s.substr(i, 8) << endl;
    }

    return 0;

}
// 64 位输出请用 printf("%lld")
// 可以先补好字符串,再换行写

  1. 这一版代码根本没有用cin输入,这是一个低级错误。

第二版(AC)

#include <iostream>
using namespace std;

int main() {
    string s;
    cin >> s;
    int a = s.size() % 8;
    if(a != 0) s.append(8 - a, '0');

    for(int i = 0; i < s.size(); i += 8){
        cout << s.substr(i, 8) << endl;
    }

    return 0;

}
// 64 位输出请用 printf("%lld")
// 可以先补好字符串,再换行写

  1. 这是一个创新的思路,它不像之前几轮的版本那样选择一边分割一边筛出长不够8的子串补足,而是选择直接对原字符串补足。
  2. 原字符串长度为8的倍数,则不用管;不是8的倍数,则补几个0。
  3. 这个思路的好处是,大大简化了循环体内部,容易看出思路、定位错误。
  4. 其实,这个版本还可以再优化,比如声明一个const常量储存8,可随时按需修改。