Run-length decompression using C++ - c++

I have a text file with a string which I encoded.
Let's say it is: aaahhhhiii kkkjjhh ikl wwwwwweeeett
Here the code for encoding, which works perfectly fine:
void Encode(std::string &inputstring, std::string &outputstring)
{
for (int i = 0; i < inputstring.length(); i++) {
int count = 1;
while (inputstring[i] == inputstring[i+1]) {
count++;
i++;
}
if(count <= 1) {
outputstring += inputstring[i];
} else {
outputstring += std::to_string(count);
outputstring += inputstring[i];
}
}
}
Output is as expected: 3a4h3i 3k2j2h ikl 6w4e2t
Now, I'd like to decompress the output - back to original.
And I am struggling with this since a couple days now.
My idea so far:
void Decompress(std::string &compressed, std::string &original)
{
char currentChar = 0;
auto n = compressed.length();
for(int i = 0; i < n; i++) {
currentChar = compressed[i++];
if(compressed[i] <= 1) {
original += compressed[i];
} else if (isalpha(currentChar)) {
//
} else {
//
int number = isnumber(currentChar).....
original += number;
}
}
}
I know my Decompress function seems a bit messy, but I am pretty lost with this one.
Sorry for that.
Maybe there is someone out there at stackoverflow who would like to help a lost and beginner soul.
Thanks for any help, I appreciate it.

Assuming input strings cannot contain digits (this cannot be covered by your encoding as e. g. both the strings "3a" and "aaa" would result in the encoded string "3a" – how would you ever want to decompose again?) then you can decompress as follows:
unsigned int num = 0;
for(auto c : compressed)
{
if(std::isdigit(static_cast<unsigned char>(c)))
{
num = num * 10 + c - '0';
}
else
{
num += num == 0; // assume you haven't read a digit yet!
while(num--)
{
original += c;
}
}
}
Untested code, though...
Characters in a string actually are only numerical values, though. You can consider char (or signed char, unsigned char) as ordinary 8-bit integers as well. And you can store a numerical value in such a byte, too. Usually, you do run length encoding exactly that way: Count up to 255 equal characters, store the count in a single byte and the character in another byte. One single "a" would then be encoded as 0x01 0x61 (the latter being the ASCII value of a), "aa" would get 0x02 0x61, and so on. If you have to store more than 255 equal characters you store two pairs: 0xff 0x61, 0x07 0x61 for a string containing 262 times the character a... Decoding then gets trivial: you read characters pairwise, first byte you interpret as number, second one as character – rest being trivial. And you nicely cover digits that way as well.

#include "string"
#include "iostream"
void Encode(std::string& inputstring, std::string& outputstring)
{
for (unsigned int i = 0; i < inputstring.length(); i++) {
int count = 1;
while (inputstring[i] == inputstring[i + 1]) {
count++;
i++;
}
if (count <= 1) {
outputstring += inputstring[i];
}
else {
outputstring += std::to_string(count);
outputstring += inputstring[i];
}
}
}
bool alpha_or_space(const char c)
{
return isalpha(c) || c == ' ';
}
void Decompress(std::string& compressed, std::string& original)
{
size_t i = 0;
size_t repeat;
while (i < compressed.length())
{
// normal alpha charachers
while (alpha_or_space(compressed[i]))
original.push_back(compressed[i++]);
// repeat number
repeat = 0;
while (isdigit(compressed[i]))
repeat = 10 * repeat + (compressed[i++] - '0');
// unroll releat charachters
auto char_to_unroll = compressed[i++];
while (repeat--)
original.push_back(char_to_unroll);
}
}
int main()
{
std::string deco, outp, inp = "aaahhhhiii kkkjjhh ikl wwwwwweeeett";
Encode(inp, outp);
Decompress(outp, deco);
std::cout << inp << std::endl << outp << std::endl<< deco;
return 0;
}

