segmentaion fault on large recursive string manipulation - c++

I am doing the challenge from www.adventofcode.com/day/10
I have a code that i think works, I am using c++ just to get to learn while having fun.
I am doing the string manipulation recursive.
The problem here is that the program crashes with segmentation fault
on the line "char ch = line[0]" when doing more than 38 iterations.
#include <iostream>
#include <string>
using namespace std;
string count_chars(string line){
char ch = line[0];
uint i;
for(i = 0; ch == line[i]; i++){
}
if(i != line.length()){
line = to_string(i) + ch + count_chars(line.substr(i));
}
else{
line = to_string(i) + ch;
}
return line;
}
int main(int argc, char** args)
{
//ifstream in("dayx");
/*
if(argc ==1)
return 1;
string line;
cout << line.capacity() << endl;
line = args[1];
*/
string line = "1";
for(int i = 1; i < 40; i++){
line = count_chars(line);
//cout << line << " after " << i << " iterations" << endl;
cout <<"Line size: " << line.size() << endl;
}
cout << line << endl;
}
The code is compiled using:
g++ day10.cpp --std=c++11 -g
My questions, why is this happening, how can i prevent it and how can i use gdb to figure this out? Thanks!
I am using linux and gcc 5.3

You have stack overflow because of too deep recursion (several thousands calls deep). You could easily implement the algorithm using a loop instead.

I'm suspicious of any lines of code that access indices of a string that may not exist:
char ch = line[0];
uint i;
for(i = 0; ch == line[i]; i++){
}
if(i != line.length()){
line = to_string(i) + ch + count_chars(line.substr(i));
It grabs the first char from the string even if the string is empty.
It is only checking if i is the same as the length of the string - not if i is greater than the length of string.

Related

Stuck on removing whitespace from string without using any helper code c++

Create a program titled str_compress.cpp. This program will take a sentence input and remove all spaces from the sentence. (A good first step in encryption programs) Make sure that both the input and output strings are all stored in a single variable each. Do not use numbers or symbols. Include both upper-case and lower-case letters. Account for cases with multiple spaces anywhere.
This is what I have so far:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int i = 0, j = 0, len;
string str;
cout << "Enter string: ";
getline(cin, str);
len = str.length();
for (i = 0; i < len; i++)
{
if (str[i] == ' ')
{
for (j = i; j < len; j++)
{
str[j] = str[j + 1];
}
len--;
}
}
cout << str << endl;
system("pause");
return 0;
}
I can eliminate spaces, but only one at a time. If I copy and paste the for loop, I can remove all spaces for how many loops there are. I'm thinking that I can loop the for loop over and over until all spaces are gone, but I'm not sure how to do that. Also, I can't use anything like remove_all() or erase().
This is a strong clue for how the authors of your exercise want you to write your code:
Make sure that both the input and output strings are all stored in a single variable each
You should make a new string:
string new_str;
Use your loop over the input string. For each char in the string, check whether it is a space. If yes, do nothing. If no, append it to the output string:
for (i = ...)
{
char c = str[i];
if (c != ' ')
new_str.push_back(c);
}
Your loop's logic when removing a space is wrong. For instance, after removing a space, you then skip the next char in the string, which may be another space. Also, although you are decrementing the len, you don't resize the string to the new len before printing the new str value.
It should look more like this:
#include <iostream>
#include <string>
using namespace std;
int main()
{
size_t i, j, len;
string str;
cout << "Enter string: ";
getline(cin, str);
len = str.length();
i = 0;
while (i < len)
{
if (str[i] == ' ')
{
for (j = i + 1; j < len; ++j)
{
str[j - 1] = str[j];
}
--len;
}
else
++i;
}
str.resize(len);
cout << str << endl;
/* or, if you are not allowed to use resize():
cout.write(str.c_str(), len);
cout << endl;
*/
/* or, if you are not allowed to use write():
if (len < str.length())
str[len] = '\0';
cout << str.c_str() << endl;
*/
system("pause");
return 0;
}
Live Demo
However, your instructions do say to "Make sure that both the input and output strings are all stored in a single variable each", which implies that separate std::string variables should be used for input and output, eg:
#include <iostream>
#include <string>
using namespace std;
int main()
{
size_t i, j, len;
string str, str2;
cout << "Enter string: ";
getline(cin, str);
str2 = str;
len = str2.length();
i = 0;
while (i < len)
{
if (str2[i] == ' ')
{
for (j = i + 1; j < len; ++j)
{
str2[j - 1] = str2[j];
}
--len;
}
else
++i;
}
str2.resize(len);
cout << str2 << endl;
/* or:
cout.write(str2.c_str(), len);
cout << endl;
*/
/* or:
if (len < str2.length())
str2[len] = '\0';
cout << str2.c_str() << endl;
*/
system("pause");
return 0;
}
Live Demo
Alternatively:
#include <iostream>
#include <string>
using namespace std;
int main()
{
size_t i, j, len;
string str, str2;
cout << "Enter string: ";
getline(cin, str);
len = str.length();
str2.reserve(len);
for(i = 0; i < len; ++i)
{
char ch = str[i];
if (ch != ' ')
str2 += ch;
}
cout << str2 << endl;
system("pause");
return 0;
}
Live Demo
This is what worked for me. Thank you everyone for the help!!
int main()
{
int i, j, len;
string str, str2;
cout << "Enter string: ";
getline(cin, str);
len = str.length();
for (i = 0; i < len; ++i)
{
char ch = str[i];
if (ch != ' ')
str2 += ch;
}
cout << str2 << endl;
system("pause");
return 0;
}

