MAC address parsing - c++

I have a MAC address like "6F:e:5B:7C:b:a" that I want to parse and insert the implicit zeros before the :e:, :b:, :a.
I cannot use Boost at the moment but I have a rough solution. The solution splits on ':'. Then I count the characters between and if there is only one I insert a zero at the front.
I was wondering if anyone had a faster approach?

For the quick and dirty:
if (sscanf(text, "%x:%x:%x:%x:%x:%x",
&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) {
// handle error
}
Note that it does not check if numbers are really hex. Usual precautions of sscanf() applies.

First of all you could use script that would convert char to int quite fast, so:
unsigned char hex_to_int(const char c)
{
if( c >= 'a' && c <= 'f'){
return c - 'a' + 10;
}
if( c >= 'A' && c <= 'F'){
return c - 'A' + 10;
}
if( c >= '0' && c <= '9'){
return c - '0';
}
return 0;
}
Then you may create loop that will iterate over the string:
unsigned char mac[6]; /* Resulting mac */
int i; /* Iteration number */
char *buffer; /* Text input - will be changed! */
unsigned char tmp; /* Iteration variable */
for( i = 0; i < 6; ++i){
mac[i] = 0;
/*
* Next separator or end of string
* You may also want to limit this loop to just 2 iterations
*/
while( ((*buffer) != '\0') && ((*buffer) != ':'){
mac[i] <<= 4;
mac[i] |= hex_to_int( *buffer);
++buffer;
}
}
if( (i != 6) || (*buffer != NULL)){
// Error in parsing, failed to get to the 6th iteration
// or having trailing characters at the end of MAC
}
This function doesn't do any error checking, but it's probably the fastest solution you'll be getting.

Related

Checking the size of hashes in C++

As one would do with a blockchain, I want to check if a hash satisfies a size requirement. This is fairly easy in Python, but I am having some difficulty implementing the same system in C++. To be clear about what I am after, this first example is the python implementation:
difficulty = 25
hash = "0000004fbbc4261dc666d31d4718566b7e11770c2414e1b48c9e37e380e8e0f0"
print(int(hash, 16) < 2 ** (256 - difficulty))
The main problem I'm having is with these numbers - it is difficult to deal with such large numbers in C++ (2 ** 256, for example). This is solved with the boost/multiprecision library:
boost::multiprecision::cpp_int x = boost::multiprecision::pow(2, 256)
However, I cannot seem to find a way to convert my hash into a numeric value for comparison. Here is a generic example of what I am trying to do:
int main() {
string hash = "0000004fbbc4261dc666d31d4718566b7e11770c2414e1b48c9e37e380e8e0f0";
double difficulty = 256 - 25;
cpp_int requirement = boost::multiprecision::pow(2, difficulty);
// Something to convert hash into a number for comparison (converted_hash)
if (converted_hash < requirement) {
cout << "True" << endl;
}
return 1;
}
The hash is either being received from my web server or from a local python script, in which case the hash is read into the C++ program via fstream. Either way, it will be a string upon arrival.
Since I am already integrating python into this project, I am not entirely opposed to simply using the Python version of this algorithm; however, sometimes taking the easier path prevents you from learning, so unless this is a really cumbersome task, I would like to try to accomplish it in C++.
Your basic need is to compute how many zero bits exist before the first non-zero bit. This has nothing to do with multi-precision really, it can be reformulated into a simple counting problem:
// takes hexadecimal ASCII [0-9a-fA-F]
inline int count_zeros(char ch) {
if (ch < '1') return 4;
if (ch < '2') return 3;
if (ch < '4') return 2;
if (ch < '8') return 1;
return 0; // see ASCII table, [a-zA-Z] are all greater than '8'
}
int count_zeros(const std::string& hash) {
int sum = 0;
for (char ch : hash) {
int zeros = count_zeros(ch);
sum += zeros;
if (zeros < 4)
break;
}
return sum;
}
A fun optimization is to realize there are two termination conditions for the loop, and we can fold them together if we check for characters less than '0' which includes the null terminator and also will stop on any invalid input:
// takes hexadecimal [0-9a-fA-F]
inline int count_zeros(char ch) {
if (ch < '0') return 0; // change 1
if (ch < '1') return 4;
if (ch < '2') return 3;
if (ch < '4') return 2;
if (ch < '8') return 1;
return 0; // see ASCII table, [a-zA-Z] are all greater than '8'
}
int count_zeros(const std::string& hash) {
int sum = 0;
for (const char* it = hash.c_str(); ; ++it) { // change 2
int zeros = count_zeros(*it);
sum += zeros;
if (zeros < 4)
break;
}
return sum;
}
This produces smaller code when compiled with g++ -Os.

Convert char array to integer value

I'm having a bit of a trouble figuring out the correct calculation of WORD, DWORD etc.
I'm having kind of a knot in my brain, probably sitting on this problem for too long.
I'm reading a PE-section header. So far everything is ok.
Here is a sample output from a random .exe file:
File is 286 Kbytes large
PE-Signature [# 0x108]
0x00000100: ........ ........ 504500
Collect Information (PE file header):
[WORD] Mashinae Type :014C
[WORD] Number of Sections :0006
[DWORD] TimeStamp :5C6ECB00
[DWORD] Pointer to symbol table:00000000
[DWORD] Number of Symbols :00000000
[WORD] Size of optional header:00E0
Now, as you see the size of the "optional" header is 0x00E0, so I was trying to buffer that for later.
(Bc. it would make things faster to just read the complete header).
Where I'm having problems is the point where I am to convert the little-endian values to an actual integer.
I need to read the value from behind (so the second WORD [ 00 ] is actually the first value to be read).
The second value, however, needs to be shifted in some way (bc. significance of bytes), and this is where I am struggeling. I guess the solution is not that hard, I just ran out of wisdom lol.
Here is my draft for a function that should return an integer value with the value:
//get a specific value and safe it for later usage
int getValue(char* memory, int start, int end)
{
if (end <= start)
return 0;
unsigned int retVal = 0;
//now just add up array fields
for (int i = end; i >= start; i--)
{
fprintf(stdout, "\n%02hhx", memory[i]);
retVal &= (memory[i] << 8 * (i- start));
}
fprintf(stdout, "\n\n\n%d",retVal);
return retVal;
}
In other words, I need to parse an array of hex values (or chars) to an actual integer, but in respect of the significance of the bytes.
Also:
[Pointer to symbol table] and [Number of Symbols] seem to always be 0. I'm guessing this is due to the fact the binary is stripped of symbols, but I'm not sure since I am more an expert on Linux Binary Analysis. Is my asumption correct?
I really hope that this helps you. From what I understood so far this will grab the bytes that are within the start to end range and will place them in an integer:
// here I am converting the chars from hex to int
int getBitPattern(char ch)
{
if (ch >= 48 && ch <= 57)
{
return ch - '0';
}
else if (ch >= 65 && ch <= 70)
{
return ch - 55;
}
else
{
// this is in case of invalid input
return -1;
}
}
int getValue(const char* memory, int start, int end)
{
if (end <= start)
return 0;
unsigned int retVal = 0;
//now just add up array fields
for (int i = end, j = 0; i >= start; i--, ++j)
{
fprintf(stdout, "\n%02hhx", memory[i]);
// bitshift in order to insert the next set of 4 bits into their correct spot
retVal |= (getBitPattern(memory[i]) << (4*j));
}
fprintf(stdout, "\n\n\n%d", retVal);
return retVal;
}
boyanhristov96 helped a lot by pointing out the usage of the OR operator instead of AND and it was his / her effort that lead to this solution
A cast to (unsigned char) also had to be made before shifting.
If not, the variable will simply be shifted over it's maximum positive range,resulting in the value
0xFFFFE000 (4294959104)
instead of the desired 0x0000E000 (57344)
We have to left-shift by 8, because we want to shift 2 16bit values at once, like in
0x00FF00 << 8 ; // after operation is 0xFF0000
The final function also uses an OR, here is it:
//now with or operation and cast
int getValue(const char* memory, int start, int end)
{
if (end <= start)
return 0;
unsigned int retVal = 0;
//now just add up array fields
for (int i = end, j = end-start; i >= start; i--, --j)
{
fprintf(stdout, "\n%02hhx", memory[i]);
retVal |= ((unsigned char)(memory[i]) << (8 * j));
}
fprintf(stdout, "\n\n\n%u", retVal);
return retVal;
}
Many thanks for helping
EDIT 16.12.2019:
Returning back here for updated version of function;
It was necassary to rewrite it for 2 reasons:
1) The offset to PE-Header depends on the target binary, so we have to get this value first (at location 0x3c). Then, use a pointer to move from value to value from there.
2) The calculations where shambled, I corrected them, now it should work as intended. The second parameter is the byte-length, f.e. DWORD - 4 byte
Here you go:
//because file shambles
int getValuePNTR(const char* memory, int &start, int size)
{
DWORD retVal = 0;
//now just add up array fields
for (int i = start + size-1,j = size-1; j >= 0; --j ,i--)
{
fprintf(stdout, "\ncycle: %d, memory: [%x]", j, memory[i]);
if ((unsigned char)memory[i] == 00 && j > 0)
retVal <<= 8;
else
retVal |= ((unsigned char)(memory[i]) << (8 * j));
//else
//retVal |= ((unsigned char)(memory[i]));
}
//get the next field after this one
start += size;
return retVal;
}

What is the proper way of reading a composite key and a numeric value from an input file?

I'm trying to read a text file consisting of numerous strings which either represent a key/value (the key is a car number in a format of a letter/' '/3digits/' '/2letters; the value is unsigned long long; \t or ' ' between them) or an empty line, e.g.:
empty line
empty line
Z 999 ZZ 80
A 000 AA 124
Z 666 ZZ 42
I am using a cin.getline() function for that, reading a whole line and going through every character, saving a key and a value into an 'element' variable and pushing it into a vector afterwards. But for some reason the program seems to work unexpectedly, giving a weird output:
0
0
Z 999 ZZP 80
A 000 AA| 124
Z 666 ZZ* 42
So far I have been trying to analyse what could go wrong but I just can't see it. I've also tried using other tools like scanf() or cin.get() but failed miserably. Can someone please explain to me why this is happening and maybe show a more correct way of solving this task? Here is the code:
struct kv {
char key[8];
unsigned long long val;
};
int main()
{
std::vector<kv> data_vector;
kv element;
char str[64] = {};
char num[32] = {};
while (std::cin.getline(str, 64)) {
if (str[0] == ' ' || str[0] == '\n' || str[0] == '\t' || str[0] == EOF) {
continue;
}
size_t i = 0, n = 0;
for (i = 0; i < 8; i++)
element.key[i] = str[i];
while (!(str[i] >= '0' && str[i] <= '9'))
i++;
while (str[i] >= '0' && str[i] <= '9')
num[n++] = str[i++];
element.val = atoi(num);
data_vector.push_back(element);
for (n = 0; n < 32; n++)
num[n] = 0;
for (i = 0; i < 64; i++)
str[i] = 0;
}
for (size_t i = 0; i < data_vector.size(); i++) {
std::cout << data_vector[i].key << "\t" << data_vector[i].val << std::endl;
}
return 0;
}
EDIT: as #JimRhodes pointed out, changing char key[8] to char key[9] and adding element.key[8] = '\0' helped, but empty lines are still being processed the wrong way (as they should be ignored), giving an output of 0.
I think you may not be understanding how std::cin.getline() works. First of all, you do not want to test the return value of std::cin.getline() for true or false. You need to check for eof or fail. Secondly, std::cin.getline() discards the newline character so there is no need to check for '\n'. Your loop could start like this:
for ( ; ; )
{
str[0] = '\0'; // Clear any previous data
std::cin.getline(str, 64);
if ( std::cin.eof() )
{
break; // No more data, exit loop
}
if ( std::cin.fail() || (str[0] < 'A') )
{
continue; // Empty line or line does not start with a letter
}
. . .

C++ How to output the letters or numbers from input of letters or numbers

So let's say we have the following case: for ”12323465723” possible answers would be ”abcbcdfegbc” (1 2 3 2 3 4 6 5 7 2 3), ”awwdfegw” (1 23 23 4 6 5 7 23), ”lcwdefgw” (12 3 23 4 6 5 7 23), in this case, the user will input numbers from 1 to 26, not divided by any space and the program itself will suggest 3 ways of interpreting the numbers, getting the most of the combinations from 1 to 26 these being the values from a to z
As you can see this is edited, as this is the last part of the problem, Thank you all who have helped me this far, I've managed to solve half of my problem, only the above mentioned one is left.
SOLVED -> Thank you
This involves a decision between 0 to 2 outcomes at each step. The base cases are there are no more characters or none of them can be used. In the latter case, we backtrack to output the entire tree. We store the word in memory like dynamic programming. This naturally leads to a recursive algorithm.
#include <stdlib.h> /* EXIT */
#include <stdio.h> /* (f)printf */
#include <errno.h> /* errno */
#include <string.h> /* strlen */
static char word[2000];
static size_t count;
static void recurse(const char *const str) {
/* Base case when it hits the end of the string. */
if(*str == '\0') { printf("%.*s\n", (int)count, word); return; }
/* Bad input. */
if(*str < '0' || *str > '9') { errno = ERANGE; return; }
/* Zero is not a valid start; backtrack without output. */
if(*str == '0') return;
/* Recurse with one digit. */
word[count++] = *str - '0' + 'a' - 1;
recurse(str + 1);
count--;
/* Maybe recurse with two digits. */
if((*str != '1' && *str != '2')
|| (*str == '1' && (str[1] < '0' || str[1] > '9'))
|| (*str == '2' && (str[1] < '0' || str[1] > '6'))) return;
word[count++] = (str[0] - '0') * 10 + str[1] - '0' + 'a' - 1;
recurse(str + 2);
count--;
}
int main(int argc, char **argv) {
if(argc != 2)
return fprintf(stderr, "Usage: a.out <number>\n"), EXIT_FAILURE;
if(strlen(argv[1]) > sizeof word)
return fprintf(stderr, "Too long.\n"), EXIT_FAILURE;
recurse(argv[1]);
return errno ? (perror("numbers"), EXIT_FAILURE) : EXIT_SUCCESS;
}
When run on your original input, ./a.out 12323465723, it gives,
abcbcdfegbc
abcbcdfegw
abcwdfegbc
abcwdfegw
awbcdfegbc
awbcdfegw
awwdfegbc
awwdfegw
lcbcdfegbc
lcbcdfegw
lcwdfegbc
lcwdfegw
(I think you have made a transposition in lcwdefgw.)
According to ASCII table we know that from 65 to 90 it A to Z.
so below is the simple logic to achieve what you're trying.
int main(){
int n;
cin>>n;
n=n+64;
char a=(char) n;
if (a>=64 && a<=90)
cout<<a;
else cout<<"Error";
return 0;
}
If you want to count the occurencs of "ab" then this will do it:
int main()
{
char line[150];
int grup = 0;
cout << "Enter a line of string: ";
cin.getline(line, 150);
for (int i = 0; line[i] != '\0'; ++i)
{
if (line[i] == 'a' && line[i+1] == 'b')
{
++grup;
}
}
cout << "Occurences of ab: " << grup << endl;
return 0;
}
If you want to convert an int to an ASCII-value you can do that using this code:
// Output ASCII-values
int nr;
do {
cout << "\nEnter a number: ";
cin >> nr;
nr += 96; // + 96 because the ASCII-values of lower case letters start after 96
cout << (char) nr;
} while (nr > 96 && nr < 123);
Here I use the C style of casting values to keep things simple.
Also bear in mind ASCII-values: ASCII Table
Hope this helps.
This could be an interesting problem and you probably tagged it wrong, There's nothing specific to C++ here, but more on algorithm.
First of all the "decode" method that you described from numerical to alphabetical strings is ambiguious. Eg., 135 could be interpreted as either "ace" or "me". Is this simply an oversight or the intended question?
Suppose the ambiguity is just an oversight, and the user will enter numbers properly separated by say a white space (eg., either "1 3 5" or "13 5"). Let nstr be the numerical string, astr be the alphabetical string to count, then you would
Set i=0, cnt=0.
Read the next integer k from nstr (like in this answer).
Decode k into character ch
If ch == astr[i], increment i
If i == astr.length(), set i=0 and increment cnt
Repeat from 2 until reaching the end of nstr.
On the other hand, suppose the ambiguous decode is intended (the numerical string is supposed to have multiple ways to be decoded), further clarification is needed in order to write a solution. For example, how many k's are there in "1111"? Is it 1 or 2, given "1111" can be decoded either as aka or kk, or maybe even 3, if the counting of k doesn't care about how the entire "1111" is decoded?

How to store in a string and convert to character array?

Write a C++ program to perform addition of two hexadecimal numerals which are less than 100 digits long. Use arrays to store hexadecimal numerals as arrays of characters.the solution is to add the corresponding digits in the format of hexadecimal directly. From right to left, add one to the digit on the left if the sum of the current digits exceed 16. You should be able to handle the case when two numbers have different digits.
The correct way to get the input is to store as character array. You can either first store in a string and convert to character array, or you can use methods such as cin.getline(), getc(), cin.get() to read in the characters.
I don't know what is wrong with my program and it I don't know how to use the function getline() and eof()
char a[number1],b[number1],c[number2],h;
int m,n,p(0),q(0),k,d[number1],z[number1],s[number2],L,M;
cout<<"Input two hexadecimal numerals(both of them within 100 digits):\n";
cin.getline(a,100);
cin.getline(b,100);
int x=strlen(a) ;
int y=strlen(b);
for(int i=0;i<(x/2);i++)
{
m=x-1-i;
h=a[i];
a[i]=a[m];
a[m]=h;
}
for(int j=0;j<(y/2);j++)
{
n=y-1-j;
h=b[j];
b[j]=b[n];
b[n]=h;
}
if(x>y)
{
for(int o=0;o<x;o++)//calculate a add b
{
if(o>=(y-1))
z[o]=0;//let array b(with no character)=0
if(a[o]=='A')
d[o]=10;
else if(a[o]=='B')
d[o]=11;
else if(a[o]=='C')
d[o]=12;
else if(a[o]=='D')
d[o]=13;
else if(a[o]=='E')
d[o]=14;
else if(a[o]=='F')
d[o]=15;
else if(a[o]=='0')
d[o]=0;
else if(a[o]=='1')
d[o]=1;
else if(a[o]=='2')
d[o]=2;
else if(a[o]=='3')
d[o]=3;
else if(a[o]=='4')
d[o]=4;
else if(a[o]=='5')
d[o]=5;
else if(a[o]=='6')
d[o]=6;
else if(a[o]=='7')
d[o]=7;
else if(a[o]=='8')
d[o]=8;
else if(a[o]=='9')
d[o]=9;
if(b[o]=='A')
z[o]=10;
else if(b[o]=='B')
z[o]=11;
else if(b[o]=='C')
z[o]=12;
else if(b[o]=='D')
z[o]=13;
else if(b[o]=='E')
z[o]=14;
else if(b[o]=='F')
z[o]=15;
else if(b[o]=='0')
z[o]=0;
else if(b[o]=='1')
z[o]=1;
else if(b[o]=='2')
z[o]=2;
else if(b[o]=='3')
z[o]=3;
else if(b[o]=='4')
z[o]=4;
else if(b[o]=='5')
z[o]=5;
else if(b[o]=='6')
z[o]=6;
else if(b[o]=='7')
z[o]=7;
else if(b[o]=='8')
z[o]=8;
else if(b[o]=='9')
z[o]=9;
p=d[o]+z[o]+q;
if(p>=16)//p is the remained number
{
q=1;
p=p%16;
}
else
q=0;
if(p==0)
c[o]='0';
else if(p==1)
c[o]='1';
else if(p==2)
c[o]='2';
else if(p==3)
c[o]='3';
else if(p==4)
c[o]='4';
else if(p==5)
c[o]='5';
else if(p==6)
c[o]='6';
else if(p==7)
c[o]='7';
else if(p==8)
c[o]='8';
else if(p==9)
c[o]='9';
else if(p==10)
c[o]='A';
else if(p==11)
c[o]='B';
else if(p==12)
c[o]='C';
else if(p==13)
c[o]='D';
else if(p==14)
c[o]='E';
else if(p==15)
c[o]='F';
}
k=x+1;
if(q==1)//calculate c[k]
{
c[k]='1';
for(int f=0;f<=(k/2);f++)
{
m=k-f;
h=c[f];
c[f]=c[m];
c[m]=h;
}
}
else
{
for(int e=0;e<=(x/2);e++)
{
m=x-e;
h=c[e];
c[e]=c[m];
c[m]=h;
}
}
}
if(x=y)
{
for(int o=0;o<x;o++)//calculate a add b
{
if(a[o]=='A')
d[o]=10;
else if(a[o]=='B')
d[o]=11;
else if(a[o]=='C')
d[o]=12;
else if(a[o]=='D')
d[o]=13;
else if(a[o]=='E')
d[o]=14;
else if(a[o]=='F')
d[o]=15;
else if(a[o]=='0')
d[o]=0;
else if(a[o]=='1')
d[o]=1;
else if(a[o]=='2')
d[o]=2;
else if(a[o]=='3')
d[o]=3;
else if(a[o]=='4')
d[o]=4;
else if(a[o]=='5')
d[o]=5;
else if(a[o]=='6')
d[o]=6;
else if(a[o]=='7')
d[o]=7;
else if(a[o]=='8')
d[o]=8;
else if(a[o]=='9')
d[o]=9;
if(b[o]=='A')
z[o]=10;
else if(b[o]=='B')
z[o]=11;
else if(b[o]=='C')
z[o]=12;
else if(b[o]=='D')
z[o]=13;
else if(b[o]=='E')
z[o]=14;
else if(b[o]=='F')
z[o]=15;
else if(b[o]=='0')
z[o]=0;
else if(b[o]=='1')
z[o]=1;
else if(b[o]=='2')
z[o]=2;
else if(b[o]=='3')
z[o]=3;
else if(b[o]=='4')
z[o]=4;
else if(b[o]=='5')
z[o]=5;
else if(b[o]=='6')
z[o]=6;
else if(b[o]=='7')
z[o]=7;
else if(b[o]=='8')
z[o]=8;
else if(b[o]=='9')
z[o]=9;
p=d[o]+z[o]+q;
M=p;
if(p>=16)
{
q=1;
p=p%16;
}
else
q=0;
s[o]=p;
if(p==0)
c[o]='0';
else if(p==1)
c[o]='1';
else if(p==2)
c[o]='2';
else if(p==3)
c[o]='3';
else if(p==4)
c[o]='4';
else if(p==5)
c[o]='5';
else if(p==6)
c[o]='6';
else if(p==7)
c[o]='7';
else if(p==8)
c[o]='8';
else if(p==9)
c[o]='9';
else if(p==10)
c[o]='A';
else if(p==11)
c[o]='B';
else if(p==12)
c[o]='C';
else if(p==13)
c[o]='D';
else if(p==14)
c[o]='E';
else if(p==15)
c[o]='F';
}
k=x+1;
if(q==1)
{
c[k]='1';
for(int f=0;f<=(k/2);f++)
{
m=k-f;
h=c[f];
c[f]=c[m];
c[m]=h;
}
}
else
{
for(int e=0;e<=(x/2);e++)
{
m=x-e;
h=c[e];
c[e]=c[m];
c[m]=h;
}
}
}
Lets look at what cin.getline does:
Extracts characters from stream until end of line. After constructing
and checking the sentry object, extracts characters from *this and
stores them in successive locations of the array whose first element
is pointed to by s, until any of the following occurs (tested in the
order shown):
end of file condition occurs in the input sequence (in which case setstate(eofbit) is executed)
the next available character c is the delimiter, as determined by Traits::eq(c, delim). The delimiter is extracted (unlike basic_istream::get()) and counted towards gcount(), but is not stored.
count-1 characters have been extracted (in which case setstate(failbit) is executed).
If the function extracts no characters (e.g. if count < 1), setstate(failbit)
is executed. In any case, if count>0, it then stores a null character
CharT() into the next successive location of the array and updates
gcount().
The result of that is in all cases, s now points to a null terminated string, of at most count-1 characters.
In your usage, you have up to 99 digits, and can use strlen to count exactly how many. eof is not a character, nor it is a member function of char.
You then reverse in place the inputs, and go about your overly repetitious conversions.
However, it's much simpler to use functions, both those you write yourself and those provided by the standard.
// translate from '0' - '9', 'A' - 'F', 'a' - 'f' to 0 - 15
static std::map<char, int> hexToDec { { '0', 0 }, { '1', 1 }, ... { 'f', 15 }, { 'F', 15 } };
// translate from 0 - 15 to '0' - '9', 'A' - 'F'
static std::map<int, char> decToHex { { 0, '0' }, { 1, '1' }, ... { 15, 'F' } };
std::pair<char, bool> hex_add(char left, char right, bool carry)
{
// translate each hex "digit" and add them
int sum = hexToDec[left] + hexToDec[right];
// we have a carry from the previous sum
if (carry) { ++sum; }
// translate back to hex, and check if carry
return std::make_pair(decToHex[sum % 16], sum >= 16);
}
int main()
{
std::cout << "Input two hexadecimal numerals(both of them within 100 digits):\n";
// read two strings
std::string first, second;
std::cin >> first >> second;
// reserve enough for final carry
std::string reverse_result(std::max(first.size(), second.size()) + 1, '\0');
// traverse the strings in reverse
std::string::const_reverse_iterator fit = first.rbegin();
std::string::const_reverse_iterator sit = second.rbegin();
std::string::iterator rit = reverse_result.begin();
bool carry = false;
// while there are letters in both inputs, add (with carry) from both
for (; (fit != first.rend()) && (sit != second.rend()); ++fit, ++sit, ++rit)
{
std::tie(*rit, carry) = hex_add(*fit, *sit, carry);
}
// now add the remaining digits of first (will do nothing if second is longer)
for (; (fit != first.rend()); ++fit)
{
// we need to account for a carry in the last place
// potentially all the way up if we are adding e.g. "FFFF" to "1"
std::tie(*rit, carry) = hex_add(*fit, *rit++, carry);
}
// or add the remaining digits of second
for (; (sit != second.rend()); ++sit)
{
// we need to account for a carry in the last place
// potentially all the way up if we are adding e.g. "FFFF" to "1"
std::tie(*rit, carry) = hex_add(*sit, *rit++, carry);
}
// result has been assembled in reverse, so output it reversed
std::cout << reverse_result.reverse();
}
Regarding the text of your problem: “add one to the digit on the left if the sum of the current digits exceed 16” is wrong; it should be 15, not 16.
Regarding your code: I did not have the patience to read all your code, however:
I have noticed one long if/else. Use a switch (but you do not need one).
To find out if a character is a hex digit use isxdigit (#include <cctype>).
The user might input uppercase and lowercase characters: convert them to the same case using toupper/tolower.
To convert a hex digit to an integer:
if the digit is between ‘0’ and ‘9’ simply subtract ‘0’. This works because the codes for ‘0’, ‘1’… are 0x30, 0x31... (google ASCII codes).
if the digit is between ‘A’ and ‘F’, subtract ‘A’ and add 10.
Solving the problem:
“less than 100 digits long” This is a clear indication regarding how your data must be stored: a simple 100 long array, no std::string, no std::vector:
#define MAX_DIGITS 100
typedef int long_hex_t[MAX_DIGITS];
In other words your numbers are 100 digits wide, at most.
Decide how you store the number: least significant digit first or last? I would chose to store the least significant first. 123 is stored as {3,2,1,0,…0}
Use functions to simplify your code. You will need three functions: read, print and add:
int main()
{
long_hex_t a;
read( a );
long_hex_t b;
read( b );
long_hex_t c;
add( c, a, b );
print( c );
return 0;
}
The easiest function to write is add followed by print and read.
For read use get and putback to analyze the input stream: get extracts the next character from stream and putback is inserting it back in stream (if we do not know how to handle it).
Here it is a full solution (try it):
#include <iostream>
#include <cctype>
#define MAX_DIGITS 100
typedef int long_hex_t[MAX_DIGITS];
void add( long_hex_t c, long_hex_t a, long_hex_t b )
{
int carry = 0;
for ( int i = 0; i < MAX_DIGITS; ++i )
{
int t = a[i] + b[i] + carry;
c[i] = t % 16;
carry = t / 16;
}
}
void print( long_hex_t h )
{
//
int i;
// skip leading zeros
for ( i = MAX_DIGITS - 1; i >= 0 && h[i] == 0; --i )
;
// all zero
if ( i < 0 )
{
std::cout << '0';
return;
}
// print remaining digits
for ( i; i >= 0; --i )
std::cout << char( h[i] < 10 ? h[i] + '0' : h[i] - 10 + 'A' );
}
void read( long_hex_t h )
{
// skip ws
std::ws( std::cin );
// skip zeros
{
char c;
while ( std::cin.get( c ) && c == '0' )
;
std::cin.putback( c );
}
//
int count;
{
int i;
for ( i = 0; i < MAX_DIGITS; ++i )
{
char c;
if ( !std::cin.get( c ) )
break;
if ( !std::isxdigit( c ) )
{
std::cin.putback( c );
break;
}
c = std::toupper( c );
h[i] = c <= '9'
? ( c - '0' )
: ( c - 'A' + 10 );
}
count = i;
}
// reverse
for ( int i = 0, ri = count - 1; i < count / 2; ++i, --ri )
{
int t = h[i];
h[i] = h[ri];
h[ri] = t;
}
// fill the rest with zero
for ( int i = count; i < MAX_DIGITS; ++i )
h[i] = 0;
}
int main()
{
long_hex_t a;
read( a );
long_hex_t b;
read( b );
long_hex_t c;
add( c, a, b );
print( c );
return 0;
}
This is a long answer. Because you have much bug in your code. Your using of getline is ok. But your are calling a eof() like e.eof() which is wrong. If you have looked at your compilation error, you would see that it was complaining about calling eof() on the variable e because it is of non-class type. Simple meaning it is not an object of some class. You cannot put the dot operator . on primitive types like that. I think what you are wanting to do, is to terminate the loop when you have reached the end of line. So that index1 and index2 can get the length of the string input. If I were you, I would just use C++ builtin strlen() function for that. And in the first place, you should use C++ class string to handle strings. Also strings have a null - terminating character '\0' at the end of them. If you don't know about it, I suggest you take some time to read about strings.
Secondly, you have many bugs and errors in your code. The way you are reversing your string is not correct. Ask yourself, what are the contents of the arrays a and b at position which have higher index than the length of the string? You should use reverse() for reversing strings and arrays.
You have errors on adding loop also. Note, you are changing the arrays value when they are A, B, C, D, and so on for hexadecimal values with the corresponding decimal values 10,11,12,13 and so on. But you should change the values for the character '0' - '9' also. Because when the array holds '0' it is not integer 0. But is is ASCII '0' which has integer value of 48. And the character '1' has integer value of 49 and so on. You want to replace this values with corresponding integer values also. When you are also storing the result values in c, you are only handling only those values which are above 9 and replacing them with corresponding characters. You should also replace the integers 0 - 9 with there corresponding ASCII characters. Also don't forget to put a null terminating character at the end of the result.
Also, when p is getting larger than 15, you are only changing your carry, but you should also change p accordingly.
I believe you can reverse the result array c in a much more elegant way. By only reversing when the calculation has been performed totally. You can simple call reverse() for that.
I believe you can think hard a little bit more, and write the code in the right way. I have a few suggestions for you, don't use variable names like a,b,c,o. Try to name variables with what are they really doing. Also, you can improve your algorithm and shorten your code and headache with one simple change in the algorithm. First find the length of a and then find the length of b. If there lengths are unequal, find out which has lesser length. Then add 0s in front of it to make both lengths equal. Now, you can simply start from the back, and perform the addition. Also, you should use builtin methods like reverse() , swap() and also string class to make your life easier ;)
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int main(){
string firstVal,secondVal;
cout<<"Input two hexadecimal numerals(both of them within 100 digits):\n";
cin >> firstVal >> secondVal;
//Adjust the length.
if(firstVal.size() < secondVal.size()){
//Find out the number of leading zeroes needed
int leading_zeroes = secondVal.size() - firstVal.size();
for(int i = 0; i < leading_zeroes; i++){
firstVal = '0' + firstVal;
}
}
else if(firstVal.size() > secondVal.size()){
int leading_zeroes = firstVal.size() - secondVal.size();
for(int i = 0; i < leading_zeroes; i++){
secondVal = '0' + secondVal;
}
}
// Now, perform addition.
string result;
int digit_a,digit_b,carry=0;
for(int i = firstVal.size()-1; i >= 0; i--){
if(firstVal[i] >= '0' && firstVal[i] <= '9') digit_a = firstVal[i] - '0';
else digit_a = firstVal[i] - 'A' + 10;
if(secondVal[i] >= '0' && secondVal[i] <= '9') digit_b = secondVal[i] - '0';
else digit_b = secondVal[i] - 'A' + 10;
int sum = digit_a + digit_b + carry;
if(sum > 15){
carry = 1;
sum = sum % 16;
}
else{
carry = 0;
}
// Convert sum to char.
char char_sum;
if(sum >= 0 && sum <= 9) char_sum = sum + '0';
else char_sum = sum - 10 + 'A';
//Append to result.
result = result + char_sum;
}
if(carry > 0) result = result + (char)(carry + '0');
//Result is in reverse order.
reverse(result.begin(),result.end());
cout << result << endl;
}