PTA L1-039古风排版:用C语言二维数组模拟竖排打印,保姆级图解教程
第一次看到PTA平台这道古风排版题时,我盯着那个"从右向左竖向排版"的要求愣了半天。作为一个刚学完C语言数组章节的新手,满脑子都是"这要怎么用代码实现?"的困惑。直到把问题拆解成二维数组的填充游戏,一切突然变得清晰起来——原来这道题的精髓不在于字符串处理,而在于如何用二维数组构建一个可视化的字符矩阵模型。
1. 理解题目本质:从文字排版到矩阵建模
很多人看到"古风排版"四个字会本能地把它归类为字符串处理问题,这恰恰是解题的第一个误区。实际上,这道题的核心是二维数组的空间建模——我们需要在内存中构建一个虚拟的"文字展板",然后按照特定规则把字符填充进去。
1.1 输入输出的空间映射关系
给定输入样例:
4 This is a test case要求输出:
asa T st i h e tsi ce s用矩阵视角看这个转换过程会更清晰。我们需要:
- 确定矩阵的行数(n=4)
- 计算需要的列数(字符串长度17,17/4=4余1→5列)
- 创建一个4行5列的字符矩阵
- 按从右到左、从上到下的顺序填充字符
- 最后按行输出矩阵
1.2 关键参数计算技巧
计算列数时有个易错点:
int col = len / n; // 基础列数 if (len % n != 0) { // 处理余数 col += 1; }这个处理确保了当字符数不是n的整数倍时,最后一列也能被正确分配空间。比如17个字符按4行排列,需要⌈17/4⌉=5列。
2. 构建字符矩阵:从右向左的填充艺术
2.1 矩阵初始化与填充方向
创建一个100x100的二维数组(题目保证n<100且字符串长度≤1000):
char arr[100][100] = {0}; // 初始化为全0填充顺序是解题的关键难点:
- 列方向:从最后一列(col-1)开始向左填充
- 行方向:每列内从上到下(0到n-1)填充
用双重循环实现:
for (int j = col - 1; j >= 0; j--) { // 从右向左列 for (int i = 0; i < n; i++) { // 每列从上到下 if (ch[index] != '\0') { arr[i][j] = ch[index++]; } else { arr[i][j] = ' '; // 填充空格 } } }2.2 边界情况处理
当字符串长度不足时(index超过字符串长度),需要用空格填充:
else { arr[i][j] = ' '; // 题目要求的填充方式 }这个细节保证了输出矩阵的完整性,避免出现未初始化的随机值。
3. 可视化推演:一步步构建矩阵
让我们用输入样例演示矩阵构建过程:
初始字符串:"This is a test case" (17字符) n=4 → 需要5列(4行5列矩阵)
填充顺序:
列号: 4 3 2 1 0 行号: 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3填充过程:
- 填充第4列:arr[0][4]='T', arr[1][4]='h', arr[2][4]='i', arr[3][4]='s'
- 填充第3列:arr[0][3]=' ', arr[1][3]='i', arr[2][3]='s', arr[3][3]=' '
- ...(依此类推)
- 填充第0列:不足部分用空格补全
最终矩阵:
列 0 1 2 3 4 行 0 a s a T 1 s t i h 2 c e e 3 s t s i4. 输出技巧:按行打印的视觉转换
填充完成后,按行输出就能得到古风排版效果:
for (int i = 0; i < n; i++) { for (int j = 0; j < col; j++) { printf("%c", arr[i][j]); } printf("\n"); }输出时需要注意:
- 每行输出对应矩阵的一行
- 列顺序是自然的从左到右,但因为我们填充时是从右向左,所以产生了古风效果
- 空格字符会正常显示,保持矩阵的规整性
5. 调试技巧与常见错误
在实际编写时,有几个常见陷阱需要注意:
5.1 数组越界防护
虽然题目给出了n<100和字符串长度≤1000的限制,但良好的习惯是:
#define MAX_ROW 100 #define MAX_COL 100 char arr[MAX_ROW][MAX_COL] = {0};这样即使输入超出预期,也有基本的防护。
5.2 字符串读取问题
原代码使用gets()是不安全的,建议改用:
fgets(ch, sizeof(ch), stdin); ch[strcspn(ch, "\n")] = '\0'; // 去除换行符5.3 可视化调试技巧
在填充过程中插入调试输出:
printf("填充位置 arr[%d][%d] = %c\n", i, j, ch[index]);这能帮助理解填充顺序和内容。
6. 算法优化与扩展思考
6.1 空间优化方案
当前方案使用了固定大小的二维数组,实际上可以动态计算所需空间:
int required_col = (len + n - 1) / n; // 向上取整 char arr[n][required_col]; // C99变长数组6.2 横向思维扩展
同样的技术可以解决类似问题,比如:
- 矩阵旋转输出
- 螺旋填充矩阵
- 对角线遍历矩阵
这些问题的核心都在于建立正确的行列映射关系。
6.3 性能分析
该算法的时间复杂度是O(n×col),也就是O(len),是线性复杂度。空间复杂度也是O(len),对于题目限制来说非常高效。
7. 实战演练:从理解到应用
为了真正掌握这个技术,建议尝试以下练习:
- 修改程序,实现从左向右的竖排输出
- 尝试不存储完整矩阵,边计算边输出(节省空间)
- 处理中文字符的竖排输出(需要考虑UTF-8编码)
我在最初实现时犯过一个典型错误——把行列填充顺序弄反了,结果输出完全错乱。通过打印中间矩阵状态才找到问题所在。这也让我意识到,对于这类空间想象问题,可视化调试比盯着代码看要有效得多。