首页 > 解决方案 > 以时尚的方式并排字符矩阵

问题描述

我正在尝试使 C 代码类似于著名的bigdigits.py.

为了达到这个结果,我已经尝试过连接for循环。

这产生了我能找到的最接近的结果

scanf("%s", nums);

system("cls");

printf("\n");

x = strlen(nums);

for(int i = 0; i < x; i++){
    if(nums[i] == '1'){
        printf("%s",n[1].number);
    }else if(nums[i] == '2'){
        printf("%s",n[2].number);
    }else if(nums[i] == '3'){
        printf("%s",n[3].number);
    }else if(nums[i] == '4'){
        printf("%s",n[4].number);
    }else if(nums[i] == '5'){
        printf("%s",n[5].number);
    }else if(nums[i] == '6'){
        printf("%s",n[6].number);
    }else if(nums[i] == '7'){
        printf("%s",n[7].number);
    }else if(nums[i] == '8'){
        printf("%s",n[8].number);
    }else if(nums[i] == '9'){
        printf("%s",n[9].number);
    }else if(nums[i] == '0'){
        printf("%s",n[0].number);
        }
}

这就是我试图找到想要的结果(for前面提到的循环)

Ps.:惨遭失败

scanf("%s", nums);

x = strlen(nums);

for(int k = 0; k < x; k++){
    for(int i = 0; i < 7; i++){
        for(int j = 0; j < 3; j++){
           if(nums[k] == '1'){
                printf("%s", n[i][j]);
           }if(nums[k] == '2'){
                printf("%s", n2[i][j]);
           }
        }
        printf("\n");
    }
}

输入类似于“12”,输出(我想要实现的)类似于

 *     ***
**    *   *
 *       *
 *      *
 *    *
 *    *
***   *****

但目前我的输出看起来像这样

 *     
**    
 *    
 *    
 * 
 * 
***

 ***
*   *
   *
  *
*
*
*****

标签: c

解决方案


让我们回溯一下,在编写代码之前先看看一般逻辑。

你显然有一个大数字数组,比如

#define  DIGITS  10
#define  ROWS    5

const char *const bigdigit[ROWS][DIGITS] = {
    { " 0 ", " 1 ", "22 ", "33 ", "  4", "555", " 66", "777", " 8 ", " 9 " },
    { "0 0", " 1 ", "  2", "  3", " 44", "5  ", "6  ", "  7", "8 8", "9 9" },
    { "0 0", " 1 ", " 2 ", " 3 ", "444", "55 ", "66 ", " 7 ", " 8 ", " 99" },
    { "0 0", " 1 ", "2  ", "  3", "  4", "  5", "6 6", " 7 ", "8 8", "  9" },
    { " 0 ", " 1 ", "222", "33 ", "  4", "55 ", " 6 ", " 7 ", " 8 ", "99 " }
};

