简体   繁体   English

将3位数的十进制数字转换为二进制(C)

[英]Converting 3 digit decimal number to binary (C)

I need to convert 3 digit decimal number to binary using C. 我需要使用C将3位数的十进制数转换为二进制。

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? 问题是,在while循环结束时,数字没有被2除以该怎么解决?

You did not store the value of dec_num after the division. dec_num后,您没有存储dec_num的值。

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

Your while loop condition was also wrong. 您的while循环条件也错了。

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

You should perform the division operation until the number is greater than 0 您应该执行除法运算,直到数字大于0

According to the rules of binary to decimal, you should print 1s and 0s in reverse order . 根据二进制到十进制的规则,应该以reverse order打印1和0。 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 . 为了解决这个问题,我们可以将结果存储在array ,然后可以以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). 我的解决方案将假设输入为正数,并且最大十进制3位数字可以由10位表示(十进制999为二进制1111100111)。 I will also use the fact that the bit-wise operators are defined by the C standard and should take place. 我还将使用以下事实:按位运算符由C标准定义并且应该发生。 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. 您不测试scanf()的返回值:如果用户未能输入可以转换为整数的字符,则会得到未定义的行为。
  • You do not test if the number indeed has at most 3 digits. 您无需测试该数字是否确实最多包含3位数字。
  • You iterate up to 12 times, but 10 should suffice since 2 10 = 1024 which is greater than any 3 digit number 您最多可以迭代12次,但是10足够了,因为2 10 = 1024,它大于任何3位数字
  • 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. 事实上,甚至没有必要限制迭代次数,因为您可以在迭代次数降至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. 测试不一致: num % TWO为0或1,第二个测试是冗余的,第三个测试从未执行,因此循环无法检测到正确的终止条件。
  • 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). 不会更新dev_num ,因此您的循环只会继续输出最低有效位( while (++i <= 12)停止循环确实需要测试while (++i <= 12) )。
  • 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. #define TWO 2并不是严格意义上的错误,但不能提高代码的可读性或安全性。 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. 谨防错别字: demical number很可爱, loop cunter器很有趣。

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. 尽管您已经有了一个有效的答案,可以纠正除法dec_num后无法更新dec_num以及其他人提供的有效递归方法,但您是否打算允许输入负的 3位数和正值尚不清楚。 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: 例如,对于每个位(索引31 -> 0 ),将代码移位1的转换部分可能很简单:

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' ) (注意:使用简单的ternary运算符来确定是输出'1'还是'0'

The bigger part of your problem is the your failure to check the return of scanf . 问题的最大部分是您无法检查 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 ? 使用scanf 要求有效输入时,每次必须处理三种情况(1)用户是否通过按Ctrl + d生成手动EOF取消输入? ( Ctrl+z on windows), (2) did a matching or input failure occur? (在Windows上为Ctrl + z ),(2)是否发生匹配输入失败? and (3) the good input case. (3)输入情况良好。 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). 然后,根据您的情况,您必须进一步验证输入是否在适当的值范围内(在您的情况下为3位数字)。 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. 现在完全可以简单地验证输入并return无效输入,而不管是由什么原因引起的故障,但是要要求输入有效,则由您来处理所有三种情况,请检查输入是否在有效范围内(并且即使随后删除scanf留下的尾部'\\n' ,也要为以后在代码中可能需要的其他输入准备输入缓冲区。

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: 例如,在您的情况下,如果您想要求用户输入有效的输入,则可以用类似于以下内容的/* read decnum here */代替:

    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() . 注意:辅助函数empty_stdin() That can be implemented with getchar() to read and discard any characters causing problems, eg 可以使用getchar()来实现,以读取和丢弃引起问题的任何字符,例如

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. 尽管这样做的时间比转换的简单right-shift实施要长,但是现在值得养成良好的用户输入习惯,以免以后出现无法解决的问题。 Look things over and let me know if you have further questions. 仔细检查一下,如果您还有其他问题,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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