The decompression can't possibly work in an unambiguous way because you didn't define a sentinel character; i.e. given the compressed stream it's impossible to determine whether a number is an original single number or it represents the repeat RLE command. I would suggest using '0' as the sentinel char. While encoding, if you see '0' you just output 010. Any other char X will translate to 0NX where N is the repeat byte counter. If you go over 255, just output a new RLE repeat command

Related

Smallest Binary String not Contained in Another String

The question description is relatively simple, an example is given
input: 10100011
output: 110
I have tried using BFS but I don't think this is an efficient enough solution (maybe some sort of bitmap + sliding window solution?)
string IntToString(int a)
{
ostringstream temp;
temp << a;
return temp.str();
}
bool is_subsequence(string& s, string& sub) {
if(sub.length() > s.length()) return false;
int pos = 0;
for(char c : sub)
{
pos = s.find(c, pos);
if(pos == string::npos) return false;
++pos;
}
return true;
}
string shortestNotSubsequence(string& s) {
Queue q(16777216);
q.push(0);
q.push(1);
while(!q.empty())
{
string str;
int num = q.front; q.pop();
str = IntToString(num);
if(!is_subsequence(s, str)) return str;
string z = str + '0';
string o = str + '1';
q.push(stoi(str+'0'));
q.push(stoi(str+'1'));
}
return "";
}
int main() {
string N;
cin >> N;
cout << shortestNotSubsequence(N) << endl;
return 0;
}
You can do this pretty easily in O(N) time.
Let W = ceiling(log2(N+1)), where N is the length of the input string S.
There are 2W possible strings of length W. S must have less than N of them as substrings, and that's less than 2W, so at least one string of length W must not be present in S.
W is also less than the number of bits in a size_t, and it only takes O(N) space to store a mask of all possible strings of length W. Initialize such a mask to 0s, and then iterate through S using the lowest W bits in a size_t as a sliding window of the substrings you encounter. Set the mask bit for each substring you encounter to 1.
When you're done, scan the mask to find the first 0, and that will be a string of length W that's missing.
There may also be shorter missing strings, though, so merge the mask bits in pairs to make a mask for the strings of length W-1, and then also set the mask bit for the last W-1 bits in S, since those might not be included in any W-length string. Then scan the mask for 0s to see if you can find a shorter missing string.
As long as you keep finding shorter strings, keep merging the mask for smaller strings until you get to length 1. Since each such operation divides the mask size in 2, that doesn't affect the overall O(N) time for the whole algorithm.
Here's an implementation in C++
#include <string>
#include <vector>
#include <algorithm>
std::string shortestMissingBinaryString(const std::string instr) {
const size_t len = instr.size();
if (len < 2) {
if (!len || instr[0] != '0') {
return std::string("0");
}
return std::string("1");
}
// Find a string size guaranteed to be missing
size_t W_mask = 0x3;
unsigned W = 2;
while(W_mask < len) {
W_mask |= W_mask<<1;
W+=1;
}
// Make a mask of all the W-length substrings that are present
std::vector<bool> mask(W_mask+1, false);
size_t lastSubstr=0;
for (size_t i=0; i<len; ++i) {
lastSubstr = (lastSubstr<<1) & W_mask;
if (instr[i] != '0') {
lastSubstr |= 1;
}
if (i+1 >= W) {
mask[lastSubstr] = true;
}
}
//Find missing substring of length W
size_t found = std::find(mask.begin(), mask.end(), false) - mask.begin();
// try to find a shorter missing substring
while(W > 1) {
unsigned testW = W - 1;
W_mask >>= 1;
// calculate masks for length testW
for (size_t i=0; i<=W_mask; i++) {
mask[i] = mask[i*2] || mask[i*2+1];
}
mask.resize(W_mask+1);
// don't forget the missing substring at the end
mask[lastSubstr & W_mask] = true;
size_t newFound = std::find(mask.begin(), mask.end(), false) - mask.begin();
if (newFound > W_mask) {
// no shorter string
break;
}
W = testW;
found = newFound;
}
// build the output string
std::string ret;
for (size_t bit = ((size_t)1) << (W-1); bit; bit>>=1) {
ret.push_back((found & bit) ? '1': '0');
}
return ret;
}

