C++ string compress - c++

I wrote a program to compress a string using the counts of repeated characters. if the compressed string is longer than the original string, then we still return the original string. Below is my program:
void stringCompress(char* src) {
char* original;
original = src;
char* rst;
rst = src;
int histogram[256];
for (int i = 0; i < 256; i++) {
histogram[i] = 0;
}
int length = 0;
while (*src != NULL) {
length++;
src++;
}
src = original;
int j = 0;
for (int i = 0; i < length; i++) {
histogram[(int) src[i]]++;
if (histogram[(int) src[i]] == 1) {
rst[j] = src[i];
j++;
}
}
rst[j] = '\0';
char* final;
rst = original;
int index = 0;
char buffer[33];
for (int i = 0; i < j; i++) {
final[index] = rst[i];
stringstream number;
number<<histogram[(int)rst[i]];
-------> //cout<<number.str()<<endl;
char* temp = new char[number.str().length()+1];
strcpy(temp, number.str().c_str());
index++;
cout<<temp<<endl;
for(int k =0 ;k<number.str().length();k++)
{
final[index]=temp[k];
index++;
}
}
final[index] = '\0';
src = original;
if (index <= length) {
for (int i = 0; i < index; i++)
cout<<final[i];
} else {
cout << src << endl;
}
}
But strange thing is that if I leave the cout sentence cout<<number.str()<<endl; there (the arrow points to the sentence), then the output is right. For example, aaaabcdaa outputs a6b1c1d1 and aabcd outputs aabcd. However if I comment out cout<<number.str()<<endl;, then nothing is generated. Any help is appreciated.

The variable final is uninitialized in your code. When I initialize it with a memory buffer, then your program prints the desired output whether the line you pointed to is commented out or not.
Perhaps you meant to use buffer (which is unused) as memory for final, such as:
final = buffer;

Related

C++ issue with LZW decoding

