8
\$\begingroup\$

Problem Description

Receive a 5 digit number and print out in a large size.

Sample input 32145

Sample output

 #####         #####          #              #              #####
      #             #         ##             #              #
      #             #          #             #              #
  #####             #          #             #  #           #####
      #        #####           #             #####              #
      #        #               #                #               #
      #        #               #                #               #
  #####        #####          ###               #           #####

This is the first time I attempted this kind of question and it is working. Could you please tell me if there any other efficient ways to do the same?

#include<stdio.h>
#define gotol(l) printf("\033[%dA",(l))
#define gotoc(c) printf("\033[%dC",(c))
#define gotold(d) printf("\033[%dB",(d))
void disp(int j,int i)
{
        switch(j)
        {
                        case 0:gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#####\n");gotol(8);;
                               break;
                        case 1:gotoc(i*15);
                               printf(" #\n");gotoc(i*15);
                               printf("##\n");gotoc(i*15);
                               printf(" #\n");gotoc(i*15);
                               printf(" #\n");gotoc(i*15);
                               printf(" #\n");gotoc(i*15);
                               printf(" #\n");gotoc(i*15);
                               printf(" #\n");gotoc(i*15);
                               printf("###\n");gotol(8);
                               break;
                        case 2:gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("     #\n");gotoc(i*15);
                               printf("     #\n");gotoc(i*15);
                               printf("     #\n");gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("#   \n");gotoc(i*15);
                               printf("#   \n");gotoc(i*15);
                               printf("#####\n");gotol(8);break;
                        case 3:gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("     #\n");gotoc(i*15);
                               printf("     #\n");gotoc(i*15);
                               printf(" #####\n");gotoc(i*15);
                               printf("     #\n");gotoc(i*15);
                               printf("     #\n");gotoc(i*15);
                               printf("     #\n");gotoc(i*15);
                               printf(" #####\n");
                               gotol(8);break;
                        case 4:gotoc(i*15);
                               printf("#\n");gotoc(i*15);
                               printf("#\n");gotoc(i*15);
                               printf("#\n");gotoc(i*15);
                               printf("#  #\n");gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("   #\n");gotoc(i*15);
                               printf("   #\n");gotoc(i*15);
                               printf("   #\n");gotol(8);break;
                        case 5:gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("#    \n");gotoc(i*15);
                               printf("#    \n");gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("    #\n");gotoc(i*15);
                               printf("    #\n");gotoc(i*15);
                               printf("    #\n");gotoc(i*15);
                               printf("#####\n");gotol(8);
                                break;
                        case 6:gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("#    \n");gotoc(i*15);
                               printf("#    \n");gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#####\n");gotol(8);
                                break;
                        case 7:gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("    #\n");gotoc(i*15);
                               printf("    #\n");gotoc(i*15);
                               printf("    #\n");gotoc(i*15);
                               printf("    #\n");gotoc(i*15);
                               printf("    #\n");gotoc(i*15);
                               printf("    #\n");gotoc(i*15);
                               printf("    #\n");gotol(8);
                                break;
                        case 8:gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#####\n");gotol(8);
                                break;
                        case 9:gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#   #\n");gotoc(i*15);
                               printf("#####\n");gotoc(i*15);
                               printf("    #\n");gotoc(i*15);
                               printf("    #\n");gotoc(i*15);
                               printf("    #\n");gotoc(i*15);
                               printf("#####\n");gotol(8);
                                break;

        }
}
int main(void)
{
        char str[6],*s=str;
        int i=0;
        printf("\n Enter the string\n\n\n");
        scanf("%s",str);
        printf("\n");
        for(i=0;str[i]!='\0';++i){
                disp((str[i]-48),i);
        }
        gotold(8);

return 0;
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Without an implementation for digits 6 to 9, this code is broken. \$\endgroup\$ Commented Jun 12, 2015 at 12:10
  • 1
    \$\begingroup\$ I've supplied the additional code using the magic of cut-and-paste. \$\endgroup\$
    – Edward
    Commented Jun 12, 2015 at 13:15

3 Answers 3

12
\$\begingroup\$

You have a working program that does what you wanted, so that's an excellent start for a beginner! I have a couple of suggestions that may help you improve your program.

Consider using a data structure

Right now, the data for the digits and the code to print them is intertwined. Since the data for the large digits is just data, consider separating that data from the code that prints the digits. For example, I might start with this:

#define DIGITHEIGHT 7
#define DIGITWIDTH  6
const char *digits[DIGITHEIGHT] = {
"#####     # ##### ##### #   # ##### ##### ##### ##### ##### ",
"#   #     #     #     # #   # #     #         # #   # #   # ",
"#   #     #     #     # #   # #     #         # #   # #   # ",
"#   #     # ##### ##### ##### ##### #####     # ##### ##### ",
"#   #     # #         #     #     # #   #     # #   #     # ",
"#   #     # #         #     #     # #   #     # #   #     # ",
"#####     # ##### #####     # ##### #####     # #####     # "
};

That way, it's easy to see how the digits will look and easy to modify them if we care to do so.

Consider how to print on a printer

Many years ago, the primary interface for a computer was more typically a printer (teletype) rather than a screen. For such devices, the ANSI escape sequences your code uses to position the cursor wouldn't work. (There are also command line interfaces today which do not support ANSI escape sequences.) One way to accommodate such a use would be to simply print each line of the string of digits. For example, one might use code like this:

for (int line = 0; line < DIGITHEIGHT; ++line) {
    for (char *s = str; *s; ++s) {
        printdigitrow(*s, line);
    }
    putchar('\n');
}

See if you can write the printdigitrow routine to use the digits array defined above to print one row of one digit.

Eliminate unused variables

The variable s in your code is defined but never used. Since unused variables are a sign of poor code quality, you should seek to eliminate them. Your compiler is probably smart enough to warn you about such things if you know how to ask it to do so.

Avoid buffer overrun vulnerabilities

The code currently includes these two statements:

char str[6];
scanf("%s",str);

This is a potential problem because the scanf will read any size of string, but we've only allocated 6 bytes. That's the recipe for a buffer overflow vulnerability and must be eliminated. Fortunately, it's simple to do so:

scanf("%5s",str);

Now the maximum width of the string is set to 5 characters (per comment by @CoolGuy -- we need to reserve room for the terminating '\0') and no buffer overflow will occur.

\$\endgroup\$
5
  • \$\begingroup\$ Very good answer! I'd call printdigit() something else. It's not printing a digit, only one line of a digit. \$\endgroup\$
    – Gauthier
    Commented Jun 12, 2015 at 13:01
  • \$\begingroup\$ @Gauthier: good suggestion. I changed it to printdigitrow() \$\endgroup\$
    – Edward
    Commented Jun 12, 2015 at 13:10
  • \$\begingroup\$ scanf("%6s",str); --> scanf("%5s",str); +1 for the NUL-terminator. \$\endgroup\$
    – Spikatrix
    Commented Jun 12, 2015 at 13:52
  • \$\begingroup\$ @CoolGuy: good catch! Thanks, I have fixed my answer. \$\endgroup\$
    – Edward
    Commented Jun 12, 2015 at 13:58
  • \$\begingroup\$ @Edward storing the Enlarged number in the array of pointer is a very smart move. I am working on writing a sub-routine printdigitsrow \$\endgroup\$ Commented Jun 15, 2015 at 5:03
8
\$\begingroup\$

Macro vs functions

Do not use #define to implement functions. Write real functions with actual parameters. You'll avoid all sorts of problems. Function-like macros have their use, but as a beginner you should always prefer functions. Mind you, learning the pitfalls of function-like macros is good.


Macro

If you were to keep macros instead of functions (I think you shouldn't), it is kind of standard to make their names all caps.


Identifiers

Take time to choose good names for your identifiers (variables and functions). That includes the input parameters to your function, j and i are not descriptive enough. You don't save much time by writing disp instead of display either. It's hard to put meaning in the name gotoc, I just don't understand the identifier. You should find names that make the use of the function obvious. The input parameters of the macros could also have meaningful names. This is hard!


Separate data and algorithms

It might be simpler to do it this way for this simple example, but it is generally a good idea to keep function separate from data. Create const arrays with the big numbers, write a function that uses this data to display on screen.

A sensible data structure if you can use c99 (std=c99 for gcc) could be:

#define NUMBER_OF_DIGITS    (10)
#define DIGIT_HEIGTH        (7)
#define DIGIT_WIDTH         (6)

// + 1 for null termination \0   
const char large_digits[NUMBER_OF_DIGITS][DIGIT_HEIGTH][DIGIT_WIDTH + 1] = {
    [0] = {
        "##### ",
        "#   # ",
        "#   # ",
        "#   # ",
        "#   # ",
        "#   # ",
        "##### "},
    [1] = {
        "    # ",
        "    # ",
        "    # ",
        "    # ",
        "    # ",
        "    # ",
        "    # "},
// ...
    [9] = {
        "##### ",
        "#   # ",
        "#   # ",
        "##### ",
        "    # ",
        "    # ",
        "    # "}
};

(c99 needed to explicitly name the indices, with is more elegant and less error-prone.)


Declarations

char str[6],*s=str; would be best separated into two rows. It's too easy to make mistakes in pointer declarations, and you don't save much by putting them in a single line.


Check error codes

scanf may return error codes, check for that (see the man page of scanf for a good example of how to deal with its possible errors). Error codes are very helpful, and even when you think you'll never have any use of them, you should check them.


Spacing and new lines

It is generally accepted that spaces around binary operators (+, -, - /, ...) increase readability. Same after ; in the for loop, and after : in the case labels.

A new line before the break; would also look clearer. When I read a switch I always more or less consciously check if the breaks are there. No new line makes this much harder.

\$\endgroup\$
4
  • \$\begingroup\$ Lots of good advice here. It might be useful to expand a bit more on the pitfalls of macros-as-functions (e.g. lack of type checking, potential for side effects). The advice is sound, but it would be even better to explain why. \$\endgroup\$
    – Edward
    Commented Jun 12, 2015 at 14:48
  • \$\begingroup\$ Did you Just declare a 3-D array ? \$\endgroup\$ Commented Jun 15, 2015 at 5:00
  • \$\begingroup\$ @RohitSaluja: sure! Note that the width should be DIGIT_WIDTH + 1, to accomodate for the null string terminator \0, which is implicitly included in string literals (I missed that first). \$\endgroup\$
    – Gauthier
    Commented Jun 15, 2015 at 7:39
  • \$\begingroup\$ @Edward: right. I left it out because the actual macros in OP's code do not illustrate side effects. Type checking might be a problem though. \$\endgroup\$
    – Gauthier
    Commented Jun 15, 2015 at 8:02
1
\$\begingroup\$

You could do it like this. I'm sharing the code that I have written. I've explained the code with comments. To read more, visit my blog - An algorithm written in C to print out the input number in large size

/**
Author:- Mayukh Datta
www.thecoducer.com
**/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define H 7
#define W 8 //one extra room in the char array is required for storing '\0'
void main()
{
    char num[11];  //here too one extra room is needed for the '\0'
    char c;  //for option
    int i, j, k;
    //declaring char 2D arrays and initializing with hash-printed digits
    char zero[H][W]={" ##### ", //H=0
                     " #   # ", //H=1
                     " #   # ", //H=2
                     " #   # ", //H=3
                     " #   # ", //H=4
                     " #   # ", //H=5
                     " ##### "},//H=6

         one[H][W]={"   #   ",
                    "  ##   ",
                    "   #   ",
                    "   #   ",
                    "   #   ",
                    "   #   ",
                    " ##### "},

         two[H][W]={" ##### ",
                    "     # ",
                    "     # ",
                    " ##### ",
                    " #     ",
                    " #     ",
                    " ##### "},

         three[H][W]={" ##### ",
                      "     # ",
                      "     # ",
                      " ##### ",
                      "     # ",
                      "     # ",
                      " ##### "},

         four[H][W]={" #     ",
                     " #   # ",
                     " #   # ",
                     " ##### ",
                     "     # ",
                     "     # ",
                     "     # "},

         five[H][W]={" ##### ",
                     " #     ",
                     " #     ",
                     " ##### ",
                     "     # ",
                     "     # ",
                     " ##### "},

         six[H][W]={" ##### ",
                    " #     ",
                    " #     ",
                    " ##### ",
                    " #   # ",
                    " #   # ",
                    " ##### "},

         seven[H][W]={" ##### ",
                      "     # ",
                      "     # ",
                      "  #### ",
                      "     # ",
                      "     # ",
                      "     # "},

         eight[H][W]={" ##### ",
                      " #   # ",
                      " #   # ",
                      " ##### ",
                      " #   # ",
                      " #   # ",
                      " ##### "},

         nine[H][W]={" ##### ",
                     " #   # ",
                     " #   # ",
                     " ##### ",
                     "     # ",
                     "     # ",
                     "     # "};

    do
    {
        printf("Enter a number upto 10 digits:- ");
        fflush(stdin);
        gets(num);
        if(strlen(num)>10)
           printf("\nYou must enter a number upto 10 digits.\nTry again!\n");
        else
        {
            printf("\n");

            k=1;
            j=0;  //controls H of each digit
            while(k<=7)  //controls height
            {
                for(i=0;i<strlen(num);i++)  //reads each digit
                {
                    if(num[i]=='0')
                        printf("%s", zero[j]);
                    else if(num[i]=='1')
                        printf("%s", one[j]);
                    else if(num[i]=='2')
                        printf("%s", two[j]);
                    else if(num[i]=='3')
                        printf("%s", three[j]);
                    else if(num[i]=='4')
                        printf("%s", four[j]);
                    else if(num[i]=='5')
                        printf("%s", five[j]);
                    else if(num[i]=='6')
                        printf("%s", six[j]);
                    else if(num[i]=='7')
                        printf("%s", seven[j]);
                    else if(num[i]=='8')
                        printf("%s", eight[j]);
                    else if(num[i]=='9')
                        printf("%s", nine[j]);
                }
                printf("\n");
                k++;
                j++;
            }
        }
        printf("\nEnter Y to continue:- ");
        fflush(stdin);
        scanf("%c", &c);
    }while(c=='Y'||c=='y');
}
\$\endgroup\$
2
  • \$\begingroup\$ The if else if is bad style. The array approach from the other answers is much better. \$\endgroup\$ Commented Aug 26, 2017 at 15:19
  • \$\begingroup\$ If we use the array approach, could we get the whole output in a single line? \$\endgroup\$ Commented Aug 27, 2017 at 17:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.