views:

114

answers:

3

I wrote program to convert decimal to binary for practice purposes but i get some strange output. When doing modulo with decimal number, i get correct value but what goes in array is forward slash? I am using char array for being able to just use output with cout <<.

// web binary converter: http://mistupid.com/computers/binaryconv.htm

#include <iostream>
#include <math.h>
#include <malloc.h> // _msize
#include <climits>
#define WRITEL(x) cout << x << endl;
#define WRITE(x) cout << x;

using std::cout;
using std::endl;
using std::cin;

char * decimalToBinary(int decimal);
void decimal_to_binary_char_array();

static char * array_main;

char * decimalToBinary(int decimal) // tied to array_main
{
   WRITEL("Number to convert: " << decimal << "\n");
   char * binary_array;
   int t = decimal,     // for number of digits
       digits = 0,      // number of digits
       bit_count = 0;   // total digit number of binary number
   static unsigned int array_size = 0;
   if(decimal < 0) { t = decimal; t = -t; }  // if number is negative, make it positive
   while(t > 0) { t /= 10; digits++; }       // determine number of digits
   array_size = (digits * sizeof(int) * 3);  // number of bytes to allocate to array_main
   WRITEL("array_size in bytes: " << array_size);
   array_main = new char[array_size];
   int i = 0;  // counter for number of binary digits
   while(decimal > 0)
   {
      array_main[i] = (char) decimal % 2 + '0';
      WRITE("decimal % 2 = " << char (decimal % 2 + '0') << "  ");
      WRITE(array_main[i] << "  ");
      decimal = decimal / 2;
      WRITEL(decimal);
      i++;
   }
   bit_count = i;
   array_size = bit_count * sizeof(int) + 1;
   binary_array = new char[bit_count * sizeof(int)];
   for(int i=0; i<bit_count+1; i++)
      binary_array[i] = array_main[bit_count-1-i];
   //array_main[bit_count * sizeof(int)] = '\0';
   //WRITEL("\nwhole binary_array: "); for(int i=0; i<array_size; i++) WRITE(binary_array[i]); WRITEL("\n");
   delete [] array_main;
   return binary_array;
}

int main(void)
{

   int num1 = 3001; 
           // 3001    = 101110111001
           // 300     = 100101100
           // 1000    = 1111101000
           // 1200    = 10010110000
           // 1000000 = 11110100001001000000
           // 200000  = 110000110101000000
   array_main = decimalToBinary(num1);
   WRITEL("\nMAIN: " << array_main);

   cin.get();
   delete [] array_main;
   return 0;
}

The output:

Number to convert: 3001

array_size in bytes: 48
decimal % 2 = 1  /  1500
decimal % 2 = 0  0  750
decimal % 2 = 0  0  375
decimal % 2 = 1  1  187
decimal % 2 = 1  /  93
decimal % 2 = 1  1  46
decimal % 2 = 0  0  23
decimal % 2 = 1  1  11
decimal % 2 = 1  1  5
decimal % 2 = 1  1  2
decimal % 2 = 0  1  1
decimal % 2 = 1  1  0

MAIN: 1111101/100/

What are those forward slashes in output (1111101/100/)?

A: 

I haven't tried to analyze all your code in detail, but just glancing at it and seeing delete [] array_main; in two places makes me suspicious. The length of the code makes me suspicious as well. Converting a number to binary should take about two or three lines of code; when I see code something like ten times that long, I tend to think that analyzing it in detail isn't worth the trouble -- if I had to do it, I'd just start over...

Edit: as to how to do the job better, my immediate reaction would be to start with something on this general order:

// warning: untested code.
std::string dec2str(unsigned input) {
    std::deque<char> buffer;
    while (input) {
        buffer.push_front((input & 1)+'0');
        input >>= 1;
   }
   return std::string(&buffer[0], &buffer[0]+buffer.size());
}

While I haven't tested this, it's simple enough that I'd be surprised if there were any errors above the level of simple typos (and it's short enough that there doesn't seem to be room to hide more than one or two of those, at very most).

Jerry Coffin
The two deletes are deleting different things, but both are the wrong size and only one is needed.
Mike Seymour
@Mike: no, both the `delete` s in question are deleting `array_main`, which is only allocated once. Contrariwise, `binary_array` doesn't get deleted anywhere.
Jerry Coffin
@Jerry: no, the first deletes the one called `array_main` in `decimalToBinary()`; the second deletes the one called `array_main` in `main()`, which is called `binary_array` in `decimalToBinary()`. It's just twisted and confusing, not wrong. Unlike the array sizes and character arithmetic, which are wrong.
Mike Seymour
@Mike: where do you see a definition of `array_main` inside of `decimalToBinary`? As far as I (and my editor) can find, there's only one definition of `array_main`, which means they're both deleting the same thing.
Jerry Coffin
I see this require some clarification on my part of what i was trying to accomplish.There is array_main. In decimalToBinary array_main serves as temp storage for binary values, but they are in reversed order. Then binary_array is allocated and serves for reversed array_main input.Then the momory allocated to array_main is deleted with delete [] array_main;And binary_array is returned from decimalToBinary() and in MAIN, the array_main gets the adress of binary_array.And on the end of program, memory for array_main is deleted so no memory leaks.
Martin Berger
Anyway guys, thanks for replying, it it really interesting to see so many opinions. And if you have this code somewhere on your comp that works better than this scrapmetal of mine i would like you to share it with me.
Martin Berger
@Jerry: you're right, it's the same global pointer (I hadn't noticed that); but it's reassigned to point to the second array on return from `decimalToBinary`. So still not wrong, as each delete is applied to a different array, but even more twisted than I thought.
Mike Seymour
+7  A: 

Your problem is here:

array_main[i] = (char) decimal % 2 + '0';

You are casting decimal to char and it is swiping off the high-order bits, so that in some cases it becomes negative. % applied to a negative number is negative, hence you get one character before 0 in the ASCII chart, which is /.

I would also like to say that I think your macros WRITEL and WRITE qualify as preprocessor abuse. :-)

Simon Nickerson
Abuse indeed. I'd expect `WRITE(1<<4)` to print 16, not 14.
Mike Seymour
Your assessment is perfect, but you may want to add that to solve it, he can place the `decimal % 2 + '0'` in parenthesis so that the cast takes place on the result of his operation (which was probably the intention, and yields the appropriate characters)
sleepynate
Simon: So that whay i got /. And i thought how is it possible to put integer into char array without loses... One more question, why is WRITE and WRITEL preprocessor abuse? I thought that such usages are allright. Can something bad happen?
Martin Berger
@Martin: You can't put an `int` into a `char` without possible loss (unless `sizeof(int) == sizeof(char)`, which is legal but which I've never seen). In this case, you're taking an `int` and casting to `char`. As far as preprocessor abuse goes, function-like macros are almost always a bad idea in C++. They don't obey scoping rules and frequently make hash of precedence. Note Mike Seymour's comment. They also typically make the code harder to read.
David Thornley
David: Allright, i'll keep that in mind. Thanks for clarification.
Martin Berger
This thread here has some examples of abusing: #define begin { #define end } http://stackoverflow.com/questions/3257400/worst-c-coding-idioms-closed
Martin Berger
+2  A: 

It must be array_main[i] = (char) (decimal % 2 + '0'); (note the parentheses). But anyway, the code is horrible, please write it again from scratch.

Philipp
Phillip: yes the code is horrible, i spent several hours trying whatever i found on net to make this work. Well it was fun. Btw, thanks for commenting.
Martin Berger