How to set my decode function to take in the encoded string?

I'm working on my decode function and I've hit a wall. I dont know if I should pass in the encode function or create a class. My encode function compresses a string, I need the decode function to take that encoded string and expand it.
I've been told that it was the same as doing the encode function. I'm not sure where to go here.
#include<iostream>
#include<string>
using namespace std;
string encode(string str)
{
string encoding = "";
int count;
for (int i = 0; str[i]; i++)
{
count = 1;
while (str[i]==str[i+1])
{
count++, i++;
}
encoding += to_string(count) + str[i];
}
return encoding;
}
//Im trying to decode the encoded string
//take in a string and count how many of the same characters there are and print
//e.g
// a3b4c1......would be decoded as aaabbbbc
string decode(string in)
{
string decoding = "";
char s;
int count;
for (int i = 0; i<in; i++)
{
count = 1;
if (in[i] == 'A')
count++, i++;
}
}
int main()
{
string str = "ABBCC";
cout << encode(str);
//cout << decode(str);
}
// My encode functions executes as needed. 1A2B2C
Your encoding is not valid because the encoding of "1a" produces "111a" which is also the encoding of 111 consecutive 'a', you need to add a separator between the count and the character
In your decode function you only manage the special case of A and you do not extract the count the encoder put
Note also in
for (int i = 0; i<in; i++)
{
count = 1;
if (in[i] == 'A')
count++, i++;
}
you always reset count to 1
You need to first extract the count (with the problem I signal at the beginning of my answer) then duplicate the letter 'count' times
It is useless to do string encoding = ""; because the constructor of std::string make it empty, can be just string encoding;
You need to decode an encoded string, this is not what you do in your main where you try to decode the initial string
A corrected version can be :
#include<iostream>
#include<string>
#include <sstream>
using namespace std;
string encode(string str)
{
stringstream encoding;
int count;
for (int i = 0; str[i]; i++)
{
count = 1;
while (str[i]==str[i+1])
{
count++, i++;
}
encoding << count << ' ' << str[i];
}
return encoding.str();
}
string decode(string in)
{
stringstream is(in);
string decoding;
int n;
char c;
while (is >> n >> c)
{
while (n--)
decoding += c;
}
return decoding;
}
int main()
{
cout << encode("ABBCC2a") << endl;
cout << decode(encode("ABBCC2a")) << endl;
return 0;
}
Compilation and execution :
pi#raspberrypi:/tmp $ g++ -pedantic -Wall -Wextra e.cc
pi#raspberrypi:/tmp $ ./a.out
1 A2 B2 C1 21 a
ABBCC2a
Run-length-encoding – but in a very strange way!
encoding += to_string(count) + str[i];
Let's encode string "sssssssssss"; it will result in a string with array representation of
{ '1', '1', 's', 0 } // string "11s"
(I chose this representation deliberately, you'll see later...)
The problem is that you wouldn't be able to encode strings containing digits: "1s" will result in
{ '1', '1', '1', 's', 0 } // string "111s"
but how would you want to distinguish if we need to decode back to "1s" or into a string solely containing 111 s characters?
Try it differently: A character actually is nothing more than a number as well, e. g. letter s is represented by numerical value 115 (in ASCII and compatible, at least), the digit 7 (as a character!) by numerical value 55. So you can simply add the value as character:
encoding += static_cast<unsigned char>(count) + str[i];
There are some corner cases, unsigned char cannot hold numbers greater than 255, so a string having more subsequent equal characters would have to be encoded e. g. as
{ 255, 's', 7, 's', 0 } // 262 times letter s
Note the representation; 255 and 7 aren't even printable characters! Now let's assume we encoded a string with 115 times the letter s:
{ 115, 's', 0 } // guess, as string, this would be "ss"...
To catch, you would simply check explicitly your counter for reaching maximum value.
Now decoding gets much simpler:
size_t i = 0;
while(i < encoded.size())
{
unsigned char n = encoded[i];
++i;
while(n--)
decoded += encoded[i];
++i;
}
Totally simple: first byte always as number, second one as character...
If you insist on numbers being encoded as string (and encode only strings not containing digits), you could use a std::istringstream:
std::istringstream s(encoded);
unsigned int n;
char c;
while(s >> n >> c)
{
while(n--)
decoded += encoded[i];
}
OK, it is not symmetric to your encoding function. You could adapt the latter to be so, though:
std::ostringstream s;
for(;;) // ...
{
unsigned int count = 1;
// ...
s << count << str[i];
}

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;
}

