最基础的菱形(实心)
我们先从一个最简单的任务开始:打印一个由 组成的实心菱形。

(图片来源网络,侵删)
示例代码
#include <stdio.h>
int main() {
int n, i, j, space;
n = 5; // 菱形半边的行数(即总行数为 2*n-1)
// 上半部分(包括中间行)
for (i = 1; i <= n; i++) {
// 打印空格
for (space = 1; space <= n - i; space++) {
printf(" ");
}
// 打印星号
for (j = 1; j <= 2 * i - 1; j++) {
printf("*");
}
printf("\n");
}
// 下半部分
for (i = n - 1; i >= 1; i--) {
// 打印空格
for (space = 1; space <= n - i; space++) {
printf(" ");
}
// 打印星号
for (j = 1; j <= 2 * i - 1; j++) {
printf("*");
}
printf("\n");
}
return 0;
}
输出结果
代码逻辑解析
这个菱形可以被看作由上半部分和下半部分组成,以最宽的那一行(第 n 行)为对称轴。
上半部分 (循环 i 从 1 到 n):
- 外层循环
for (i = 1; i <= n; i++): 控制当前是第几行。i从 1 增加到n。 - 第一个内层循环
for (space = 1; space <= n - i; space++): 负责打印每行开头的空格。- 第 1 行 (
i=1),需要n-1个空格。 - 第 2 行 (
i=2),需要n-2个空格。 - 第
n行 (i=n),需要n-n=0个空格。 - 这样就能保证星号始终居中。
- 第 1 行 (
- *第二个内层循环 `for (j = 1; j <= 2 i - 1; j++)` 负责打印每行的星号**。
- 第 1 行 (
i=1),星号数量为2*1 - 1 = 1个。 - 第 2 行 (
i=2),星号数量为2*2 - 1 = 3个。 - 第
n行 (i=n),星号数量为2*n - 1个。 - 这个公式
2*i - 1是打印奇数个星号的核心。
- 第 1 行 (
printf("\n");: 每打印完一行后,换行。
下半部分 (循环 i 从 n-1 到 1):
- 这部分与上半部分逻辑完全相同,只是外层循环的顺序是倒着的,从
n-1递减到 1。 - 这样就能打印出对称的下半部分。
进阶版:空心菱形
空心菱形只打印菱形的轮廓,内部是空的。

(图片来源网络,侵删)
示例代码
#include <stdio.h>
int main() {
int n, i, j, space;
n = 5; // 半边行数
// 上半部分
for (i = 1; i <= n; i++) {
// 打印空格
for (space = 1; space <= n - i; space++) {
printf(" ");
}
// 打印星号
for (j = 1; j <= 2 * i - 1; j++) {
// 如果是当前行的第一个或最后一个字符,打印星号,否则打印空格
if (j == 1 || j == 2 * i - 1) {
printf("*");
} else {
printf(" ");
}
}
printf("\n");
}
// 下半部分
for (i = n - 1; i >= 1; i--) {
// 打印空格
for (space = 1; space <= n - i; space++) {
printf(" ");
}
// 打印星号
for (j = 1; j <= 2 * i - 1; j++) {
// 如果是当前行的第一个或最后一个字符,打印星号,否则打印空格
if (j == 1 || j == 2 * i - 1) {
printf("*");
} else {
printf(" ");
}
}
printf("\n");
}
return 0;
}
输出结果
代码逻辑解析
核心变化在于打印星号的内层循环。
- 实心版:
for (j = 1; j <= 2 * i - 1; j++) { printf("*"); }—— 循环内的所有位置都打印 。 - 空心版:
for (j = 1; j <= 2 * i - 1; j++) { if (j == 1 || j == 2 * i - 1) { printf("*"); } else { printf(" "); } }—— 增加了一个if条件判断。j == 1: 判断是否是当前行的第一个字符。j == 2 * i - 1: 判断是否是当前行的最后一个字符。- 如果是第一个或最后一个,就打印 ,否则打印一个空格 ` `,形成“空心”效果。
通用版:用户输入大小
让用户自己决定菱形的大小,使程序更具交互性。
示例代码
#include <stdio.h>
int main() {
int n, i, j, space;
printf("请输入菱形半边的行数 (n > 0): ");
scanf("%d", &n);
// 检查输入是否合法
if (n <= 0) {
printf("输入无效,请输入一个正整数,\n");
return 1; // 非正常退出
}
// 上半部分
for (i = 1; i <= n; i++) {
for (space = 1; space <= n - i; space++) {
printf(" ");
}
for (j = 1; j <= 2 * i - 1; j++) {
// 可以在这里修改为空心菱形
// if (j == 1 || j == 2 * i - 1) {
// printf("*");
// } else {
// printf(" ");
// }
printf("*"); // 这里我们打印实心菱形
}
printf("\n");
}
// 下半部分
for (i = n - 1; i >= 1; i--) {
for (space = 1; space <= n - i; space++) {
printf(" ");
}
for (j = 1; j <= 2 * i - 1; j++) {
// 同样可以修改为空心
printf("*");
}
printf("\n");
}
return 0;
}
代码逻辑解析
scanf("%d", &n);: 从键盘读取一个整数并赋值给变量n。- 输入验证:
if (n <= 0)是一个良好的编程习惯,可以防止用户输入负数或零导致程序出现意外行为。 - 后续逻辑: 之后的循环逻辑与前面完全相同,只是
n的值由用户决定。
高级版:数字菱形
将星号 替换为数字,可以打印出更有趣的图案。
示例代码 (数字递增菱形)
#include <stdio.h>
int main() {
int n, i, j, space, num = 1;
n = 5;
// 上半部分
for (i = 1; i <= n; i++) {
for (space = 1; space <= n - i; space++) {
printf(" ");
}
for (j = 1; j <= 2 * i - 1; j++) {
printf("%d", num++);
}
printf("\n");
}
// 下半部分 (需要重置num)
num = 1;
for (i = n - 1; i >= 1; i--) {
for (space = 1; space <= n - i; space++) {
printf(" ");
}
for (j = 1; j <= 2 * i - 1; j++) {
printf("%d", num++);
}
printf("\n");
}
return 0;
}
输出结果
1
234
56789
101112131415
161718192025
2223242526
27282930
3132
33
代码逻辑解析
- 我们引入了一个新的变量
int num = 1;。 - 在打印星号的循环中,我们将
printf("*")替换为printf("%d", num++)。 num++是一个后缀自增操作符,意思是“先使用num的当前值进行打印,然后再将num的值加 1”。- 下半部分开始前,需要重置
num = 1,否则会接着上半部分的数字继续递增。
总结与技巧
- 分解问题: 将复杂的菱形分解为“上半部分”和“下半部分”两个独立的部分,分别处理。
- 循环嵌套: 使用
for循环的嵌套是打印二维图案的核心,外层循环控制行,内层循环控制列(即每行的内容)。 - 寻找规律: 关键是找到行号
i与每行空格数、星号数之间的关系。- 空格数 =
总行数/2 - 当前行号 - 星号数 =
2 * 当前行号 - 1
- 空格数 =
- 格式化输出:
printf中的格式化字符串(如 、、"%d")和换行符"\n"是控制最终显示效果的关键。 - 代码复用: 上半部分和下半部分的代码逻辑高度相似,可以通过调整外层循环的步进方向(
i++vsi--)来复用,减少代码量。
希望这个详细的解释能帮助你彻底理解如何在 C 语言中打印菱形图案!

(图片来源网络,侵删)
