2

Ive beenn attempting to make a program that reads from a file, and if it reads a B it means the next line is binary and it will translate that next line from binary, into hex and dec and print out binary, then move on to the next line. I am having trouble with #1, going to the next line and #2 having my functions translate.

#include <iostream>
#include <sstream>
#include <fstream>
#include <bitset>
#include <cmath>
#include <string.h>
#include <cstring>
#include <string>

using namespace std;

//creating function to tranlsate hex into decimal
int hexi(char num[]) {
    int len = strlen(num);
    int base = 1;
    int temp = 0;
    for (int i = len - 1; i >= 0; i--) {
        if (num[i] >= '0' && num[i] <= '9') {
            temp += (num[i] - 48) * base;
            base = base * 16;
        }
        else if (num[i] >= 'A' && num[i] <= 'F') {
            temp += (num[i] - 55) * base;
            base = base * 16;
        }
    }
    return temp;
}
int main()
{
    
    {
    string line;
    signed char Binary[6] = { }; //array for binary string
    char Hex[16] = {}; //array for hex string
    double decimal{}; // initilizing decimal value
    char letter; //letter entered
    int rem; //remainder
    unsigned int i = 0; //for binary
    long long n; //for string of 010

    ifstream file;

    file.open("C:\\Users\\18059\\source\\repos\\translation\\input.txt");
    while (true)
    {
        getline(file, line);
        if (file.eof()) break;
        cout << line << " Binary: " << Binary << bitset<6>{i} << " Hexidecimal: " <<  hexi(Hex) << line << " Decimal: " << decimal << endl;
        //getline(file, line);
        

        {
            //read the letter
            cin >> letter;
            //reading if B for binary
            if (letter == 'B')
            {
                cout << endl;
                file >> n;
                while (n != 0) {
                    rem = n % 10;
                    n /= 10;
                    decimal += rem * pow(2, i);
                    ++i;
                }
                cout << "Decimal: " << decimal << endl;
            }

            else if (letter == 'H')
            {
                file >> Hex;
                cout << Hex << "Hexidecimal: " << hexi(Hex) << endl;
                return 0;
            }
        }
        {
            if (letter == 'D')
            {
                file >> decimal;
                cout << "Decimal: " << dec << endl;
            }
        }
    }

    file.close();
    }
}

right now it prints this what it prints