I'm writing a LZW algorithm and I'm having trouble with decoding the encoded file. The encoding function works fine,the issues is as far as I know in the building of the dictionary in the decoding function.
Edit: The size of the decoding dictionary is for 1 bigger than the encoding dictionary. Also the decoding dictionary doesn't seem to contain any string value that has more than 2 characters. For testing I used a .txt file of Alice in wonderland and the first few words are ok but after that everything goes wrong
My encoding function:
void encode(char* path, int vel_s){
unordered_map<string,int>dict; //dictionary
int bit_size = ceil(log2(vel_s + 1)); //size of codes - x bits
//init dictionary
for(int i = 0; i < 256; i++){
string k = "";
k.push_back((unsigned char)i);
dict[k] = i;
}
int count = 256, maxVel = pow(2, bit_size); //counter and max value in bits
BinReader reader(path);//text to encodede
BinWriter writer("out.bin");//output file
string P = "";
P.push_back(reader.readByte());//read first char
while(!reader.f.eof()){
char C = reader.readByte(); //read next char
if(dict.find(P + C) != dict.end()){ //if in dictionary
P+=C;
}else{ //if not in dictionary
if(count >= maxVel){
count = 0;
}
int out = dict[P]; //int code of P
string binString = toBinary(out, bit_size); //binary value of out
for(int i = 0; i<binString.size();i++){ //write bits
if(binString[i]=='1'){
writer.writeBit(true);
}else{
writer.writeBit(false);
}
}
dict[P + C] = count; //write P+C to dictionary
count++;
P = C; //overwrite P
}
}
//write last output
int out = dict[P];
string binString = toBinary(out, bit_size);
for(int i = 0; i<binString.size();i++){
if(binString[i]=='1'){
writer.writeBit(true);
}else{
writer.writeBit(false);
}
}
}
And this is the decoding function:
void decompress(char* path, int vel_s){//file path + dictionary max size
unordered_map<int,string>dict; //dictionary
int bit_size = ceil(log2(vel_s + 1));//max number of bits in code
for(int i = 0; i < 256; i++){ //init dictionary
dict[i] = (unsigned char) i;
}
int count = 256; //counter
vector<bool>B;
BinWriter writer("out_d.txt"); //output file
BinReader reader(path); //input file
int newI, oldI; //new and old value
for(int i = 0; i < bit_size; i++){ //read code from encoded file of size bit_size
B.push_back(reader.readBit());
}
oldI = convertToInt(B); //convert to integer
string S = dict[oldI]; //String is dictionary value of old value
writer.writeByte(S[0]); //write first letter
string C = ""; //init C
C =S[0]; //C is first character of S
int maxVel = pow(2, bit_size); //max value of encoded code
while(!reader.f.eof()){
B.clear();//clear vector B for reading bits
for(int i = 0; i < bit_size; i++){
B.push_back(reader.readBit());//read next code
}
newI = convertToInt(B); //convert bits to int
if(dict.find(newI) == dict.end()){ //if new value not in dictionary
S = dict[oldI]; //S is value of old code
S += C; //concat C to S
}else{
S = dict[newI]; //S is value of new code
}
for(int k = 0; k < S.size(); k++){ //write S to file
writer.writeByte(S[k]);
}
C = "";
C += S[0]; //C is first character of S
dict[count] = dict[oldI] + C; //new input in dictionary
count++;
oldI = newI; //old value is new value
}
And the toBinary() and convertToInt() functions that I use for help
string toBinary(int x, int l){
string temp;
while(x!=0){
temp =(x%2==0 ? "0":"1")+temp;
x/=2;
}
while(temp.length() != l){
temp = "0"+temp;
}
return temp;
}
int convertToInt(vector<bool>B){
int power= B.size()-1,res= 0;
for(int i = 0; i < B.size(); i++){
if(B[i]){
res+=pow(2, power);
}
power--;
}
return res;
}

Difficulty writing run length encoder in c++

Trying to write this run length encoder, and it basically works but it is not passing test cases because of a '/0'.
Code
std::string run_length_encode(const std::string& str)
{
std::string encoded = "";
char prevch;
char newch;
int count = 1;
prevch = str[0];
for (int i = 0; i <= str.length(); i++)
{
newch = str[i];
if (prevch == newch)
{
count++;
}
else
{
encoded += prevch;
if (count > 1)
{
encoded += std::to_string(count);
}
prevch = newch;
count = 1;
}
}
if (prevch == newch)
{
encoded += newch;
if (count > 1)
{
encoded += std::to_string(count);
}
}
return encoded;
Error message:
Expected equality of these values:
run_length_encode("A")
Which is: "A\0"
"A"
Answer should be A but my code returns A\0.
for (int i = 0; i <= str.length(); i++)
should be
for (int i = 0; i < str.length(); i++)
In C++ string indexes start at zero and finish one before the length of the string.

C - strtok does strange things

i use strtok to split a string into different pieces and assemble them as a struct. This is my code:
object* parseJSON(size_t length, char* json, size_t jsonLen){
char *finalString = prepareJSON(json,jsonLen);
cout << finalString << "\n";
char delimiter[] = ",:";
char *token = strtok(finalString, delimiter);
object *retObj = (struct object *)malloc(length);
size_t returnObjectIndex = 0;
size_t index = 0;
bool firstTime = true;
struct object item;
while(token != NULL){
if((index % 2) != 0){
if(firstTime){
item.Type = token;
firstTime = false;
} else {
item.ID = token;
retObj[returnObjectIndex] = item;
returnObjectIndex++;
firstTime = true;
}
}
token = strtok(NULL,delimiter);
index++;
}
return retObj;
}
This is the finalString:
Type:temp,id:3,Type:temp,id:1
In my mind this should come out with this code:
for(int n = 0; n < 5; n++){
cout << returnObject[n].Type << " " << returnObject[n].ID << "\n";
}
as:
temp 3
temp 1
but instead i get this on the console:
temp 3
temp 1
h"° Ó*°
C
Is this because i loop 5 times even though there should be only 2 elements in the array? I loop 5 times because i can't get the number of elements of the array in the pointer (atleast i think that this is not possible).
Any help is very much appreciated
Best regards
Edit: This is my prepareJSON function:
char* prepareJSON(char* json, size_t jsonLen){
char forbiddenChars[] = {'[', '{','\"', '}', ']'};
bool isForbbidenChar = false;
char* finalString = (char*)malloc(jsonLen);
size_t finalStringIndex = 0;
for(size_t i = 0; i < jsonLen; i++){
char c = json[i];
isForbbidenChar = false;
for(int k = 0; k < 5; k++){
if(c == forbiddenChars[k]){
isForbbidenChar = true;
break;
}
}
if(isForbbidenChar){
continue;
}
else{
finalString[finalStringIndex] = c;
finalStringIndex++;
}
}
return finalString;
}
and this my main function:
int main(){
object *returnObject;
char json[] = "[{\"Type\":\"temp\",\"id\":\"3\"},{\"Type\":\"temp\",\"id\":\"1\"}]";
returnObject = parseJSON(5,json, strlen(json));
for(int n = 0; n < 5; n++){
cout << returnObject[n].Type << " " << returnObject[n].ID << "\n";
}
}
Solution:
I did indeed allocate too little memory, changed it:
object *retObj = (struct object *)malloc(sizeof(struct object) * length);
Now it works!

Dynamic Memory issue in C++

so I was writing a program which has to check if the input sting is a palindrome or not. And it's actually working but a problem with deleting the array I created during the course of it arouse.
#include <iostream>
using namespace std;
bool checkPalindrome(char* text);
char* clearString(char* src);
int main()
{
char buffer[1000];
cin.getline(buffer, 1000);
cout << boolalpha << checkPalindrome(buffer) << endl;
return 0;
}
bool checkPalindrome(char* text)
{
char* newStr = clearString(text);
if (!newStr)
return false;
int newLen = strlen(newStr);
for (int i = 0; i < newLen / 2; i++) {
if (newStr[i] == newStr[newLen - i - 1])
continue;
else
return false;
}
//delete[] newStr;
return true;
}
char* clearString(char* src)
{
unsigned len = strlen(src);
unsigned counter = 0;
for (int i = 0; i < len; i++) {
if (src[i] == ' '||src[i] == '.'||src[i] == ','||src[i] == '!')
counter++;
}
unsigned newSize = len - counter + 1;
char* dest = new(nothrow) char[newSize];
if (!dest) {
cout << "not enoough memory\n";
return NULL;
}
int i, j;
for(i = j = 0; j < newSize; ++i, ++j) {
if(src[i]==' '||src[i]=='.'||src[i]==','||src[i]=='!'||src[i]=='?')
i++;
else
dest[j] = src[i];
}
dest[j] = '\0';
return dest;
}
So the commentated delete in the checkPalindrome function causes a crash if executed and I get the "Heap corruption detected" error. I tried changing the function type to void and delete there and the same thing happened. Any ideas what causes it?
Your loop copies the '\0' at the end of the string, but then you add another '\0', using one more byte of memory than you allocated.

char* pointer alloted to char array,and outputted within for

I have defined the struct chararray as follows.
struct chararray
{
char* lhs;
char* rhs;
};
Now, I have two arrays la[l] and ra[l](both have all l values defined). I assign that to the struct,and return the function.
chararray s;
s.lhs = new char[l];
s.rhs = new char[l];
s.lhs = &la[0];
s.rhs = &ra[0];
return s;
In main , I ouptut
for(int i = 1; i < l;i++){
cout << *(s.rhs + i);
}
Now,I get gibberish as output.
But if I output *(s.rhs + 0) and *(s.rhs + 1) and ... [ the values 0,1,.. are explicitly included ], I get correct output!
Why doesnt the for loop work?
PS - My entire code is -
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
struct chararray
{
char* lhs;
char* rhs;
};
chararray getcenter(char in[],int l){
int open_count = 0;
int open = 0;
int first = 0;
int last = 0;
int limit;
int close_count = 0;
char lhs[l],rhs[l];
for(int i = 0; i < l;i++){
lhs[i] = ' ';
rhs[i] = ' ';
}
for(int i = 0; in[i]!='\0';i++){
int flag = 0;
if(in[i] == '('){
if(flag == 0){first = i;flag = 1;}
open++;
}
if(in[i] == '('){
last = i;
}
limit = i;
}
for(int i = 0; in[i]!='\0';i++)
{
//cout << "entrt" << endl;
int temp;
if(in[i] == '(') { open_count++; }
if(in[i] == ')') { close_count++; }
if((open_count == close_count) && (open_count != 0) && (open_count != open))
{
//cout << open_count << endl;
for(int j = 0;j < i+1;j++)
{
lhs[j] = in[j];
}
lhs[i+1] = ' ';
lhs[i+2] = ' ';
for(int j = i+3; in[j]!='\0';j++)
{
lhs[j] = ' ';
rhs[j-i-3] = in[j];//Assuming no space between -> and rhs
temp = j;
}
for(int j = temp;rhs[j] != '\0';j++){
rhs[j] = ' ';
}
for(int j = temp;lhs[j] != '\0';j++){
lhs[j] = ' ';
}
break;
}
}
chararray s;
s.lhs = new char[l];
s.rhs = new char[l];
s.lhs = &lhs[0];
s.rhs = &rhs[0];
return s;
}
int main()
{
string input;
cin >> input;
int l=input.length()+1;
char in[l];
strcpy(in, input.c_str());
chararray s = getcenter(in,l);
for(int i = 1; i < l;i++){
//cout << *(s.rhs + i); - Doesnt work
}
cout << *(s.lhs + 5); // Works!
return 0;
}
Your for loop is starting at i=1, and when you explicitly set the values you are using 0 and 1. Decide where you want to start, and try it again.
Try this:
for(int = 0 ; i < l; i++)
cout << *(s.rhs + i);
Note that you are actually risking a memory leak with these lines of code:
s.lhs = new char[l];
s.rhs = new char[l];
s.lhs = &lhs[0];
s.rhs = &rhs[0];
You are allocating 1 char and storing its address in s.lhs, then resetting s.lhs to the address of lhs[0]. There is no need for the two first lines with the new in them. So replace that code with this: (also note that &lhs[0] is the same as lhs)
s.lhs = lhs;
s.rhs = rhs;