-1

For some reason the program is not working when I try to run it and I can't figure it out. I'd appricate any help. Homework stuff, so I have to stick to the very basics.

#include <stdio.h>
long long int decimal(long long int);
int power_2 (int);
long int power_10 (int);

int main(void){
    long long int n;
    while(1){
        printf("Write down a binary number. \n");
        scanf("%lld", &n);
    long long int a = decimal(n);
    printf("The binary number %lld converted into decimal is: %lld \n", n, a);
    }
    
}

//Here what I realized is if let's say I have the number 1001, then I subtract 1 and divide by 10, the remainder is going to be 0, meaning it will "jump" on the second if statement. I don't really know how to solve it.

long long int decimal(long long int e){
    long long int result;
    long long int k = 0;
    int i;
    for(i=0; i>=0; i++){
        if(e % 10 == 1){
            k += power_2(i);
            e--;
            if(e != 0){
            e /= 10;
            }
        }
        if(e % 10 == 0){
            e /= 10;
        if(e==0){
            break;
        }
    }
    return(k);
}

//This function should work, so it's not a problem

int power_2(int n){
    int base = 2, i, result = 1;
    if(n>0){
        for(i=1; i<=n; i++){
            result *= base;
        }
    }
    if(n=0){
        result = 1;
    }
    return(result);
}

//This is just something I thought I would need but no

long int power_10(int n){
    int base = 10, i, result = 1;
    if(n>0){
        for(i=1; i<=n; i++){
            result *= base;
        }
    }
    if(n=0){
        result = 1;
    }
    return(result);
}
  • 3
    Take the input as a string, then process it, right to left. – Cheatah Oct 10 '22 at 20:37
  • 1
    should spark some inspiration: https://stackoverflow.com/questions/2343099/convert-binary-format-string-to-int-in-c – yano Oct 10 '22 at 21:06
  • 1
    You don't need to convert your long long to a string. Stripping off powers of ten and converting them to powers of two is straight forward iteration... – Fe2O3 Oct 10 '22 at 23:39

4 Answers4

4

You can't use scanf with %lld to input a binary number string (e.g. 10101010101010101010101010101010101). It will interpret the number incorrectly.

You have to accept it as a char string (e.g).

char str[100];
scanf("%s",str);

But, scanf is problematic because it can overflow str. And, IMO, the "usual" remedy of:

scanf("%99s",str);

Is a hack [because if we ever change to (e.g.) char str[80]; then we have to manually change the scanf as well].

Better to use fgets:

char str[100];
fgets(str,sizeof(str),stdin);
str[strcspn(str,"\n")] = 0;

Then, loop on the string. No need for power* functions. You want:

long long int decimal(const char *e){

Loop on e and do: k <<= 1;

Here is the refactored code:

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

long long int
decimal(const char *e)
{
    long long int result = 0;

    for (int chr = *e++;  chr != 0;  chr = *e++) {
        result <<= 1;
        switch (chr) {
        case '0':
        case '1':
            result += (chr - '0');
            break;
        default:
            fprintf(stderr,"decimal: not a binary digit -- chr='%c'\n",chr);
            break;
        }
    }

    return result;
}

int
main(void)
{
    char str[100];

    while (1) {
        printf("Write down a binary number.\n");

        if (fgets(str,sizeof(str),stdin) == NULL)
            break;

        // strip newline
        str[strcspn(str,"\n")] = 0;

        long long int a = decimal(str);

        printf("The binary number '%s' converted into decimal is: %lld (hex: %llX)\n",
            str, a, a);
    }

    return 0;
}

Here is some sample output:

Write down a binary number.
110010111001
The binary number '110010111001' converted into decimal is: 3257 (hex: CB9)
Write down a binary number.

UPDATE:

Apart from the possibility of "overfilling" the register with bits (accepting a string that is more than 32 or 64 'bits'), someone here on SO recently pointed out that left shifting (possibly into the sign bit) a "signed" value can invoke UB... – Fe2O3

I'm not sure it's UB (depending on the context). But, to keep the peace, here's a version that sets errno:

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

#ifndef UNSIGNED
#define UNSIGNED    0
#endif

#if UNSIGNED
typedef unsigned long long num_t;
#define FMT "%llu"
#else
typedef long long num_t;
#define FMT "%lld"
#endif

num_t
decimal(const char *e)
{
    int count = 0;
    long long int result = 0;

    errno = 0;

    // NOTE: use of error codes is arbitrary

    for (int chr = *e++;  chr != 0;  chr = *e++) {
        result <<= 1;

        if (++count > (63 + UNSIGNED)) {
            fprintf(stderr,"decimal: too many digits\n");
            errno = E2BIG;
            break;
        }

        switch (chr) {
        case '0':
        case '1':
            result += (chr - '0');
            break;
        default:
            fprintf(stderr,"decimal: not a binary digit -- chr='%c'\n",chr);
            errno = EINVAL;
            break;
        }

        if (errno)
            break;
    }

    return result;
}

int
main(void)
{
    char str[100];

    while (1) {
        printf("Write down a binary number.\n");

        if (fgets(str,sizeof(str),stdin) == NULL)
            break;

        // strip newline
        str[strcspn(str,"\n")] = 0;

        num_t a = decimal(str);

        printf("The binary number '%s' converted into decimal is: " FMT " (hex: %llX)\n",
            str, a, a);
    }

    return 0;
}

Caveat: The following is off topic for this question, but, in response to the comments below ...

Neither of those, although... No, the DV for braces (not an anonymous drive-by shooting!) was for stackoverflow.com/a/74010599/17592432, the most trivial game on the planet... :-) /sigh/ – Fe2O3

I agree that leaving off the curly braces is not ambiguous. But, I would add them for human clarity. Note that GNU indent complains about premature EOF when trying to indent the code.

But, I eschew if/else ladder logic. In your block, using an if and then switch/case would be clearer, IMO.

And, I've never liked else if because to me, to properly indent it, we'd have:

if (user == robot)
    printf("It's a tie!");
else
    if (user == 1)
        if (robot == 2)
            printf("Robot wins by choosing Paper!");
        else
            printf("User wins by choosing Rock!");
    else
        if (user == 2)
            if (robot == 1)
                printf("User wins by choosing Paper!");
            else
                printf("Robot wins by choosing Scissors! ");
        else
            if (user == 3)
                if (robot == 2)
                    printf("User wins by choosing Scissors!");
                else
                    printf("Robot wins by choosing Rock!");

So, [to further muddy the waters] I prefer using do { ... } while (0):

do {
    if (user == robot) {
        printf("It's a tie!");
        break;
    }

    if (user == 1) {
        if (robot == 2)
            printf("Robot wins by choosing Paper!");
        else
            printf("User wins by choosing Rock!");
        break;
    }

    if (user == 2) {
        if (robot == 1)
            printf("User wins by choosing Paper!");
        else
            printf("Robot wins by choosing Scissors! ");
        break;
    }

    if (user == 3) {
        if (robot == 2)
            printf("User wins by choosing Scissors!");
        else
            printf("Robot wins by choosing Rock!");
        break;
    }
} while (0);

UPDATE #2:

May at least want to mention POSIX and _t types (I'm guilty as charged on the use as well) – David C. Rankin

Sigh, I was hoping to have a quiet day ;-)

First, I like [love] POSIX (vs. ISO/C). But, claiming all *_t and all _* as POSIX only is hubris.

The _* [for private functions] is quite common in other languages (e.g. python).

As to *_t types, I've been doing that for decades and never once hit a conflict. And, if I did, it's my responsibility as the programmer to fix that [by changing my code or the #include statements]. That is, assess the risks beforehand.

Worse, I also do (e.g.) typedef struct foo foo_t, *foo_p;. Note the *_p for a pointer type that seems to burn people here on SO.

But, it's arguably no worse that MS/Win's pType for pointers. And, it's my convention. And, it's passed code reviews plenty of times.

So, as Nixon once said (re. "Checkers"): Regardless of what they say about it, we're gonna keep it.

Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • 1
    Don't suggest code that leads to a buffer overflow. – Roland Illig Oct 10 '22 at 21:24
  • @RolandIllig You mean the `scanf` with just `%s`? – Craig Estey Oct 10 '22 at 21:25
  • Yes, exactly that. – Roland Illig Oct 10 '22 at 21:26
  • 1
    @RolandIllig [Of course] I'm aware of `scanf` shortcomings. But, I didn't want to muddy up the waters. I never use it, so I've rewritten the code to use `fgets` [and `strcspn`] which is, IMO, better for input from user TTY when prompting. – Craig Estey Oct 10 '22 at 21:31
  • "How to make a **binary** to decimal program in C?"... You've taken some liberties with the OP problem statement... – Fe2O3 Oct 10 '22 at 23:42
  • 1
    @Fe2O3 You mean, by accepting a string instead of an integer? That's not "taking a liberty", that's "proper education". So-called decimal-coded-binary is one of the more misbegotten notations out there. (Apologies if that's not what you meant.) – Steve Summit Oct 11 '22 at 00:21
2
#ifndef MUST_REINVENT_THE_WHEEL

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

int main (void)
{
  char str[100];
  printf("Write down a binary number. \n");
  fgets(str,100,stdin);
  printf("Decimal: %ld\n", strtol(str,0,2));
}

#endif
Lundin
  • 195,001
  • 40
  • 254
  • 396
1

You want to accept an integer value that is the sum of 10^x
Eg 10^6 + 10^4 + 10^2 + 10^1 = 1010110 (base 10)
Then interpret that as a series binary bits
2^6 + 2^4 + 2^2 + 2^1 = 1010110 (base 2)

You're on the right path with dividing by ten, but I get lost in the confusing code that you've written. Here's a simple sample that seems to work (using long with my 32 bit compiler.) It combines bit-shifting and divide-by-ten, and testing whether-or-not to set the current bit in the output accumulator.

int main() {
    long in = 10110101, wrk = in;
    unsigned long out = 0;

    for( unsigned long bit = 1; wrk; wrk /= 10, bit <<= 1 )
        if( wrk & 1 )
            out |= bit;

    printf( "in %ld  out %ld  (hex %X )\n", in, out, out );

    return 0;
}
in 10110101  out 181  (hex B5 )

Testing for negative values seems silly in this "toy" application. There's no way the range of 2^32 can accommodate 10^32.

Fe2O3
  • 6,077
  • 2
  • 4
  • 20
0

Turned out my program was pretty much correct. Only thing I missed is the second if in the decimal function should be an else if. Here's the correct program:

#include <stdio.h>
long long int decimal(long long int);
int power_2 (int);

int main(void){
    long long int n;
    while(1){
        printf("Write down a binary number. \n");
        scanf("%lld", &n);
    long long int a = decimal(n);
    printf("The binary number %lld converted into decimal is: %lld \n", n, a);
    }
    
}
long long int decimal(long long int e){
    long long int k = 0;
    int i;
    for(i=0; i>=0; i++){
        if(e % 10 == 1){
            k += power_2(i);
            e--;
            if(e != 0){
            e /= 10;
            }
        }
        else if(e % 10 == 0){
            e /= 10;
        }
        if(e==0){
            break;
        }
    }
    return(k);
}
int power_2(int n){
    int base = 2, i, result = 1;
    if(n>0){
        for(i=1; i<=n; i++){
            result *= base;
        }
    }
    if(n=0){
        result = 1;
    }
    return(result);
}

Example:

Write down a binary number. 
100010101011
The binary number 100010101011 converted into decimal is: 2219