简体   繁体   中英

Converting 3 digit decimal number to binary (C)

I need to convert 3 digit decimal number to binary using C.

My code:

#include <stdio.h> 

#define TWO 2 

int main() {
    int dec_num; // demical number  
    int i = 0; // loop cunter 
    printf("type in 3 digits number to convert to binary\n"); 
    scanf("%d", &dec_num); 

    while (++i <= 12) {
        if (dec_num % TWO != 0) {
            printf("1") ;
        } else if (dec_num % TWO == 0) {
            printf("0"); 
        } else if (dec_num <= 0) {
            break; 
        }
        dec_num / TWO;
    }
    return 0;
}

The problem is that the number doesn't get divided by 2 at the end of the while loop how can I fix it?

You did not store the value of dec_num after the division.

 dec_num / TWO; //<--------------------

Your while loop condition was also wrong.

while(++i <= 12) //<-------------------

You should perform the division operation until the number is greater than 0

According to the rules of binary to decimal, you should print 1s and 0s in reverse order . But in your code, you have changed the order. In order to fix that We could store the result in an array and then we could print the result in reverse order .

Here is your modified code,

#include <stdio.h> 
#define TWO 2 

int main()
{
  int dec_num; // demical number  
  int i=0; // loop cunter 
  printf("type in 3 digits number to convert to binary\n"); 
  int flag = scanf("%d",&dec_num); //<-----check the user input
  if(flag!=1)
    {
  printf("Input is not recognized as an integer");
  return 0;
    }
  int size=0;  

  int array[120] = {0};  //<-------to store the result

  while(dec_num > 0){   //<------- while the number is greater than 0

      if(dec_num % TWO !=0){
          array[i] = 1;
         }
      else if(dec_num % TWO ==0){
          array[i] = 0;
          }

      size = ++i;  //<------- store the size of result

     dec_num = dec_num / TWO;  //<------- divide and modify the original  number
  }

  for(i=size-1;i>=0;i--)    //<------- print in reverse order
      printf("%d",array[i]);

  return 0;
}

My solution will assume that the input is a positive number and that maximal decimal 3 digit number can be presented by 10 bits (decimal 999 is binary 1111100111). I will also use the fact that the bit-wise operators are defined by the C standard and should take place. These operations on most of the architectures are very efficient and much faster than / or % .

#include <stdio.h>

#define MAX_BIN_DIGITS 10
#define ERR_INVALID_INPUT_VALUE 1

int main(void)
{
  int dec_num; // demical input number  
  int i = MAX_BIN_DIGITS;
  int bin_bit;
  // storing the result at zero terminated string
  char bin_res[MAX_BIN_DIGITS+1] = {0};

  printf("Type in 3 digits number to convert to binary:\n"); 
  if (1 != scanf("%d",&dec_num))
  {
     printf("Error: Invalid input value!");
     return ERR_INVALID_INPUT_VALUE;
  } 

  // Checking for 'i' here just to be safe in case of larger input than expected - 4 digits or more
  while(i-- && dec_num) 
  {
    bin_bit = dec_num & 1;      // get the LSB
    dec_num >>= 1;              // remove the LSB from 'dec_num'
    bin_res[i] = '0' + bin_bit; // store the LSB at the end as a char
  }

  // Print the array starting from the most significant bit which is '1'
  // NOTE: Need to take care of special case when the input is '0', then 'i'
  //       will be  equal to 'MAX_BIN_DIGITS-1'.
  printf("%s\n", (i != MAX_BIN_DIGITS-1) ? &(bin_res[i+1]) ? "0");

  return 0;
}

