Home > Software design >  Smartest way to write a program that reads a number N between 20 and 89 and prints its value express
Smartest way to write a program that reads a number N between 20 and 89 and prints its value express

Time:10-21

I have done the title-related task in the following way, using the C programming language:

#include <stdio.h>

int main(){
  int N;
  scanf("%d", &N);
  int ar[] = {2,3,4,5,6,7,8};
  if (N/10 == ar[0]) printf("twenty");
  if (N/10 == ar[1]) printf("thirty");
  if (N/10 == ar[2]) printf("forty");
  if (N/10 == ar[3]) printf("fifty");
  if (N/10 == ar[4]) printf("sixty");
  if (N/10 == ar[5]) printf("seventy");
  if (N/10 == ar[6]) printf("eighty");
  int ar1[] = {0,1,2,3,4,5,6,7,8,9};
  if (N%10 == ar1[0]) printf("\n");
  if (N%10 == ar1[1]) printf("one\n");
  if (N%10 == ar1[2]) printf("two\n");
  if (N%10 == ar1[3]) printf("three\n");
  if (N%10 == ar1[4]) printf("four\n");
  if (N%10 == ar1[5]) printf("five\n");
  if (N%10 == ar1[6]) printf("six\n");
  if (N%10 == ar1[7]) printf("seven\n");
  if (N%10 == ar1[8]) printf("eight\n");
  if (N%10 == ar1[9]) printf("nine\n");
    
  
  
}

What could be a smarter way to do this, sinc my code is quite verbose and long? Thanks in advance.

CodePudding user response:

You could move strings to arrays:

char *ar[] = { NULL, NULL, "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty"};
if (20 <= N && N <= 89)
  printf("%s", ar[N / 10]);

use similar scheme for ar1. From C99 you could use designated initializers to improve readability:

char *ar[] = {
  [2] = "twenty",
  [3] = "thirty",
  [4] = "forty",
  [5] = "fifty",
  [6] = "sixty",
  [7] = "seventy",
  [8] = "eighty",
};

CodePudding user response:

This may be overkill for what you want, but...

Here's a function that can print an English word representation of a value between 0 and 999:

/**
 * Print a string representation of a century (3 digits).  Assumes that n
 * is between 0 and 100 and that there is sufficient space in `dst` for
 * the resulting string.
 */