wofstream automatically narrows wide characters

#include "stdafx.h"
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
int main(int argc, char * argv[]) {
srand(time(NULL));
if (argc < 1) {
cout << "Too few arguments inserted.\nUSAGE: RKRIPT [InFile] [OutFile]" << endl;
return EXIT_FAILURE;
}
string InFile, OutFile;
InFile = argv[1];
OutFile = argv[2];
if (InFile.size() > FILENAME_MAX || OutFile.size() > FILENAME_MAX) {
cout << "Invalid filename lenght.\nFILENAME_MAX = " << FILENAME_MAX;
return EXIT_FAILURE;
}
wstring * Cont = new wstring;
if (Cont == nullptr) {
cout << "Memory allocation failed." << endl;
return EXIT_FAILURE;
}
wifstream i_f;
wchar_t temp;
i_f.open(InFile);
while (i_f.get(temp)) {
*Cont += temp;
}
i_f.close();
wofstream o_f;
o_f.open(OutFile);
long long int OutSize = 0;
for (long long int i = 0; i < Cont->size(); i++) {
do {
temp = wchar_t(rand() % WCHAR_MAX); //Keeps getting another value for temp until its sum with the current character doesn't exceed WCHAR_MAX.
} while (((long long int)temp + (long long int)Cont->at(i)) > WCHAR_MAX);
o_f << temp + Cont->at(i) << temp;
OutSize += 2;
}
o_f.close();
cout << "Done. Input file was " << InFile << "(" << Cont->size() << " Bytes)" << ". Output file is " << OutFile << "(" << OutSize << " Bytes)";
delete Cont;
return EXIT_SUCCESS;
}
This code is a simple "encrypter" that plays with altcodes to conceal characters. Though, when the application is done, the output file will be empty. The file output file I specified isn't anywhere at all. This application is meant to be run from shell. So, say I want to encrypt dummy.txt, I'll have to use this:RKRIPT dummy.txt out.txt.
At first I thought that I was using the stream incorrectly, leading to characters not to be printed out. But after changing
for (long long int i = 0; i < Cont->size(); i++) {
do {
temp = wchar_t(rand() % WCHAR_MAX); //Keeps getting another value for temp until its sum with the current character doesn't exceed WCHAR_MAX.
} while (((long long int)temp + (long long int)Cont->at(i)) > WCHAR_MAX);
o_f << temp + Cont->at(i) << temp;
OutSize += 2;
}
to this(notice the changes from WCHAR_MAX to CHAR_MAX)...
for (long long int i = 0; i < Cont->size(); i++) {
do {
temp = wchar_t(rand() % WCHAR_MAX); //Keeps getting another value for temp until its sum with the current character doesn't exceed CHAR_MAX.
} while (((long long int)temp + (long long int)Cont->at(i)) > CHAR_MAX);
o_f << temp + Cont->at(i) << temp;
OutSize += 2;
}
My output was just fine, because there were only narrow characters(ASCII) to write on my file. Though, I don't know how to fix this, how do I get my WIDE characters to be written onto a file using a WIDE stream? Thanks for any reply.

Breaking an array of chars into words

i need a little help with this problem,
How do you break a char array like this "char* text" into individual words based on specific delimiters and save them in the form "char* text[]" without using the strtok function or any libraries besides "iostream".
In a normal situation i would use strings instead of char arrays and the strtok function, but in this situation, i am simply not allowed to.
Thanks,
Update:
i have included what i have attempted
#include <iostream>
#include <fstream>
//#define MAX_CHARS_PER_LINE = 512;
//#define MAX_TOKENS_PER_LINE = 5;
using namespace std;
char stringToken(char* input_string);
int main(int argc, char* argv[])
{
char input_string[512];
ifstream infile;
infile.open(argv[1]);
while(!infile.eof())
{
infile.getline(input_string, 512);
cout << "Main line: " << input_string << endl;
stringToken(input_string);
}
infile.close();
return 0;
}
char stringToken(char* input_string)
{
//char* word;
//cout << "String token function: " << input_string << endl;
/*while(input_string >> word)
{
cout << word << endl;
}*/
char *tempone;
char *temptwo[5];
int ii=0,
jj=0;
while(input_string[ii] != '\0' && jj<5)
{
if((int)input_string[ii]!= 32 && (int)input_string[ii]!= 9 && (int)input_string[ii] != 44)
{
tempone[ii]=input_string[ii];
//cout << "\n\nindiv char" << input_string[ii] << "\t\t" << (int)input_string[ii] << "\n\n";
}
else
{
temptwo[jj]=tempone;
jj++;
//testing
cout << temptwo << endl;
}
ii++;
}
return 0;
}
Here a pseudo code
words split(line, delims)
{
nb_words = cound_words(line);
words = allocate_words(nb_words + 1); // words is a array of pointer
i = 0
j = 0
while true
{
while line[i] in delims // we transform every delims into a end string
{
line[i] = end_string
i++
}
if line[i] not end_string
{
words[j] = line + i // we stock the address of line[i]
j++
while line[i] not in delims and line[i] not end_string
{
i++
}
}
else
{
words[j] = NULL // we end the array by NULL pointer
return words
}
}
}
count_word use a similar loop. I let you find it. The purpose of this algorithm is to transform the line into multiple word. So line must life as long that you use words.