这样就描述了数字(0..9)的bigdigit[row][digit]row(0..4 )。digit上面,每个数字是 3 个字符宽,但没关系,只要任何特定字符的行都具有相同的宽度(即"对齐!)。

假设您希望251使用这些大数字进行打印。

因为printf()输出是从上到下,从左到右,所以我们需要先打印2第一行,然后再打印5下一行,然后再打印第一行1,最后是一个新行,直到我们打印剩下的行。

所以,循环显然必须是

/* char *message;                    or 
   char  message[MAXSIZE];           contains the digits to be printed
   int   columns = strlen(message);  is the number of digits */

for (row = 0; row < ROWS; row++) {

    for (column = 0; column < columns; column++) {
        switch (message[column]) {
            case '0': fputs(bigdigit[row][0], stdout); break;
            case '1': fputs(bigdigit[row][1], stdout); break;
            case '2': fputs(bigdigit[row][2], stdout); break;
            case '3': fputs(bigdigit[row][3], stdout); break;
            case '4': fputs(bigdigit[row][4], stdout); break;
            case '5': fputs(bigdigit[row][5], stdout); break;
            case '6': fputs(bigdigit[row][6], stdout); break;
            case '7': fputs(bigdigit[row][7], stdout); break;
            case '8': fputs(bigdigit[row][8], stdout); break;
            case '9': fputs(bigdigit[row][9], stdout); break;
        }
    }

    fputc('\n', stdout);
}

如果不熟悉fputs()fputs(stuff, stdout)就相当于printf("%s", stuff)。同样,fputc('\n', stdout)等价于printf("\n");

换句话说,外循环在行上,内循环在要显示的每个大数字上。是的,我们确实在消息上循环 ROWS 次,但这没关系;我们确实需要这样做。


虽然我也建议不要展示完整的解决方案,但 OP 的问题实际上只是循环顺序,所以让我们破例,看一个完整的示例程序:

#include <stdlib.h>
#include <stdio.h>

#define  DIGITS  10
#define  ROWS    7

const char *const bigdigit[ROWS][DIGITS] = {
    { " 00 ", " 1", " 22 ", "333 ", "  44 ", "5555", " 666", "7777", " 88 ", " 99 " },
    { "0  0", "11", "2  2", "   3", " 4 4 ", "5   ", "6   ", "   7", "8  8", "9  9" },
    { "0  0", " 1", "   2", "   3", "4  4 ", "5   ", "6   ", "  7 ", "8  8", "9  9" },
    { "0  0", " 1", "  2 ", " 33 ", "44444", "555 ", "666 ", " 7  ", " 88 ", " 999" },
    { "0  0", " 1", " 2  ", "   3", "   4 ", "   5", "6  6", " 7  ", "8  8", "   9" },
    { "0  0", " 1", "2   ", "   3", "   4 ", "5  5", "6  6", " 7  ", "8  8", "   9" },
    { " 00 ", " 1", "2222", "333 ", "   4 ", " 55 ", " 66 ", " 7  ", " 88 ", "999 " }
};

int main(void)
{
    char  message[100];
    int   row, col;

    while (scanf(" %99[0-9]", message) == 1) {

        for (row = 0; row < ROWS; row++) {

            for (col = 0; message[col] != '\0'; col++) {
                fputs(bigdigit[row][message[col] - '0'], stdout);
                fputc(' ', stdout);
            }

            fputc('\n', stdout);
        }

        fputc('\n', stdout);
    }

    return EXIT_SUCCESS;
}

是字符串文字的bigdigit二维数组。外部(左)维度是行(0 到ROWS-1),内部(右)维度是数字(0 到 9)。如您所见,这允许我们以人类可读的形式定义数组。

char 数组限制为 100 个字符,包括字符串结尾的messagenul 字节,'\0'因此转换说明符将输入转换限制为 99 个字符。转换为[0-9],表示包含 ASCII 数字 0 到 9 的字符串。

scanf()函数返回成功转换的次数。scanf(" %99[0-9]", message)如果它转换由十进制数字组成的字符串,则返回 1,否则返回 0 或 EOF 。转换前面的空格意味着首先跳过任何空格(制表符、空格、换行符)。

因此,此示例程序一次一个地转换此类数字,直到不再提供输入,或者输入包含除空格或数字之外的其他内容。例如,任何字母都会结束程序。

重要的是要认识到,当任何scanf()函数族遇到无法按要求转换的输入时,该输入将留在输入缓冲区中。不可转换的数据不会被丢弃。如果您愿意,您需要丢弃该数据。(scanf("%*[\n]");可用于丢弃此类数据,如果转换模式以空格开头。它基本上丢弃输入行的其余部分,不包括行尾的换行符。*表示跳过转换;结果不存储在任何地方,并且没有对应于该转换的参数。)

行循环与此答案开头所解释的相同。

列循环在两个特征上有所不同:循环不是从0比 in 的字符串长度小一message开始循环,而是从 in0到字符串的末尾message。请记住,在 C 中,字符串以空字符 . 结尾'\0'。(strlen()只计算非空字符的数量,直到它看到一个空字符。)

列循环还会在每个数字之间打印一个空格。这只是为了让您不需要在bigdigit[][]数组本身中有字母空间。

bigdigit[row][message[col] - '0']表达式中的“棘手”部分是该message[col] - '0'部分。你看,字符串中的单个字符实际上只是整数,通常称为代码或代码点。在基本上所有字符集中,0通过9具有连续的代码集,因此message[col] - '0'如果 message[] 中的第 col'th 个字符是零位,则计算为零,如果是一位,则为 1,依此类推,最多为 9。

第二个fputc('\n', stdout);在每个大数字字符串之后打印一个空行。程序就是这样。

如果你编译上面的程序,输入1237 543,程序会输出

 1  22  333  7777 
11 2  2    3    7 
 1    2    3   7  
 1   2   33   7   
 1  2      3  7   
 1 2       3  7   
 1 2222 333   7   

5555   44  333  
5     4 4     3 
5    4  4     3 
555  44444  33  
   5    4     3 
5  5    4     3 
 55     4  333  

请注意,在 C 中,标准输入是行缓冲的。(也就是说,当您键入输入时,程序实际上会立即看到整行,但仅在您按 Enter 时。)因为大数字打印是在一次从输入中获取一个数字字符串的循环中完成的,这两个字符串打印在不同的行上。

如果您想按行中指定的方式打印输入,则需要阅读整行(使用 eg fgets()),并至少实现空格字符(bigdigit[][]我的意思是 in ),然后将fputs(bigdigit[row][message[col] - '0'], stdout)后面更改为 switch语句,以便您可以输出一个空格。例如:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define  DIGITS  10
#define  ROWS    7

const char *const bigdigit[ROWS][DIGITS] = {
    { " 00 ", " 1", " 22 ", "333 ", "  44 ", "5555", " 666", "7777", " 88 ", " 99 " },
    { "0  0", "11", "2  2", "   3", " 4 4 ", "5   ", "6   ", "   7", "8  8", "9  9" },
    { "0  0", " 1", "   2", "   3", "4  4 ", "5   ", "6   ", "  7 ", "8  8", "9  9" },
    { "0  0", " 1", "  2 ", " 33 ", "44444", "555 ", "666 ", " 7  ", " 88 ", " 999" },
    { "0  0", " 1", " 2  ", "   3", "   4 ", "   5", "6  6", " 7  ", "8  8", "   9" },
    { "0  0", " 1", "2   ", "   3", "   4 ", "5  5", "6  6", " 7  ", "8  8", "   9" },
    { " 00 ", " 1", "2222", "333 ", "   4 ", " 55 ", " 66 ", " 7  ", " 88 ", "999 " }
};

int main(void)
{
    char  message[100], *line;
    int   row, col;

    while (1) {

        line = fgets(message, sizeof message, stdin);
        if (line == NULL)
            break;

        if (strcspn(line, "\r\n") < 1)
            break;

        for (row = 0; row < ROWS; row++) {

            for (col = 0; line[col] != '\0'; col++) {
                switch (line[col]) {
                case '0': fputs(bigdigit[row][0], stdout); fputc(' ', stdout); break;
                case '1': fputs(bigdigit[row][1], stdout); fputc(' ', stdout); break;
                case '2': fputs(bigdigit[row][2], stdout); fputc(' ', stdout); break;
                case '3': fputs(bigdigit[row][3], stdout); fputc(' ', stdout); break;
                case '4': fputs(bigdigit[row][4], stdout); fputc(' ', stdout); break;
                case '5': fputs(bigdigit[row][5], stdout); fputc(' ', stdout); break;
                case '6': fputs(bigdigit[row][6], stdout); fputc(' ', stdout); break;
                case '7': fputs(bigdigit[row][7], stdout); fputc(' ', stdout); break;
                case '8': fputs(bigdigit[row][8], stdout); fputc(' ', stdout); break;
                case '9': fputs(bigdigit[row][9], stdout); fputc(' ', stdout); break;
                case ' ': fputs("     ", stdout); break;
                }
            }

            fputc('\n', stdout);
        }

        fputc('\n', stdout);

    }

    return EXIT_SUCCESS;
}

如果您增加DIGITS,您可以bigdigit[row][10]在案例中添加等等switch,以打印例如字母等。

因为空格始终只是空格,而不是bigdigit为其使用条目,我只是将其设置为五个空格字符宽,包括字母间空格。

如果你编译并运行这个程序,它会一直运行,直到你给它一个空行。对于相同的1237 543输入,这个输出

 1  22  333  7777      5555   44  333  
11 2  2    3    7      5     4 4     3 
 1    2    3   7       5    4  4     3 
 1   2   33   7        555  44444  33  
 1  2      3  7           5    4     3 
 1 2       3  7        5  5    4     3 
 1 2222 333   7         55     4  333  

与前一个相比,这个程序只有两个真正的新东西:首先,scanf()整个输入行被读入message[]缓冲区而不是 (限制为比 的大小少一个字符message[])。该表达式sizeof message计算出message数组中的字符数,包括为字符串结尾的 nul 字符保留的字符数。它仅适用message于数组,而不是指针。

(如果您为 动态分配内存char *message,那么您确实需要将分配的字符数保留在一个单独的变量中,并将其提供给fgets()。没有标准方法可以找出您为指针分配了多少字符;在C,如果需要,您必须自己跟踪。)

第二个变化是时髦的strcspn(line, "\r\n")函数调用。它返回line到字符串末尾的字符数,或最多列出的任何字符(此处为回车符或换行符,在不同操作系统中以各种组合用于换行符的两个字符),以先发生者为准.

(您有时会看到line[strcspn(line, "\r\n")] = '\0';用于line在第一个回车或换行时修剪内容,删除fgets()离开那里的字符串末尾的换行符。只要line不为 NULL 并且包含字符串,即使它不包含字符串也是安全的包含回车或换行,因为在这种情况下strcspn()只返回字符串的长度。)

if (strcspn(line, "\r\n") < 1)行可以读作“如果 中没有字符line,或者第一个字符是回车符或换行符,则”。我可以把它写成if (line[0] == '\0' || line[0] == '\r' || line[0] == '\n'),但我认为在这里展示这样一个漂亮的小标准函数是合适的。

因为语句中没有default:大小写,所以switch除了数字和空格之外的所有其他字符(以及您添加的字符,如果您增加DIGITS并将它们的字符串添加到bigdigit[][]数组并作为新case语句输出),将被完全忽略。


推荐阅读