String subscript out of range (Visual Studio 2013)

I understand that questions with this title/problem have been asked numerous times before (here,here and many others). Here is my code followed by what all I have done to remove the error:
CaesarCipher.h
#ifndef CAESARCIPHER_H
#define CAESARCIPHER_H
#include <ctime>
#include <string>
using namespace std;
// Write your class CaesarCipher here.
class CaesarCipher
{
public:
CaesarCipher();
string Encode(string plainString);
string Decode(string encryptedString);
private:
int key1, key2;
char Encode(char normalChar)const;
char Decode(char encodedChar)const;
};
#endif
CaesarCipher.cpp
#include "stdafx.h"
#include "CaesarCipher.h"
using namespace std;
// Implement the member functions of class CaesarCipher.
CaesarCipher::CaesarCipher()
{
//Random initialization of integer key1
//srand(time(0));
srand((unsigned int)time(0));
int value1 = rand() % 10;
int sign1 = rand() % 2;
sign1 = sign1 == 0 ? -1 : 1;
int key1 = value1 * sign1;
//Random initialization of integer key2
//srand(time(0));
srand((unsigned int)time(0));
int value2 = rand() % 10;
int sign2 = rand() % 2;
sign2 = sign2 == 0 ? -1 : 1;
int key2 = value2 * sign2;
}
char CaesarCipher::Encode(char normalChar) const
{
int result=0;
int charValue = normalChar; //get the ASCII decimal value of character
if (charValue == 32) // if characeter is a space, we leave it
{
result = 32;
}
else
{
if (key1 > 0)
{
result = char(int(charValue + key1 - 97) % 26 + 97); // find the integer value of char after rotating it with key1(positive)
}
if (key1 < 0)
{
result = char(int(charValue -key1 - 97) % 26 + 97); // find the integer value of char after rotating it with key1(negative)
}
if (key2 > 0)
{
result += char(int(charValue + key2 - 97) % 26 + 97); // find the updated integer value of char after rotating it with key2(positive)
}
if (key2 < 0)
{
result += char(int(charValue - key2 - 97) % 26 + 97); // find the updated integer value of char after rotating it with key2(negative)
}
}
return result; // returning the integer value which will be typecasted into a char(encoded char)
}
char CaesarCipher::Decode(char encodedChar) const
{
int result = 0;
int charValue = encodedChar; //get the ASCII decimal value of encoded character
if (charValue == 32) // if characeter is a space, we leave it unchanged
{
result = 32;
}
else
{
if (key1 > 0)
{
result = char(int(charValue - key1 - 97) % 26 + 97); // find the integer value of encoded char after rotating it with key1(positive) in opposite direction
}
if (key1 < 0)
{
result = char(int(charValue + key1 - 97) % 26 + 97); // find the integer value of encoded char after rotating it with key1(negative) in opposite direction
}
if (key2 > 0)
{
result += char(int(charValue - key2 - 97) % 26 + 97); // find the updated integer value of encoded char after rotating it with key2(positive) in opposite direction
}
if (key2 < 0)
{
result += char(int(charValue + key2 - 97) % 26 + 97); // find the updated integer value of encoded char after rotating it with key2(negative) in opposite direction
}
}
return result; // returning the integer value which will be typecasted into a char(decrypted char)
}
string CaesarCipher::Encode(string plainString)
{
int length = plainString.length(); //gets the length of the
input string
string encodedString; // variable to hold the final encrypted string
for (int i = 0; i < length; i++)
{
encodedString[i] = Encode(plainString[i]); // encrypting the string one character at a time
}
return encodedString; // return the final encoded string
}
string CaesarCipher::Decode(string encryptedString)
{
int length = encryptedString.length(); //gets the length of the input encrypted string
string decodedString; // variable to hold the final decrypted string
for (int i = 0; i < length; i++)
{
decodedString[i] = Decode(encryptedString[i]); // decrypting the string one character at a time
}
return decodedString; // return the final decoded string
}
I am using two keys to cipher the text (key1 followed by key2), if it helps in any way.
Main.cpp
#include "stdafx.h"
#include "CaesarCipher.h"
#include <fstream>
#include <iostream>
int main() {
// File streams
ifstream fin("input.txt");
ofstream fout("output.txt");
if (!fin.good()) {
cout << "Error: file \"input.txt\" does not exist!" << endl;
return -1;
}
string original[20], encrypted[20], decrypted[20];
int i = 0; // will store the number of lines in the input file
CaesarCipher cipher; // an object of CaesarCipher class
// Read the sentences from the input file and save to original[20].
// Hint: use getline() function.
while (!fin.eof())
{
getline(fin, original[i]); // Reading a line from input.txt file
encrypted[i] = cipher.Encode(original[i]); // Encrypt the sentences and save to encrypted[20]
decrypted[i] = cipher.Decode(encrypted[i]); // Decrypt the sentences and save to decrypted[20]
i++;
}
//first output all the encrypted lines
for (int j = 0; j < i; j++)
{
fout << "Encrypted sentences:\n";
fout << encrypted[j]<<"\n";
}
//now output all the decrypted lines
for (int j = 0; j < i; j++)
{
fout << "Decrypted sentences:\n";
fout << decrypted[j] << "\n";
}
// Close the files and end the program.
fin.close();
fout.close();
cout << "done!";
return 0;
}
The error which i am getting isExpression: string subscript out of range. Now i understand that i am trying to iterate beyond the limits of the string (somewhere probably in CaesarCipher.cpp in Encoder or Decoder function).
I have tried to change the limits on i without any effect.
I have tried to use size() instead of length() (in desperacy inspite knowing they do the same thing).
I would really appreciate if you can pin-point any thing in particular which might be causing this error and i will try and change it by myself and see the results.
And if you can also tell, how to avoid such errors in future that will also be of great value to me.
CaesarCipher::Encode() is not allocating any memory for the character data of encodedString, so the loop has nothing valid to access with encodedString[i]. To fix that, either:
Use string encodedString = plainString; to make a copy of the input string, then the loop can manipulate the copied data:
string CaesarCipher::Encode(string plainString) {
int length = plainString.length(); //gets the length of the input string
string encodedString = plainString; // variable to hold the final encrypted string
for (int i = 0; i < length; i++) {
encodedString[i] = Encode(encodedString[i]); // encrypting the string one character at a time
}
return encodedString; // return the final encoded string
}
Use encodedString.resize(length) to pre-allocate the output string before entering the loop:
string CaesarCipher::Encode(string plainString) {
int length = plainString.length(); //gets the length of the input string
string encodedString; // variable to hold the final encrypted string
encodedString.resize(length); // allocate memory for the final encoded string
for (int i = 0; i < length; i++) {
encodedString[i] = Encode(plainString[i]); // encrypting the string one character at a time
}
return encodedString; // return the final encoded string
}
Use encodedString += plainString[i]; to append characters to the output string and let it grow as needed:
string CaesarCipher::Encode(string plainString) {
int length = plainString.length(); //gets the length of the input string
string encodedString; // variable to hold the final encrypted string
for (int i = 0; i < length; i++) {
encodedString += Encode(plainString[i]); // encrypting the string one character at a time
}
return encodedString; // return the final encoded string
}
The same problem exists in CaesarCipher::Decode() with the decodedString variable.
Also, main() has a buffer overflow if input.txt has more than 20 lines in it. Consider changing the code to use std::vector instead of fixed arrays.
And while (!fin.eof()) is wrong to use. Use while (getline(...)) instead:
// Read the sentences from the input file and save to original[20].
// Hint: use getline() function.
string line;
while (getline(fin, line)) { // Reading a line from input.txt file
original[i] = line;
encrypted[i] = cipher.Encode(original[i]); // Encrypt the sentences and save to encrypted[20]
decrypted[i] = cipher.Decode(encrypted[i]); // Decrypt the sentences and save to decrypted[20]
i++;
}