How do I count words and lines that were input as a cstring array

This program should read a paragraph from a text file provided by the user and then store each line in a ragged char array and count the total number of words and lines of the paragraph then display the result.
I can't figure out why does the number of lines keep giving me the result of 3
and why the number of words is always missing 2 words.
please help and keep in mind that I'm no professional just started learning c++ recently.
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main()
{
ifstream infile;//declarations
char filename[45];
char **data = 0;
char **temp = 0;
char *str = 0;
char buffer[500], c;
int numoflines = 0, numofwords = 0;
cout << "Please enter filename: ";//prompt user to enter filename
cin >> filename;
infile.open(filename);//open file
if (!infile)//check if file was successfully opened
{
cout << "File was not successfully opened" << endl << endl;//display error message
return 0;
} //end of if
data = new char*[numoflines];
while (!infile.eof())
{
temp = new char*[numoflines + 1];
for (int i = 0; i < numoflines; i++)
{
infile.getline(buffer, 500);//read line
for (int i = 0; i < strlen(buffer); i++)//count number of words in line
{
c = buffer[i];
if (isspace(c))
numofwords++;
}
str = new char[strlen(buffer) + 1];//allocate a dynamic array
strcpy(str, buffer);
data[i] = str;
temp[i] = data[i];
}//end of for
infile.getline(buffer, 500);
for (int i = 0; i < strlen(buffer); i++)//count number of words in line
{
c = buffer[i];
if (isspace(c))
numofwords++;
}
temp[numoflines] = new char[strlen(buffer) + 1];
strcpy(temp[numoflines], buffer);
delete[] data;
data = temp;
numoflines++;
}
cout << "Number of words: " << numofwords << endl;
cout << "Number of lines: " << numoflines << endl;
return 0;
}
The concept of number of lines is a viewing concept only. It's not encoded into the file. The following single paragraph can be displayed on one line or 16 lines depending upon the size of the editor window:
If you wanted to specify a char width of the window, lines could be calculated from that, but as is, paragraphs and wordcount are as good as you will do. And given a successfully opened ifstream infile that is fairly simple to obtain:
auto numoflines = 0;
auto numofwords = 0;
string paragraph;
while(getline(infile, paragraph)) {
numofwords += distance(istream_iterator<string>(istringstream(paragraph)), istream_iterator<string>());
++numoflines;
}
cout << "Number of words: " << numofwords << "\nNumber of lines: " << numoflines << endl;
NOTE:
Visual Studio supports inline construction of an istringstream so if you're not using that you'll need to construct on a separate line.

C++ Pig Latin is not working

So, I have tried and tried to make this c++ pig latin program, but it's just not working. Here is my code:
int main()
{
string tmp = "";
char a;
cout << "String: "; getline(cin, tmp);
char pigLatin[1024];
strncpy(pigLatin, tmp.c_str(), sizeof(pigLatin));
pigLatin[sizeof(pigLatin) - 1] = 0;
a = pigLatin[0];
pigLatin[sizeof(pigLatin)] = '-';
pigLatin[sizeof(pigLatin) + 1] = a;
pigLatin[sizeof(pigLatin) + 2] = 'a';
pigLatin[sizeof(pigLatin) + 3] = 'y';
for (int i = 1; i < sizeof(pigLatin); i++)
{
cout << pigLatin[i];
}
cout << endl;
system("PAUSE");
return 0;
}
When I run it, it doesn't return any runtime errors or anything, but when I enter a string it just puts the string minus the first letter and then a bunch of spaces. Does anyone know the problem?
The problem is that sizeof returns the size in bytes of the array not the length of the string it contains. In this case the result of sizeof is 1024 assuming char is 8 bits. You could always use strlen to determine the length of the string or you can eliminate the use of a naked array altogether and use std::string instead. This would decrease the size of your code significantly. Something like this...
int main()
{
cout << "String: " << flush;
string pigLatin;
getline(cin, pigLatin);
pigLatin += '-';
pigLatin += pigLatin[0];
pigLatin += "ay";
pigLatin.erase(0, 1);
cout << pigLatin << endl;
system("PAUSE");
}