and then my text file looks like this

  • Unrelated: Replace `while (true) { getline(file, line); if (file.eof()) break;` with `while (getline(file, line)) {`. Saved you a couple lines and protects you from the rare possibility that `getline` finds a way to fail without hitting the end of the stream. – user4581301 Aug 23 '21 at 02:52
  • Unrelated: In `temp += (num[i] - 48) * base;` replace the `48` with `'0'`. Save you some potential portability nasties and is a lot easier to read. Side note: Looks like you are trying to reinvent [`strtoul`](https://en.cppreference.com/w/c/string/byte/strtoul). If you can use a library function, do it. Save you a lot of time. – user4581301 Aug 23 '21 at 02:58
  • Side note: 16 hex digits won't necessarily fit in an `int`. Consider using a `uint64_t` And don't forget to reserve space for the terminating null in `Hex` Use `std::string` if you are allowed because it makes a few otherwise fatal problems next to impossible. Can't help you with [Why does std::getline() skip input after a formatted extraction?](https://stackoverflow.com/questions/21567291/why-does-stdgetline-skip-input-after-a-formatted-extraction) though. I think you wrote too much code without testing. – user4581301 Aug 23 '21 at 03:04
  • 2
    Welcome to Stack Overflow. First, when you post a question here, please post all necessary files in the question. Not a link, not a screenshot, not a link to a screenshot, but the actual text. Second, when you write code, it behooves you to develop new functions *in isolation* as much as possible; get them working perfectly before you try to dovetail them. In this case your reading loop is badly formed and your conversion routines are... questionable. Write a loop and test it; write routines and test them. Don't write them all in one lump without testing; it never works. – Beta Aug 23 '21 at 03:06
  • Warning about `decimal += rem * pow(2, i);`: `pow` takes a detour through floating point, and if you want integers, [that's a big mistake](https://stackoverflow.com/questions/588004/is-floating-point-math-broken). Sometimes it returns a number like 1023.99999999999, and that's close enough for floating point, but rounds down to 1023 when you turn it back into an integer. Use bit shifting instead: `1 << i`. Also probably a lot faster. – user4581301 Aug 23 '21 at 03:08
  • Please isolate each of your issues and ask about each one separately. (Who knows? Maybe in the process of creating a [mre] focused on one issue, you might notice that you are reading from `cin` for some strange reason.) – JaMiT Aug 23 '21 at 05:43

2 Answers2

1

There are some problems.

YOu make your life overly complicated. You can use existing conversion functions.

But then, you also have some mistakes in the code. You always read a line and, in this line is already the letter. Then you read again and want to have the letter. But here you read already the next line. And so, it will never work.

Additionally you have a typo and read the letter from std::cin instead from file. This will block the execution of the program until you enter a letter in the console. But, becuase you are not even aware of that, you will wait forever.

What you need to do:

  • Read line by line
  • Check, if it starts with a letter
  • Depending on the letter, remember a conversion mode for the next round
  • If no letter, but number, then convert line string to number, using the numerical base
  • Use existing functions for that

Program can then look like this (one of million possible solutions):

#include <iostream>
#include <fstream>
#include <bitset>
#include <string>
#include <iomanip>

int main()
{
    std::string line;

    enum Mode {decimal, binary,hex};
    Mode mode = Mode::decimal;

    std::ifstream file("r:\\input.txt");
    if (!file) {
        std::cerr << "\nError: coud not open source file\n";
    }
    else while (std::getline(file, line))
    {

        //read the the first character and check, if it is a valid letter
        char letter = line[0];

        switch (letter) {
        case 'D':
            mode = Mode::decimal;
            break;
        case 'B':
            mode = Mode::binary;
            break;
        case 'H':
            mode = Mode::hex;
            break;
        default:
            // No letter, so, we assume a number
            // Use last read mode
            long value{};

            switch (mode) {
            case Mode::decimal:
                value = std::stol(line, nullptr, 10);
                break;
            case Mode::binary:
                value = std::stol(line, nullptr, 2);
                break;
            case Mode::hex:
                value = std::stol(line, nullptr, 16);
                break;
            default:
                std::cerr << "\nError: invalid Mode\n";
                break;
            }
            std::cout << line << "  \t  " 
                << " Binary: " << std::bitset<6>{static_cast<unsigned long long>(value)} 
                << " \tHexidecimal: " << std::hex << value
                << " \tDecimal: " << std::dec << value << std::endl;
        }
    }
    return 0;
}

A M
  • 14,694
  • 5
  • 19
  • 44
0

Thank you for your help, I definitely used it all. Instead of translating it all and printing in one line, I used the switch case to translate in the lines for me and then print the output every switch case.

//if file is open
    if (file.is_open())
    {
        //while there is a line to read
        while (getline(file, big))
        {
            letter = big[0];
            //switch case between b h and d
            switch (letter)
            {
                //binary
            case 'B':
                //get bitstring
                file >> bit;
                //convert the bit to ulong
                cout << "Binary: " << bit << " Hexidecimal: " << hex << bit.to_ulong() << " Decimal: " 
                    << dec << bit.to_ulong() << endl;
                break;
            case 'H':
                //define and get char
                char hexi;
                file >> hexi;
                //use hex table numbers from whatever char to translate
                //for decimal use hex table
                cout << "Binary: " << bitset<6>{(unsigned(tableConverter(hexi)))} << " Hexidecimal: "
                    << hex << hexi << " Decimal: " << to_string(tableConverter(hexi)) << endl;
                break;
            case 'D':
                //get number
                file >> number;
                //using normal bitset, hex, and dec operations
                cout << "Binary: " << bitset<6>{unsigned(number)}
                << " Hexidecimal: " << hex << number << " Decimal: " << dec << number << endl;
                break;
            default:
                break;

and for hex I couldn't figure out the translation that well so I just made a table where a=10, b=11, etc, and used that.