converting 128 bits from a character array to decimal without external libraries in C++ [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I had to convert a the 128 bits of a character array which has size 16 (1 byte each character), into a decimal and hexadecimal, without using any other libraries than included. Converting it to hexadecimal was easy as four bits were processed each time an the result was printed for each four bits as soon as it was generated.
But when it comes to decimal. Converting it in the normal mathematical way was not possible, in which each bit is multiplied by 2 to the power the index of the bit from left.
So I thought to convert it like I did with hexadecimal by printing digit by digit. But the problem is that in decimal it is not possible as the maximum digit is 9 and it needs 4 bits to represented while 4 bits can represent decimal numbers up to 15. I tried making some mechanism to carry the additional part, but couldn't find a way to do so. And I think, that was not going to work either. I have been trying aimlessly for three days as I have no idea what to do. And couldn't even find any helpful solution on the internet.
So, I want some way to get this done.
Here is My Complete Code:
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
const int strng = 128;
const int byts = 16;
class BariBitKari {
char bits_ar[byts];
public:
BariBitKari(char inp[strng]) {
set_bits_ar(inp);
}
void set_bits_ar(char in_ar[strng]) {
char b_ar[byts];
cout << "Binary 1: ";
for (int i=0, j=0; i<byts; i++) {
for (int k=7; k>=0; k--) {
if (in_ar[j] == '1') {
cout << '1';
b_ar[i] |= 1UL << k;
}
else if (in_ar[j] == '0') {
cout << '0';
b_ar[i] &= ~(1UL << k);
}
j++;
}
}
cout << endl;
strcpy(bits_ar, b_ar);
}
char * get_bits_ar() {
return bits_ar;
}
// Functions
void print_deci() {
char b_ar[byts];
strcpy(b_ar, get_bits_ar());
int sum = 0;
int carry = 0;
cout << "Decimal : ";
for (int i=byts-1; i >= 0; i--){
for (int j=4; j>=0; j-=4) {
char y = (b_ar[i] << j) >> 4;
// sum = 0;
for (int k=0; k <= 3; k++) {
if ((y >> k) & 1) {
sum += pow(2, k);
}
}
// sum += carry;
// if (sum > 9) {
// carry = 1;
// sum -= 10;
// }
// else {
// carry = 0;
// }
// cout << sum;
}
}
cout << endl;
}
void print_hexa() {
char b_ar[byts];
strcpy(b_ar, get_bits_ar());
char hexed;
int sum;
cout << "Hexadecimal : 0x";
for (int i=0; i < byts; i++){
for (int j=0; j<=4; j+=4) {
char y = (b_ar[i] << j) >> 4;
sum = 0;
for (int k=3; k >= 0; k--) {
if ((y >> k) & 1) {
sum += pow(2, k);
}
}
if (sum > 9) {
hexed = sum + 55;
}
else {
hexed = sum + 48;
}
cout << hexed;
}
}
cout << endl;
}
};
int main() {
char ar[strng];
for (int i=0; i<strng; i++) {
if ((i+1) % 8 == 0) {
ar[i] = '0';
}
else {
ar[i] = '1';
}
}
BariBitKari arr(ar);
arr.print_hexa();
arr.print_deci();
return 0;
}
To convert a 128-bit number into a "decimal" string, I'm going to make the assumption that the large decimal value just needs to be contained in a string and that we're only in the "positive" space. Without using a proper big number library, I'll demonstrate a way to convert any array of bytes into a decimal string. It's not the most efficient way because it continually parses, copies, and scans strings of digit characters.
We'll take advantage of the fact that any large number such as the following:
0x87654321 == 2,271,560,481
Can be converted into a series of bytes shifted in 8-bit chunks. Adding back these shifted chunks results in the original value
0x87 << 24 == 0x87000000 == 2,264,924,160
0x65 << 16 == 0x00650000 == 6,619,136
0x43 << 8 == 0x00004300 == 17,152
0x21 << 0 == 0x00000021 == 33
Sum == 0x87654321 == 2,271,560,481
So our strategy for converting a 128-bit number into a string will be to:
Convert the original 16 byte array into 16 strings - each string representing the decimal equivalent for each byte of the array
"Shift left" each string by the appropriate number of bits based on the index of the original byte in the array. Taking advantage of the fact that a left shift is equivalent of multiplying by 2.
Add all these shifted strings together
So to make this work, we introduce a function that can "Add" two strings (consisting only of digits) together:
// s1 and s2 are string consisting of digits chars only ('0'..'9')
// This function will compute the "sum" for s1 and s2 as a string
string SumStringValues(const string& s1, const string& s2)
{
string result;
string str1=s1, str2=s2;
// make str2 the bigger string
if (str1.size() > str2.size())
{
swap(str1, str2);
}
// pad zeros onto the the front of str1 so it's the same size as str2
while (str1.size() < str2.size())
{
str1 = string("0") + str1;
}
// now do the addition operation as loop on these strings
size_t len = str1.size();
bool carry = false;
while (len)
{
len--;
int d1 = str1[len] - '0';
int d2 = str2[len] - '0';
int sum = d1 + d2 + (carry ? 1 : 0);
carry = (sum > 9);
if (carry)
{
sum -= 10;
}
result.push_back('0' + sum);
}
if (carry)
{
result.push_back('1');
}
std::reverse(result.begin(), result.end());
return result;
}
Next, we need a function to do a "shift left" on a decimal string:
// s is a string of digits only (interpreted as decimal number)
// This function will "shift left" the string by N bits
// Basically "multiplying by 2" N times
string ShiftLeftString(const string& s, size_t N)
{
string result = s;
while (N > 0)
{
result = SumStringValues(result, result); // multiply by 2
N--;
}
return result;
}
Then to put it altogether to convert a byte array to a decimal string:
string MakeStringFromByteArray(unsigned char* data, size_t len)
{
string result = "0";
for (size_t i = 0; i < len; i++)
{
auto tmp = to_string((unsigned int)data[i]); // byte to decimal string
tmp = ShiftLeftString(tmp, (len - i - 1) * 8); // shift left
result = SumStringValues(result, tmp); // sum
}
return result;
}
Now let's test it out on the original 32-bit value we used above:
int main()
{
// 0x87654321
unsigned char data[4] = { 0x87,0x65,0x43,0x21 };
cout << MakeStringFromByteArray(data, 4) << endl;
return 0;
}
The resulting program will print out: 2271560481 - same as above.
Now let's try it out on a 16 byte value:
int main()
{
// 0x87654321aabbccddeeff432124681111
unsigned char data[16] = { 0x87,0x65,0x43,0x21,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x43,0x21,0x24,0x68,0x11,0x11 };
std::cout << MakeStringFromByteArray(data, sizeof(data)) << endl;
return 0;
}
The above prints: 179971563002487956319748178665913454865
And we'll use python to double-check our results:
Python 3.8.3 (tags/v3.8.3:6f8c832, May 13 2020, 22:37:02) [MSC v.1924 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> int("0x87654321aabbccddeeff432124681111", 16)
179971563002487956319748178665913454865
>>>
Looks good to me.
I originally had an implementation that would do the chunking and summation in 32-bit chunks instead of 8-bit chunks. However, little-endian vs. big endian byte order issues get involved. I'll leave that potential optimization as an exercise to do another day.