Hexidecimal to Decimal conversion via string.

I'm trying to write a function that takes a hexidecimal value in string-form as an argument and coverts it into a decimal value. I haven't started writing error code yet, but even accepting an argument which shouldn't cause an error causes the command prompt to crash. What's wrong with this code?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
 #include <cstdlib>
#include <iostream>
#include <string>

using namespace std;

int parseHex(const string &hexString){
        int decValue[hexString.length()];
        int finalDec = 0;
        unsigned int *exponentCounter;
        int temp = hexString.length()-1;
        
        for(int i = 0; i<=hexString.length()-1; i++)           //string position loop
        {
                if(hexString.at(i) == ('0'||'1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'||'9'))      //character comparison
                {   
                      decValue[i] = hexString.at(i)-'0';     //sets decValue[i] to value of digit character
                }
                if(hexString.at(i) == ('A'||'B'||'C'||'D'||'E'||'F'))         //character comparison
                {   
                      decValue[i] = hexString.at(i)-'0'-7;     //sets decValue[i] to value of letter character in decimal
                }

                exponentCounter[i] = temp--;
        }
        
        for(int i = 0; i <= hexString.length()-1; i++)
        {
                temp = 16;
                int a = 0;
                if((exponentCounter[i] > 1) && (a < exponentCounter[i]-1)){
                       temp *= 16;
                       a++;
                }else if(exponentCounter[i] == 1){temp = 16;
                }else if(exponentCounter[i] == 0){temp = 1;}
                finalDec += decValue[i] * temp;
        }
        return finalDec;
}


int main(int argc, char *argv[])
{
 string hexNum;
 cout << "Enter a hexidecimal value: ";
 cin >> hexNum;
 cout << "\n" << "Your value in decimal is: " << parseHex(hexNum) << "\n";
  
    system("PAUSE");
    return EXIT_SUCCESS;
}
hexString.at(i) == ('0'||'1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'||'9')
hexString.at(i) == ('A'||'B'||'C'||'D'||'E'||'F')


Although this would be a lovely piece of syntactic sugar if C++ allowed this to work as you're probably intending it to... sadly, this likely doesn't do what you think it does.

The whole right side of these expression will always evaluate to true. The left side will also always evaluate to true UNLESS the character at i is a null character (0x0).

You may wish to check instead if the character at i is greater than or equal to a certain character AND less than or equal to a certain character. Remember, all character literals have integer values. There is also the std::isdigit(char) function in <cctype> for the first statement.

Examples:

if(a_char >= 'w' && a_char <= 'z')

if(a_char >= '1' && a_char <= '3')

Good luck.

-Albatross
Last edited on
That's how my code was written before and it wasn't working... Hrmm

It's changed back.

1
2
3
4
5
6
7
8
9
10
11
12
13
 for(int i = 0; i<=hexString.length()-1; i++)           //string position loop
        {
                if(hexString.at(i) <= '9')      //character comparison
                {   
                      decValue[i] = hexString.at(i)-'0';     //sets decValue[i] to value of digit character
                }
                if(hexString.at(i) >= 'A' && hexString.at(i) <= 'F')         //character comparison
                {   
                      decValue[i] = hexString.at(i)-'0'-7;     //sets decValue[i] to value of letter character in decimal
                }

                exponentCounter[i] = temp--;
        }
Interesting. There were some small logic errors, but mostly the issue right now is that it crashes if I put it in a function, but if the code in in int main() it works fine... Why is this?
Last edited on
How didn't I notice that?

You never allocate memory for your exponentCounter pointer (on line 10 of your original code), and that pointer is uninitialized and not guaranteed to point to memory that you have access to. Thus, you open up a major risk for a segfault and the program's behavior is undefined.

You can either new an array once you know the length of hexString (make sure to delete what you new) or use an STL container like std::vector to store your data.

-Albatross
Oh, whoops, I keep doing that in my code. >< Thanks Albatross.
Alright, final problem. Implementing error code is confusing me somewhat. Here's the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <cstdlib>
#include <iostream>
#include <string>
#include "hexExcept.h"

using namespace std;