void printCentury( int n, char *dst )
{
  static const char *units[] = { "", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
  static const char *teens[] = { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
  static const char *decades[] = { "", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };

  /**
   * Special case for zero 
   */
  if ( n == 0 )
  {
    strcat( dst, "zero" );
    return;
  }

  if ( n / 100 )
  {
    strcat( dst, units[n/100] );
    strcat( dst, " hundred" );

    n -= n/100 * 100;
    if ( n )
      strcat( dst, " and " );
  }
  
  if ( n / 10 > 1 )
  {
    strcat( dst, decades[n/10] ); 
    n -= n / 10 * 10;
    if ( n )
    {
      strcat( dst, "-" );
      strcat( dst, units[n] );
    }
  }
  /**
   * special case for teens
   */
  else if ( n / 10 == 1 )
  {
    strcat( dst, teens[n-10] );
  }  
  else if ( n )
  {
    strcat( dst, units[n] );
  }
}

We use arrays to store our words, indexed by a value between 0 and 9. To get the "hundreds" number, we divide our input by 100. Integer division yields an integer result, so 123 / 100 == 1 - we use 1 to index into the units array, giving us the string "one", which we append to dst. We immediately append " hundred", then subtract 100 from n to give us the remaining 23 value. Since that value is not 0, we also append " and " to the string.

To get the "tens" number, we divide by 10 - again, integer division gives an integer result, so 23 / 10 == 2. We use 2 to index into the decades array, giving us the string "twenty", which we append to the string. We then subtract 20 from the value, giving us the remaining 3.

If we print out a decade string ("twenty", "thirty", etc. ), we check to see if the "ones" digit is zero - if it isn't, we append a "-" followed by the unit string.

There's a special case for handling values between 11 and 19, since 11, 12, 13, 15, and 18 don't follow the unit "teen" pattern.

Some examples:

$ ./numbers 0
0 - zero

$ ./numbers 1
1 - one

$ ./numbers 10
10 - ten

$ ./numbers 100
100 - one hundred

$ ./numbers 101
101 - one hundred and one

$ ./numbers 111
111 - one hundred and eleven

$ ./numbers 121
121 - one hundred and twenty-one

We can use this function to print numbers greater than 999 - we just break our input into groups of three digits, so 12345678 is processed as 12 ("twelve"), 345 ("three hundred and forty-five"), 678 ("six hundred and seventy-eight"), we just need to add the appropriate magnitudes: "twelve million, three hundred and forty-five thousand, six hundred and seventy-eight". Here's that function:

/**
 * Print a string representation of a number.  Assumes a signed 32-bit
 * int input and that there is sufficient space in dst for the
 * result.
 */
void printNumber( int n, char *dst )
{
  static int magval[] = { 0, 1000, 1000000, 1000000000 };
  static const char *magnitudes[] = { "", "thousand", "million", "billion" };
  int m = 0;

  if ( n == 0 )
  {
    strcat( dst, "zero" );
    return;
  }

  if ( n < 0 )
  {
    strcat( dst, "minus " );
    n = -n;
  }

  while ( m < 4 && n > magval[m] )
    m  ;

  while ( --m )
  {
    printCentury( n / magval[m], dst );
    strcat( dst, " " );
    strcat( dst, magnitudes[m] );
    strcat( dst, ", " );
    n -= n / magval[m] * magval[m];
  }
  
  printCentury( n, dst );
}

We start by figuring out the magnitude - we do that by checking to see if n is greater than the n'th magnitude (0, 1000, 1000000, 1000000000). That gives us our starting index into the "magnitudes" array so we can pick the right magnitude string - "thousand", "million", or "billion".

Then it's a similar process to the printCentury function - we use integer division to give us the (up to) three leading digits of the number, print that "century", then subtract that magnitude to give us the next three digits. Again, there's a special case for zero, and there's logic to handle negative values (by printing "minus" and negating the input value).

More examples:

$ ./numbers 1234
1234 - one thousand, two hundred and thirty-four

$ ./numbers 12345
12345 - twelve thousand, three hundred and forty-five

$ ./numbers 123456
123456 - one hundred and twenty-three thousand, four hundred and fifty-six

$ ./numbers 1234566
1234566 - one million, two hundred and thirty-four thousand, five hundred and sixty-six

$ ./numbers 12345668
12345668 - twelve million, three hundred and forty-five thousand, six hundred and sixty-eight

$ ./numbers 123456689
123456689 - one hundred and twenty-three million, four hundred and fifty-six thousand, six hundred and eighty-nine

$ ./numbers 1234566891
1234566891 - one billion, two hundred and thirty-four million, five hundred and sixty-six thousand, eight hundred and ninety-one

$ ./numbers -1234566891
-1234566891 - minus one billion, two hundred and thirty-four million, five hundred and sixty-six thousand, eight hundred and ninety-one

Complete program:

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

/**
 * Print a string representation of a century (3 digits).  Assumes that n
 * is between 0 and 100 and that there is sufficient space in `dst` for
 * the resulting string.
 */
void printCentury( int n, char *dst )
{
  static const char *units[] = { "", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
  static const char *teens[] = { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
  static const char *decades[] = { "", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };

  /**
   * Special case for zero 
   */
  if ( n == 0 )
  {
    strcat( dst, "zero" );
    return;
  }

  if ( n / 100 )
  {
    strcat( dst, units[n/100] );
    strcat( dst, " hundred" );

    n -= n/100 * 100;
    if ( n )
      strcat( dst, " and " );
  }
  
  if ( n / 10 > 1 )
  {
    strcat( dst, decades[n/10] ); 
    n -= n / 10 * 10;
    if ( n )
    {
      strcat( dst, "-" );
      strcat( dst, units[n] );
    }
  }
  else if ( n / 10 == 1 )
  {
    strcat( dst, teens[n-10] );
  }  
  else if ( n )
  {
    strcat( dst, units[n] );
  }
}

/**
 * Print a string representation of a number.  Assumes a signed 32-bit
 * int input and that there is sufficient space in dst for the
 * result.
 */
void printNumber( int n, char *dst )
{
  static int magval[] = { 0, 1000, 1000000, 1000000000 };
  static const char *magnitudes[] = { "", "thousand", "million", "billion" };
  int m = 0;

  if ( n == 0 )
  {
    strcat( dst, "zero" );
    return;
  }

  if ( n < 0 )
  {
    strcat( dst, "minus " );
    n = -n;
  }

  while ( m < 4 && n > magval[m] )
    m  ;

  while ( --m )
  {
    printCentury( n / magval[m], dst );
    strcat( dst, " " );
    strcat( dst, magnitudes[m] );
    strcat( dst, ", " );
    n -= n / magval[m] * magval[m];
  }
  
  printCentury( n, dst );
}
   
/**
 * Main. Takes an integer value from the command line
 * and prints the string representation.
 */  
int main( int argc, char **argv )
{
  if ( argc < 2 )
  {
    fprintf( stderr, "USAGE: %s <number>\n", argv[0] );
    return 0;
  }

  int val = strtol( argv[1], NULL, 10 );
  
  char text[1000] = {0};

  printNumber( val, text );
  printf( "%d - %s\n", val, text );
  return 0;
}
  • Related