C-код для преобразования десятичной в любую базу (от 2 до 36) - PullRequest
0 голосов
/ 22 октября 2018

Я только недавно начал изучать C. Я написал очень короткую программу, которая конвертирует между десятичным и двоичным.Я хотел попробовать написать код, который конвертирует между десятичной и любой базовой (до 36).Тем не менее, мой код просто распечатывает мусор.

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

void printBase(int n, int k, int i, char a[])
{
    int placeholder;
    if (n != 0)
    {
        //return n % 2 + 10 * printBinary(n / 2);
        placeholder=(char)(n%k);
        if(placeholder>=10)
        {
            a[i] = (char)(placeholder - 10) + 'A';
        } else {
            a[i] = (char)placeholder;
        }
        i++;
        printBase(n/2, k, i, a);
    }
    for (i=0; a[i]!='\0'; i++)
    {
        printf("%c", a[i]);
    }
    return;
}

void reverse(char fromStr[], char toStr[])
{
    int i, j=0;
    i=getchar();
    for (i=0; fromStr[i]!='\0'; i++)
    {
        j++;
    }
    i=0;
    while (j>=0)
    {
        toStr[i]=fromStr[j];
        i++;
        j--;
    }
    printf("%s", toStr);
}

int main()
{
    int n, k;
    char a[81], b[81];
    setvbuf(stdout, NULL, _IONBF, 0);
    printf("Enter a deicmal number you want to convert to binary: ");
    scanf("%i", &n);
    fflush(stdout);
    printf("Enter a base: ");
    scanf("%i", &k);
    printBase(n, k, 0, a);
    //printf("%s", a);
    //reverse(a, b);
    return 0;
}

Я думал, что проблема была с моей обратной функцией, но она прекрасно работает вне этого кода.Даже когда я печатаю строку a внутри функции printBase, она выводит мусор.В чем здесь проблема?

Ответы [ 5 ]

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

Я не знал, что ответы на мой собственный вопрос должны быть размещены ниже, извините!Но вот код, который я написал сам, если он кому-нибудь поможет:

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

void printBinary(int n, int k, int i, char a[])
{
    int placeholder;
    if (n != 0)
    {
        placeholder=(n%k);
        if(placeholder>=10)
        {
            a[i] = (placeholder - 10) + 'A';
        } else if(placeholder>=0 && placeholder<=9){
            a[i] = placeholder + '0';
        }
        i++;
        a[i]='\0';
        printBinary(n/k, k, i, a);
    }
    return;
}

int main()
{
    int n, k;
    char a[81], b[81];
    setvbuf(stdout, NULL, _IONBF, 0);
    printf("Enter a deicmal number you want to convert to binary: ");
    scanf("%i", &n);
    fflush(stdout);
    printf("Enter a base: ");
    scanf("%i", &k);
    printBinary(n, k, 0, a);
    n=strlen(a);
    k=0;
    n--;
    while (n>=0)
    {
        b[k]=a[n];
        n--;
        k++;
    }
    b[k]='\0';
    printf("%s", b);
    return 0;
}
0 голосов
/ 22 октября 2018

В качестве альтернативы обращению массива используется рекурсия.

Поскольку число цифр в некотором целочисленном типе никогда не бывает таким большим, рекурсия не будет чрезмерной.

Ниже приведено значение do {} while цикл, чтобы избежать особого случая с printBase(0).
Он также использует отрицательные значения в printBase_helper(), где /,% хорошо определено с C99.Это позволяет избежать неопределенного поведения кода, например n = -n, когда n == INT_MIN.

void printBase_helper(int neg, int base) {
  if (neg <= -base) {
    printBase_helper(neg / base, base);
    neg %= base;
  }
  putchar("0123456789ABCDEFGHIJKLMONOPQSTUVWXYZ"[-neg]);
}

void printBase(int n, int base) {
  if (n < 0) {
    putchar('-');
  } else {
    n = -n;
  }
  printBase_helper(n, base);
}

Тестовый код