int parseHex(const string &hexString){
        int decValue[hexString.length()];
        int finalDec = 0;
        int *exponentCounter = new int[hexString.length()];
        int temp = hexString.length()-1;
        
        for(int i = 0; i < hexString.length(); i++)           //string position loop
        {
                int errorBit = 0;
                if(hexString.at(i) <= '9')      //character comparison
                {   
                      decValue[i] = hexString.at(i)-'0';     //sets decValue[i] to value of digit character
                      errorBit++;
                }
                if(hexString.at(i) >= 'A' && hexString.at(i) <= 'F')         //character comparison
                {   
                      decValue[i] = hexString.at(i)-'0'-7;     //sets decValue[i] to value of letter character in decimal
                      errorBit++;
                }

                if(errorBit == 0){throw hexException(hexString);}

                exponentCounter[i] = temp;
                temp--;
        }
        
        for(int i = 0; i < hexString.length(); i++)
        {
                temp = 16;
                int a = 0;
                while((exponentCounter[i] > 1) && (a < exponentCounter[i]-1)){
                       temp *= 16;
                       a++;
                }
                if(exponentCounter[i] == 1){temp = 16;}
                if(exponentCounter[i] == 0){temp = 1;}
                finalDec += decValue[i] * temp;
        }
        delete exponentCounter;
        return finalDec;
}

int main(int argc, char *argv[])
{
    
    string hexNum;
    cout << "Enter a hexidecimal value: ";
    cin >> hexNum;
    
 cout << "\n" << "Your value in decimal is: " << parseHex(hexNum) << "\n";
    
    system("PAUSE");
    return EXIT_SUCCESS;
}


hexExcept.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdexcept>
using namespace std;

class hexException: public invalid_argument
{
private:
  string &hexString;
public:
  hexException(const string &hexString)
    : invalid_argument("Invalid Hex String")  
  {
      for(int i = 0; i < this->hexString.length(); i++)
      {hexString.at(i) = this->hexString.at(i);}
  }
  string getHexString()
  {
    return hexString;
  }

};


Getting an unitialized reference member at 11 in hexExcept that's confusing me somewhat.
That reference needs to be initialized in the initializer list for the constructor.

Also, your error-detection code only checks the first character of the string. Do you see why, and do you see how to potentially fix it?

-Albatross
I understand, but I'm not sure what it's supposed to be initialized as.... Honestly, when I say "confused" I mean totally very quite completely so I'm afraid.
A reference is like a pointer that you don't have to dereference but you can't reassign. That reference needs to point to something... so why not make it initialize it with the erroneous string variable that you're passing into your constructor?

EDIT: I just noticed that the constructor takes a const string& while the private member is a plain string&. You're going to need to decide which approach to take.

-Albatross
Last edited on
Right, I get that, I'm just kinda confused about how I'm supposed to do it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdexcept>
using namespace std;

class hexException: public runtime_error
{
private:
  const string &hexString;
public:
  hexException(const string &hexString)
    : hexString(&hexString), runtime_error("Invalid Hex String"){}    // ERROR: invalid initialization of reference of type 'const std::string&' from expression of type 'const std::string*' 
    
  string getHexString()
  {
    return hexString;
  }

};
Last edited on
The exception object needs to make a copy of the string.

When an exception is thrown (as in throw hexException(hexString);), the function scope is exited and all local objects (including the string hexString) are destroyed. Without a copy, the exception object would hold a dangling reference to a string that has been destroyed.

Something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <sstream>
#include <stdexcept>

struct hex_parse_error : std::invalid_argument
{
    explicit hex_parse_error( const std::string& str )
        : std::invalid_argument( "invalid hex string" ), bad_hex_string(str) {}

    const std::string bad_hex_string ;
};

unsigned int parse_hex( const std::string& str )
{
    std::istringstream stm(str) ;
    unsigned int v ;
    if( stm >> std::hex >> v && stm.eof() ) return v ;
    throw  hex_parse_error(str) ; // parse failed
}

int main()
{
    const std::string test[] = { "1000", "ffff", "abcd123", "abcy123" } ;

    try
    {
        for( const std::string& str : test )
        {
             std::cout << str << " : " ;
             std::cout << parse_hex(str) << '\n' ;
        }
    }

    catch( const hex_parse_error& e )
    {
        std::cerr << "parse error - invalid_argument: '" << e.bad_hex_string << "'\n" ;
    }
}

http://coliru.stacked-crooked.com/a/5550f1cdc15a65db
I think you don't need a function to parse from decimal to hexadecimal.

1
2
3
4
5
6
7
8
9
#include <cstdio>

int main(){
	int k;
	printf("Enter a hexadecimal value: ");
	scanf("%X",&k);
	printf("\nDecimal value for %X is %d", k,k);
	return 0;
}


I think you'll understand it.
This is all what you need, isn't it?
Topic archived. No new replies allowed.