There are multiple problems in your code:

  • You do not test the return value of scanf() : you get undefined behavior if the user fails to input characters that can be converted to an integer.
  • You do not test if the number indeed has at most 3 digits.
  • You iterate up to 12 times, but 10 should suffice since 2 10 = 1024 which is greater than any 3 digit number
  • As a matter of fact, it should not even be necessary to limit the number of iterations, since you stop when the number drops to 0.
  • The tests are inconsistent: num % TWO is either 0 or 1, the second test is redundant and the third test is never executed, so the loop fails to detect proper termination condition.
  • dec_num / TWO; does not update dev_num , so your loop just keeps printing the least significant bit (and the test while (++i <= 12) is indeed necessary for the loop to stop).
  • if corrected, this loop would print the bits from the least significant to the most significant, which is probably not the expected behavior.
  • #define TWO 2 is not strictly speaking a mistake, but does not improve code readability or safety. Local coding rules might bar you from using non trivial numeric constants in the code: such a rule seems counter productive in this particular case.
  • It is considered good style to always end output lines with a newline.
  • beware of typos: demical number is cute and loop cunter is intriguing.

Here is a corrected version of your code, using your algorithm, to illustrate the unexpected output (last significant bit to most significant bit):

#include <stdio.h> 

int main() {
    int dec_num; // decimal number  

    printf("type in a 3 digit number to convert to binary\n"); 
    if (scanf("%d", &dec_num) != 1) {
        printf("invalid input\n");
        return 1;
    }
    if (dec_num < 0 || dec_num > 999) {
        printf("invalid value: must have at most 3 digits\n");
        return 1;
    }

    for (;;) {
        if (dec_num % 2 != 0) {
            printf("1");
        } else {
            printf("0");
        }
        dec_num = dec_num / 2;
        if (dec_num == 0)
            break;
    }
    printf("\n");
    return 0;
}

Here is a recursive version that outputs the bits in the proper order:

#include <stdio.h> 

void output_binary(int num) {
    if (num > 1)
        output_binary(num / 2);
    printf("%d", num % 2);
}

int main() {
    int dec_num; // decimal number  

    printf("type in a 3 digit number to convert to binary\n"); 
    if (scanf("%d", &dec_num) != 1) {
        printf("invalid input\n");
        return 1;
    }
    if (dec_num < 0 || dec_num > 999) {
        printf("invalid value: must have at most 3 digits\n");
        return 1;
    }
    output_binary(dec_num);
    printf("\n");
    return 0;
}

While you already have a valid answer correcting the failure to update dec_num following division and valid recursive methods provided by others, it is unclear whether you intend to allow entry of negative 3-digit values as well as positive values. An implementation that determines the size of the type and then shifts by one over each of the bits can provide a simple solution that will handle both positive and negative values.

For example the conversion part of the code shifting by 1 for each bit (indexed 31 -> 0 ) could be as simple as:

int main (void) {

    int decnum = 0;         /* user input number */
    unsigned remain = 0;    /* remainder after shift */
    size_t nbits = sizeof decnum * CHAR_BIT;    /* number of bits for type */

    /* read decnum here */

    printf ("decimal: %d\nbinary : ", decnum);  /* output value */
    while (nbits--) {   /* write bits 31->0 while 1 bits remain */
        if ((remain = decnum >> nbits))     /* shift saving shifted value */
            putchar ((remain & 1) ? '1' : '0'); /* bit 0/1 output '0'/'1' */
    }
    putchar ('\n');     /* tidy up with newline */
}

(note: a simple ternary operator is used to determine whether to output '1' or '0' )

The bigger part of your problem is the your failure to check the return of scanf . This is an open invitation for Undefined Behavior . Regardless of what function you use for user-input , you must validate that input succeeded before proceeding further. Otherwise you will invoke undefined behavior when you attempt to access an indeterminate value.

