Преобразование трехзначного десятичного числа в двоичное (C) - PullRequest
0 голосов
/ 23 октября 2018

Мне нужно преобразовать 3-значное десятичное число в двоичное, используя C.

Мой код:

#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;
}

Проблема в том, что число не делится на 2 в концепетли while как это исправить?

Ответы [ 4 ]

0 голосов
/ 24 октября 2018

Хотя у вас уже есть действительный ответ, исправляющий ошибку обновления dec_num после деления и действительные рекурсивные методы, предоставленные другими, неясно, намереваетесь ли вы разрешить ввод отрицательных 3-значных значений кака также положительные значения.Реализация, которая определяет размер типа и затем сдвигается на единицу по каждому из битов, может обеспечить простое решение, которое будет обрабатывать как положительные, так и отрицательные значения.

Например, часть преобразования кода, сдвигаемая на *Значение 1006 * для каждого бита (индексированное 31 -> 0) может быть простым:

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 */
}

(примечание: простой оператор ternary используется для определения, выводить ли '1' или '0')

Большая часть вашей проблемы - ваша неспособность проверить возврат из scanf.Это открытое приглашение для Неопределенное поведение .Независимо от того, какую функцию вы используете для пользовательского ввода , вы должны проверить, что ввод был успешным, прежде чем продолжить.В противном случае вы будете вызывать неопределенное поведение при попытке получить доступ к неопределенному значению.

При использовании scanf для запроса допустимого ввода вы должны обрабатывать три случая каждый раз (1) сделалпользователь отменяет ввод, нажимая Ctrl + d , генерируя руководство EOF?( Ctrl + z в окнах), (2) произошел сбой , соответствующий или , ?и (3) хороший случай ввода.Затем, как и в вашем случае, вы должны дополнительно проверить , что вход был в правильном диапазоне значений (3-значное число в вашем случае).Кроме того, для требуется допустимый ввод, вы должны обработать любой символ, который остается непрочитанным во входном буфере (как в случае сбоя , соответствующего , или еслипользователь подсунул и набрал дополнительные символы после целочисленного значения.

Теперь вполне нормально просто проверить ввод и return на недопустимом вводе независимо от того, что вызвало сбой, но для требуется действительный ввод, вы должны обработать все три случая, проверить, что вход был в допустимом диапазоне (и даже затем удалить завершающий '\n', оставленный scanf, подготавливая буфер ввода для любого дополнительного ввода, который может быть взятпозже в вашем коде.

Во многих случаях это потребует больше кода, чем требует ваш фактический расчет, но это очень важно. Например, в вашем случае, если вы хотите, чтобы требовал , пользователь должен ввестидопустимый ввод, вы можете заменить /* 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;
        }
    }

примечание: вспомогательная функция empty_stdin().Это может быть реализовано с помощью 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();
}

В целом, вы можете сделать что-то вроде следующего:

#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 */
}

Пример использования / Вывод

$ ./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

Или случай с отрицательным значением:

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

Или случай, когда пользователь отменяет ввод:

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

Несмотря на то, что это оказалось дольше, чем могла бы быть простая right-shift реализация преобразования, сейчас стоит выстроить хорошие привычки пользовательского ввода, чтобы потом избежать неисчислимых проблем.Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 23 октября 2018

Мое решение будет предполагать, что вход является положительным числом и что максимальное десятичное трехзначное число может быть представлено 10 битами (десятичное 999 является двоичным 1111100111).Я также буду использовать тот факт, что побитовые операторы определены стандартом Си и должны иметь место.Эти операции на большинстве архитектур очень эффективны и намного быстрее, чем / или %.

#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;
}
0 голосов
/ 24 октября 2018

В вашем коде несколько проблем:

  • Вы не проверяете возвращаемое значение scanf(): вы получаете неопределенное поведение, если пользователь не может ввести символы, которые можно преобразовать в целое число.
  • Вы не проверяете, действительно ли число имеет не более 3 цифр.
  • Вы выполняете итерацию до 12 раз, но достаточно 10, поскольку 2 10 = 1024, чтобольше любого 3-значного числа
  • На самом деле, даже не нужно ограничивать количество итераций, поскольку вы останавливаетесь, когда число падает до 0.
  • Тестынесовместимы: num % TWO равен 0 или 1, второй тест является избыточным, а третий тест никогда не выполняется, поэтому цикл не может определить правильное условие завершения.
  • dec_num / TWO; не обновляет dev_numтаким образом, ваш цикл просто продолжает печатать младший значащий бит (и тест while (++i <= 12) действительно необходим для остановки цикла).
  • , если исправлено, этот цикл будет печатать биты из младшего значащего to самое существенное, что, вероятно, не является ожидаемым поведением.
  • #define TWO 2 не является, строго говоря, ошибкой, но не улучшает читаемость кода или безопасность.Локальные правила кодирования могут воспрепятствовать использованию в коде нетривиальных числовых констант: в данном конкретном случае такое правило кажется неэффективным.
  • Считается хорошим стилем всегда заканчивать выходные строки новой строкой.
  • Остерегайтесь опечаток: demical number это мило, а loop cunter интригует.

Вот исправленная версия вашего кода, использующая ваш алгоритм, для иллюстрации неожиданного вывода (последний значащий битдо старшего значащего бита):

#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;
}

Вот рекурсивная версия, которая выводит биты в правильном порядке:

#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;
}
0 голосов
/ 23 октября 2018

Вы не сохранили значение dec_num после деления.

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

Ваше условие цикла while также было неверным.

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

Вы должны выполнять операцию деления, пока число не станет больше 0

В соответствии с правиламиот двоичного к десятичному, вы должны вывести 1 и 0 в reverse order.Но в вашем коде вы изменили порядок.Чтобы это исправить, мы можем сохранить результат в array, а затем вывести результат в reverse order.

Вот ваш модифицированный код,

#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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...