int main(void) {
  int value[] = {0, 1, -1, 10, INT_MAX, INT_MIN};
  int base[] = {10, 2, 36};
  for (unsigned v = 0; v < sizeof value / sizeof value[0]; v++) {
    for (unsigned b = 0; b < sizeof base / sizeof base[0]; b++) {
      printf("Base %2d, value %11d, --> base %2d, value ", 10, value[v], base[b]);
      printBase(value[v], base[b]);
      printf("\n");
    }
  }
  return 0;
}

Вывод

Base 10, value           0, --> base 10, value 0
Base 10, value           0, --> base  2, value 0
Base 10, value           0, --> base 36, value 0
Base 10, value           1, --> base 10, value 1
Base 10, value           1, --> base  2, value 1
Base 10, value           1, --> base 36, value 1
Base 10, value          -1, --> base 10, value -1
Base 10, value          -1, --> base  2, value -1
Base 10, value          -1, --> base 36, value -1
Base 10, value          10, --> base 10, value 10
Base 10, value          10, --> base  2, value 1010
Base 10, value          10, --> base 36, value A
Base 10, value  2147483647, --> base 10, value 2147483647
Base 10, value  2147483647, --> base  2, value 1111111111111111111111111111111
Base 10, value  2147483647, --> base 36, value ZIK0ZJ
Base 10, value -2147483648, --> base 10, value -2147483648
Base 10, value -2147483648, --> base  2, value -10000000000000000000000000000000
Base 10, value -2147483648, --> base 36, value -ZIK0ZK
0 голосов
/ 22 октября 2018

Исходя из вашего кода, следующее делает то, что вы хотите.Он помещает в a обратное преобразование, которое все еще должно быть напечатано в обратном направлении:

void convertBase(int n, int k, char a[])
{
    int j, i=0, sign= 0;
    if (n==0) a[i++]='0';
    if (n<0 ) {sign= -1; n= -n;}
    while (n>0) {
        j= n%k;
        if (j<10)
            a[i]= j+'0';
        else
            a[i]= j+'A';
        n= n/k;
        i++;
    }
    if (sign== -1) a[i++]= '-';
    a[i]= 0;
}

А вот обратное:

void revStr(char *s)
{
    char c;
    int i=0, j=0;
    while (s[i]) i++; i--;
    while (i>j) {
        c= s[j];
        s[j]=s[i];
        s[i]= c;
        i--; j++;
    }
}
0 голосов
/ 22 октября 2018

С некоторой общей реализацией itoa

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

static const char* DIGISTS = "0123456789ABCDEFGHIKLMNOPQRSTVXYZ";

void itoa(long long i, unsigned char radix, char* to) {
    char *s = to + 65;
    char sign;
    unsigned len;
    if(i < 0) {
        sign = 1;
        len = 2;
    } else {
        sign = 0;
        len = 1;
    }
    *s = '\0';
    do {
        *(--s)= * ( DIGISTS + abs(i % radix) );
        i /= radix;
        ++len;
    } while(i != 0);
    if(sign)
        *(--s) = '-';
    memmove( to, s, len );
}

int main(int argc, const char** argv)
{
    char a[65];
    itoa( LLONG_MAX, 2, a);
    printf("binary: %s \n", a);
    itoa(12345, 10, a);
    printf("digit: %s \n", a);
    itoa(64018, 16, a);
    printf("hex : 0x%s \n", a);
    itoa(-24, 24, a);
    printf("base 24 : base24x%s \n", a);
    itoa(LLONG_MAX, 36, a);
    printf("base 36 : base36x%s \n", a);
    return 0;
}
0 голосов
/ 22 октября 2018
#define c ('A' - 10)


int n = 4564567; // any number
int b = 16; // any base

int tmp = n < 0 ? -n : n;
int i = 0;

while (tmp)
{
    tmp /= b;
    ++i; // you need to calculate how long will be the number
}

while (i--)
{
    a[i] = n % b + ((n % b < 10) ? '0' : c); // you have to check if the remaining is below 10 or not. That is very important
    n /= b;
}

Я думаю, что вы забыли добавить '0' в другом случае

Адаптировано из старого исходного файла https://github.com/agavrel/42-ft_printf/blob/master/srcs/pf_number.c

...