When using scanf in order to require valid input, you must handle three cases each time (1) did the user cancel input by pressing Ctrl+d generating a manual EOF ? ( Ctrl+z on windows), (2) did a matching or input failure occur? and (3) the good input case. Then, as is your case, you must further validate the input was in the proper range of values (a 3 digit number in your case). Additionally, to require valid input, you must handle any character that remains unread in the input buffer (as is the case for a matching failure, or if the user slipped and typed additional characters after the integer value.

Now it is completely fine to simply validate the input and return on an invalid input regardless of what caused the failure, but to require valid input it is up to you to handle all three cases, check that the input was within the valid range (and even then remove the trailing '\\n' left by scanf preparing the input-buffer for whatever additional input may be taken later in your code.

Many times that will require more code than your actual calculation does, but it is critical. For instance in your case, if you wanted to require the user to enter valid input, you could replace the /* read decnum here */ with something similar to:

    for (;;) {      /* loop continually until valid input or canceled */
        int rtn;    /* variable to hold scanf return */
        fputs ("enter 3 digit integer: ", stdout);  /* prompt */
        rtn = scanf ("%d", &decnum);    /* read value, saving return */
        if (rtn == EOF) {   /* handle manual EOF cancelation */
            fputs ("(user canceled input)\n", stderr);
            return 1;
        }
        if (rtn == 0) {     /* handle input failure */
            empty_stdin();  /* always empty input buffer */
            fputs ("  error: invalid integer input.\n", stderr);
        }   /* validate 3 digit poisitive (or negative) number */
        else if (decnum < -999 || (decnum > -100 && decnum < 100) 
                || decnum > 999) {
            empty_stdin();
            fputs ("  error: not a 3 digit number.\n", stderr);
        }
        else {              /* handle good input case (break loop) */
            empty_stdin();
            break;
        }
    }

note: the helper function empty_stdin() . That can be implemented with getchar() to read and discard any characters causing problems, eg

void empty_stdin (void) /* helper function to empty stdin after bad input  */
{                       /* (as well as the trailing '\n' after good input) */
    int c = getchar();
    while (c != '\n' && c != EOF)
        c = getchar();
}

Putting it altogether, you could do something like the following:

#include <stdio.h>
#include <limits.h>     /* for CHAR_BIT */

void empty_stdin (void) /* helper function to empty stdin after bad input  */
{                       /* (as well as the trailing '\n' after good input) */
    int c = getchar();
    while (c != '\n' && c != EOF)
        c = getchar();
}

int main (void) {

    int decnum = 0;         /* user input number */
    unsigned remain = 0;    /* remainder after shift */
    size_t nbits = sizeof decnum * CHAR_BIT;    /* number of bits for type */

    for (;;) {      /* loop continually until valid input or canceled */
        int rtn;    /* variable to hold scanf return */
        fputs ("enter 3 digit integer: ", stdout);  /* prompt */
        rtn = scanf ("%d", &decnum);    /* read value, saving return */
        if (rtn == EOF) {   /* handle manual EOF cancelation */
            fputs ("(user canceled input)\n", stderr);
            return 1;
        }
        if (rtn == 0) {     /* handle input failure */
            empty_stdin();  /* always empty input buffer */
            fputs ("  error: invalid integer input.\n", stderr);
        }   /* validate 3 digit poisitive (or negative) number */
        else if (decnum < -999 || (decnum > -100 && decnum < 100) 
                || decnum > 999) {
            empty_stdin();
            fputs ("  error: not a 3 digit number.\n", stderr);
        }
        else {              /* handle good input case (break loop) */
            empty_stdin();
            break;
        }
    }

    printf ("decimal: %d\nbinary : ", decnum);  /* output value */
    while (nbits--) {   /* write bits 31->0 while 1 bits remain */
        if ((remain = decnum >> nbits))     /* shift saving shifted value */
            putchar ((remain & 1) ? '1' : '0'); /* bit 0/1 output '0'/'1' */
    }
    putchar ('\n');     /* tidy up with newline */
}

Example Use/Output

$ ./bin/prnbin3digit
enter 3 digit integer: why?
  error: invalid integer input.
enter 3 digit integer: -75
  error: not a 3 digit number.
enter 3 digit integer: 1024
  error: not a 3 digit number.
enter 3 digit integer: 127 and more junk
decimal: 127
binary : 1111111

Or the case with a negative value:

$ ./bin/prnbin3digit
enter 3 digit integer: -127
decimal: -127
binary : 11111111111111111111111110000001

Or the case where the user cancels input:

$ ./bin/prnbin3digit
enter 3 digit integer: (user canceled input)

While this ended up being longer than what a simple right-shift implementation of the conversion would have been, it is worth building good user-input habits now to avoid untold problems later. Look things over and let me know if you have further questions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM