题目描述:
通过c语言,打印字符星号( * ),并使之呈现出下面的“小飞机”图案。
题目分析:
图案可以看作由 6x12 的格子矩阵组成。
考虑图案是由单一的星号重复构成,因此第一想法想到了利用双层循环,外层循环负责变换行数,内层循环负责变换列数。
但是!又考虑到图案只有6行,因此也可以抛弃循环,采用暴力的硬输出:直接用 printf() 函数打印每一行需要的星号。
解法一:
直接用 printf() 打印每一行需要的星号,代码如下:
#include <stdio.h>
int main()
{
printf( " ** \n" );
printf( " ** \n" );
printf( "************\n" );
printf( "************\n" );
printf( " * * \n" );
printf( " * * \n" );
return 0;
}
解法二:
我第一反应想到循环来完成,建立外层 i 循环负责变化行数,内层 j 循环负责变化列数,循环遍历第 i 行第 j 列,并利用 if 判断在需要打印 * 的位置调用 printf() 函数。
近日网络上对于多层 if 嵌套造成的“屎山代码”讨论比较激烈,考虑非工作性以学习为目的,还是建议大家采用简洁的代码,尽量避免太多的 if 嵌套,因此代码考虑用switch-case语句处理外层循环,if语句处理内层循环。
#include <stdio.h>
int main()
{
int i,j;
for ( i = 0 ; i<6 ; i++ )
{
switch ( i )
{
case 0 :
case 1 :
for ( j = 0 ; j < 12 ; j++ )
{
if ( j == 5 || j == 6)
{
printf ( "*" );
}
else
{
printf ( " " );
}
}
printf ( "\n" );break;
case 2:
case 3:
for ( j = 0 ; j < 12 ; j++ )
{
printf ( "*" );
}
printf ( "\n" );break;
case 4 :
case 5:
for ( j = 0 ; j < 12 ; j++ )
{
if ( j == 4 || j == 7)
{
printf ( "*" );
}
else
{
printf ( " " );
}
}
printf ( "\n" );break;
}
}
return 0;
}
注意,关于代码中出现
case 0 :
case 1 :
的原因是,12行代码工作内容重复,因此可以利用 case 语句匹配成功后,如果未遇到 break 会继续执行的特点,让其能在 i=0 时匹配成功,又能在 i=1 时再次匹配此段代码,节省代码长度。
上述代码还可以简化,运用冒号运算符弱化if条件判断,代码如下:
#include <stdio.h>
int main()
{
int i,j;
for ( i = 0 ; i<6 ; i++ )
{
switch ( i )
{
case 0 :
case 1 :
for ( j = 0 ; j < 12 ; j++ )
{
printf( "%c", ( j==5 || j==6 ? '*' : ' ' ) );
}
printf ( "\n" );break;
case 2:
case 3:
for ( j = 0 ; j < 12 ; j++ )
{
printf ( "*" );
}
printf ( "\n" );break;
case 4 :
case 5:
for ( j = 0 ; j < 12 ; j++ )
{
printf( "%c", ( j==4 || j==7 ? '*' : ' ' ) );
}
printf ( "\n" );break;
}
}
return 0;
}
解法三:
我最喜欢的解法,采用了单片机编程中的位运算技巧。因为每一行的每一个格子只存在两种情况:要嘛是空格,要嘛是星号。因此我们可以采用 数字0代表空格,数字1代表星号。
例如,第一行第6个和第7个格子星号,其余为空白,则可以表示为二进制代码 000001100000 ,将二进制转化为十六进制为 0x060 ,即第一二行可利用 0x060 确定星号位置。第三四行可利用 0xfff 确定,第五六行可利用 0x090 确定。将产生的十六进制数取名为:星号位置编码。
将相应的星号位置编码存入数组,利用外层 i 循环变化行数,在对应行数取出数组对应值。这里需要明白一个关键点,那就是如何在对应的行中,在星号位置编码中数字1对应的位置打印 * 。思路是采用移位,内层 j 循环移位读取二进制数值,先看代码如下:
#include <stdio.h>
int main()
{
int xinghao[6] = {0x060, 0x060, 0xfff, 0xfff, 0x090, 0x090};
int i,j;
for ( i = 0; i <= 5; i++)
{
for ( j = 0; j <= 11; j++)
{
if (((xinghao[i] >> j) & 0x001) == 0x001)
//先将数组中的星号位置编码读出,再将编码向右依次移位,
//从而使对应某列的格子需要的0或1,正好对应移位后编码的最右边一位的数值
//再通过位与运算,移位后编码与0x001按位与。因为 0&任何为0,1&任何不变
//因此移位后编码与最后一位和1与运算不变,其余为和0与运算变成0
//最后再看看是否等于0x001,如果是则表示对应的格子应该填 *
printf("*");
else
printf(" ");
}
printf("\n");
}
return 0;
}
难点在于 移位运算 和 位与运算,需要着重理解一下。