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;
}
-
1\$\begingroup\$ Without an implementation for digits 6 to 9, this code is broken. \$\endgroup\$Gareth Rees– Gareth Rees2015年06月12日 12:10:07 +00:00Commented Jun 12, 2015 at 12:10
-
1\$\begingroup\$ I've supplied the additional code using the magic of cut-and-paste. \$\endgroup\$Edward– Edward2015年06月12日 13:15:27 +00:00Commented Jun 12, 2015 at 13:15
3 Answers 3
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.
-
\$\begingroup\$ Very good answer! I'd call
printdigit()
something else. It's not printing a digit, only one line of a digit. \$\endgroup\$Gauthier– Gauthier2015年06月12日 13:01:56 +00:00Commented Jun 12, 2015 at 13:01 -
\$\begingroup\$ @Gauthier: good suggestion. I changed it to
printdigitrow()
\$\endgroup\$Edward– Edward2015年06月12日 13:10:06 +00:00Commented Jun 12, 2015 at 13:10 -
\$\begingroup\$
scanf("%6s",str);
-->scanf("%5s",str);
+1 for the NUL-terminator. \$\endgroup\$Spikatrix– Spikatrix2015年06月12日 13:52:25 +00:00Commented Jun 12, 2015 at 13:52 -
\$\begingroup\$ @CoolGuy: good catch! Thanks, I have fixed my answer. \$\endgroup\$Edward– Edward2015年06月12日 13:58:23 +00:00Commented 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\$Rohit Saluja– Rohit Saluja2015年06月15日 05:03:52 +00:00Commented Jun 15, 2015 at 5:03
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 break
s are there. No new line makes this much harder.
-
\$\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– Edward2015年06月12日 14:48:21 +00:00Commented Jun 12, 2015 at 14:48
-
\$\begingroup\$ Did you Just declare a 3-D array ? \$\endgroup\$Rohit Saluja– Rohit Saluja2015年06月15日 05:00:39 +00:00Commented Jun 15, 2015 at 5:00
-
\$\begingroup\$ @RohitSaluja: sure! Note that the width should be
DIGIT_WIDTH + 1
, to accomodate for the null string terminator0円
, which is implicitly included in string literals (I missed that first). \$\endgroup\$Gauthier– Gauthier2015年06月15日 07:39:34 +00:00Commented 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– Gauthier2015年06月15日 08:02:37 +00:00Commented Jun 15, 2015 at 8:02
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');
}
-
\$\begingroup\$ The
if else if
is bad style. The array approach from the other answers is much better. \$\endgroup\$Roland Illig– Roland Illig2017年08月26日 15:19:26 +00:00Commented Aug 26, 2017 at 15:19 -
\$\begingroup\$ If we use the array approach, could we get the whole output in a single line? \$\endgroup\$Mayukh Datta– Mayukh Datta2017年08月27日 17:05:25 +00:00Commented Aug 27, 2017 at 17:05