相关知识
- 对于一个字符串,如何在最后追加一个字符或多个相同字符?
用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;
}
}
- 这版的基本逻辑是,从
s中切割一个长度为8的字符串,然后输出,循环这个过程。 - 那么在切割和输出之间,存在一个要做选择的情况——如果这个字符串长度不够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")
- 这里犯了哪些错误呢?由于忘记了可以用
append(),笔者在这里声明了一个string output(8, 0)。 - 在这里,笔者混淆了字符的ASCII码值(
0)和字面量('0')。
string output(8, 0)的意思是创建一个字符串,里面用ASCII码值为0的字符(字面量为'\0',即空字符)填充。string output(8, '0')才是正确的写法,意思是创建一个字符串,里面用字面量为0的字符(ASCII码值为48)填充。 - 这里的写法错了,会导致一个问题——当切割出来的字符串长度恰好为8时,没有问题,当切割出来的字符串长度不够8时,就有问题。
- 于是,当整个字符串长度恰好为8的倍数时,测试用例就会通过;当整个字符串的长度不是8的倍数,测试用例就会报错。这就是5/27这个数字的来源。
- 笔者将这个错误修改以后,顺利通过。
第二版(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")
- 这一版犯了和上一版犯了相同的错误,修改后直接通过。
第三版(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)以外,应该还有其他问题。
- 这一版有个额外的错误(错误2)——本意是希望把最后一行输出和前面若干行输出区分开来,但是并没有起到这一效果。
以一个长为16的字符串为例。它在进入循环后会输出两行,从循环出来后又会输出一行。如果是一个长为15的字符串呢?它在进入循环后会输出一行,从循环出来后又会输出一行。
- 基于上述分析,如果我们把错误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")
// 可以先补好字符串,再换行写
- 这一版代码根本没有用
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")
// 可以先补好字符串,再换行写
- 这是一个创新的思路,它不像之前几轮的版本那样选择一边分割一边筛出长不够8的子串补足,而是选择直接对原字符串补足。
- 原字符串长度为8的倍数,则不用管;不是8的倍数,则补几个0。
- 这个思路的好处是,大大简化了循环体内部,容易看出思路、定位错误。
- 其实,这个版本还可以再优化,比如声明一个const常量储存8,可随时按需修改。