CodeEval Challenge: Reverse strings in input file - c++

I've decided to start learning C++ before I take a formal class on it next year, I've begun with some of the easy challenges on CodeEval and Project Euler. In this one, you have to take an input file which has strings of words, and you have to output the line of the file with the words reversed. Such that a file with the following input
1: This is line one
2: This is line two
would end up as
1: one line is This
2: two line is This
I wrote the following program to do that, and aside from not properly reversing the string, instead fully reversing the word, it Segmentation faults despite compiling with no errors or warnings. I assume I've missed something about proper memory management in C++ but I'm not sure what it is. So can someone enlighten me on what I've missed in this regarding memory management?
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
int main(int argc, char** argv)
{
std::string filename = argv[1]; //has to be argv[1], argv[0] is program name
std::string output_string; //final output
std::string line; //Current line of file
std::ifstream read(filename.c_str());
if(read.is_open()){
while(std::getline(read,line)){
std::string temp;
std::istringstream iss;
iss.str(line);
while(iss >> temp){ //iterates over every word
output_string.insert(0,temp); //insert at the start to reverse
output_string.insert(0," "); //insert spaces between new words
}
output_string.erase(0,1); //Removes the space at the beginning
output_string.insert(0,"\n"); //Next line
}
output_string.erase(0,1); //Remove final unnecessary \n character
read.close();
}
else{
std::cout<<"Unable to open file\n";
}
for(unsigned int i = output_string.length(); i>=0;i--){
std::cout<<output_string[i];
}
std::cout<<"\n";
}

for(unsigned int i = output_string.length(); i>=0;i--){
std::cout<<output_string[i];
}
The segfault happens here; you might be able to get a warning from the compiler with some additional flags. e.g. g++ produces no warnings with -Wall, but produces two warnings with -Wextra: one about argc not being used, and the other about this loop never terminating.
The issue here is twofold: as Captain Giraffe said, you're starting beyond the actual length your strings; but also the condition i >= 0 will always be true, because i is unsigned. Therefore once it reaches 0, the next decrement will cause it to wrap around to the highest possible value, and then you definitely get an out-of-bounds memory access.
The warning reported is:
reverse.cpp:31:49: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits]
for(unsigned int i = output_string.length(); i>=0;i--){
Also as Captain Giraffe said, you're reversing the entire file, not just each line. You can therefore just reverse each line and output it once you've finished the line, rather than storing the entire output for later.
Here's the entire program with minimal changes to avoid any warnings and get the correct output. The main change is moving all usage of output_string into the read loop.
int main(int argc, char** argv)
{
if (argc != 2)
{
std::cerr << "Need a file to process!" << std::endl;
return 1;
}
std::string filename = argv[1]; //has to be argv[1], argv[0] is program name
std::string line; //Current line of file
std::ifstream read(filename.c_str());
if(read.is_open()){
while(std::getline(read,line)){
std::string output_string; //final output
std::string temp;
std::istringstream iss;
iss.str(line);
while(iss >> temp){ //iterates over every word
output_string.insert(0,temp); //insert at the start to reverse
output_string.insert(0," "); //insert spaces between new words
}
output_string.erase(0,1); //Removes the space at the beginning
std::cout << output_string << std::endl;
}
read.close();
}
else{
std::cout<<"Unable to open file\n";
}
}

Change the last for-statement to
std::cout << output_string;
You are starting off the output by printing the character after the last in the output string. This gets rid of the segfault. Now you are trying to print the reversed output in reverse.
Now you find that you should just reverse each line, not the entire text. You can easily do that by adding a starting index for each line, instead of 0, in your inserts.
So instead of
output_string.insert(0,temp); //insert at the start to reverse
You can do
output_string.insert(start_of_line, temp); //insert at the start to reverse

Related

Read line in C++ till EOF

I'm writing a function that reads line by line from cin and returns when it sees ; character.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
using namespace std;
int read_cmd(char *cmd)
{
cout << "Please enter a string: \n";
cmd[0]='\0';
while(1){
char currentLine[10000];
currentLine[0]='\0';
cin.getline(currentLine,10000);
if (strcmp(currentLine,";")==0){
break;
}
strcat(cmd, "\n");
strcat(cmd, currentLine);
}
return 0;
}
int main(){
char cmd[1000];
while (1){
read_cmd(cmd);
cout<< cmd << endl;
}
}
I then tested it using text fed from another file via pipe.
./read_cmd < test_file
contents of test_file:
line 1
line 2
;
This outputs results just fine, however it gives me a segmentation fault at the end. Is there a way for cin to check if it's coming across an EOF and terminates?
To detect the EOF you should use something like:
while (cin.good() && !cin.eof())
{
// Read the file
}
See the documentation for cin, in particular the good() (for error checking) and eof() member functions.
In particular this example might be helpful.
I would highly suggest the use of the string object for something like this, that way you're not wasting space, as well as ensuring that you have enouch space. You can also do it without a loop.
string currentLine;
getline(cin, currentLine, ';');
Now, if you need to get just the last line with has the semi-colon, a loop is necessary, but still you can do it at little more easily.
string currentLine;
while(getline(cin, currentLine)){
if(currentLine.find(";") != string::npos){
break;
}
}
Use strings to pass things around as well. There's always the .clear() method as well that any string has for easy emptying.
string getline
string Object

Reading data in from a .csv into usable format using C++

I would like to be able to read the data that I have into C++ and then start to do things to manipulate it. I am quite new but have a tiny bit of basic knowledge. The most obvious way of doing this that strikes me (and maybe this comes from using excel previously) would be to read the data into a 2d array. This is the code that I have so far.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <string>
#include <sstream>
using namespace std;
string C_J;
int main()
{
float data[1000000][10];
ifstream C_J_input;
C_J_input.open("/Users/RT/B/CJ.csv");
if (!C_J_input) return -1;
for(int row = 0; row <1000000; row++)
{
string line;
getline(C_J_input, C_J, '?');
if ( !C_J_input.good() )
break;
stringstream iss(line);
for(int col = 0; col < 10; col++)
{
string val;
getline(iss, val, ',');
if (!iss.good() )
break;
stringstream converter(val);
converter >> data[row][col];
}
}
cout << data;
return 0;
}
Once I have the data read in I would like to be able to read through it line by line and then pull analyse it, looking for certain things however I think that could probably be the topic of another thread, once I have the data read in.
Just let me know if this is a bad question in any way and I will try to add anything more that might make it better.
Thanks!
as request of the asker, this is how you would load it into a string, then split into lines, and then further split into elements:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <sstream>
//This takes a string and splits it with a delimiter and returns a vector of strings
std::vector<std::string> &SplitString(const std::string &s, char delim, std::vector<std::string> &elems)
{
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim))
{
elems.push_back(item);
}
return elems;
}
int main(int argc, char* argv[])
{
//load the file with ifstream
std::ifstream t("test.csv");
if (!t)
{
std::cout << "Unknown File" << std::endl;
return 1;
}
//this is just a block of code designed to load the whole file into one string
std::string str;
//this sets the read position to the end
t.seekg(0, std::ios::end);
str.reserve(t.tellg());//this gives the string enough memory to allocate up the the read position of the file (which is the end)
t.seekg(0, std::ios::beg);//this sets the read position back to the beginning to start reading it
//this takes the everything in the stream (the file data) and loads it into the string.
//istreambuf_iterator is used to loop through the contents of the stream (t), and in this case go up to the end.
str.assign((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
//if (sizeof(rawData) != *rawSize)
// return false;
//if the file has size (is not empty) then analyze
if (str.length() > 0)
{
//the file is loaded
//split by delimeter(which is the newline character)
std::vector<std::string> lines;//this holds a string for each line in the file
SplitString(str, '\n', lines);
//each element in the vector holds a vector of of elements(strings between commas)
std::vector<std::vector<std::string> > LineElements;
//for each line
for (auto it : lines)
{
//this is a vector of elements in this line
std::vector<std::string> elementsInLine;
//split with the comma, this would seperate "one,two,three" into {"one","two","three"}
SplitString(it, ',', elementsInLine);
//take the elements in this line, and add it to the line-element vector
LineElements.push_back(elementsInLine);
}
//this displays each element in an organized fashion
//for each line
for (auto it : LineElements)
{
//for each element IN that line
for (auto i : it)
{
//if it is not the last element in the line, then insert comma
if (i != it.back())
std::cout << i << ',';
else
std::cout << i;//last element does not get a trailing comma
}
//the end of the line
std::cout << '\n';
}
}
else
{
std::cout << "File Is empty" << std::endl;
return 1;
}
system("PAUSE");
return 0;
}
On second glance, I've noticed few obvious issues which will slow your progress greatly, so I'll drop them here:
1) you are using two disconnected variables for reading the lines:
C_J - which receives data from getline function
line - which is used as the source of stringstream
I'm pretty sure that the C_J is completely unnecessary. I think you wanted to simply do
getline(C_J_input, line, ...) // so that the textline read will fly to the LINE var
// ...and later
stringstream iss(line); // no change
or, alternatively:
getline(C_J_input, C_J, ...) // no change
// ...and later
stringstream iss(C_J); // so that ISS will read the textline we've just read
elsewise, the stringstream will never see what getline has read form the file - getline writes the data to different place (C_J) than the stringstream looks at (line).
2) another tiny bit is that you are feeding a '?' into getline() as the line separator. CSVs usually use a 'newline' character to separate the data lines. Of course, your input file may use '?' - I dont know. But if you wanted to use a newline instead then omit the parameter at all, getline will use default newline character matching your OS, and this will probably be just OK.
3) your array of float is, um huge. Consider using list instead. It will nicely grow as you read rows. You can even nest them, so list<list<float>> is also very usable. I'd actually probably use list<vector<float>> as the number of columns is constant though. Using a preallocated huge array is not a good idea, as there always be a file with one-line-too-much you know and ka-boom.
4) your code contains a just-as-huge loop that iterates a constant number of times. A loop itself is ok, but the linecount will vary. You actually don't need to count the lines. Especially if you use list<> to store the values. Just like you;ve checked if the file is properly open if(!C_J_input), you may also check if you have reached End-Of-File:
if(C_J_input.eof())
; // will fire ONLY if you are at the end of the file.
see here for an example
uh.. well, that's for start. Goodluck!

How to split a string into two integers over several lines C++

I've been trying to retrieve saved data from a text file. The data stored are both numbers, separated by a ~. I've managed to get it to print out one of the lines (the top line) however I've been unable to figure out how to proceed through the entire file.
There are only two numbers (integers) on each line, an X and Y position of another vector. The idea is to assign each integer to the respective variable in the vectors. I've not managed to get that far since I can't get it to go past line 1. But I'd thought that by having an array size of 2, and the array temporarily stores the value, assigns it to the vector, then overwrites it with the next value(s) that could work. But again not managed to get that far.
Below is the code I've been trying to use;
........
string loadZombieData;
loadFile >> loadZombieData; //Data gets read from the file and placed in the string
vector<string> result; //Stores result of each split value as a string
stringstream data(loadZombieData);
string line;
while(getline(data,line,'~'))
{
result.push_back(line);
}
for(int i = 0; i < result.size(); i++){
cout << result[i] << " ";
}
.......
Just to clarify, this is not my code, this is some code I found on Stackoverflow, so I'm not entirely certain how it all works yet. As I said, I've been trying to get it to read multiple lines, then using the for loop was going to assign the results to the other vector variables as needed. Any help is appreciated :)
Use two while loops:
std::vector<std::string> result;
std::vector<int> numbers;
std::string filename;
std::ifstream ifile(filename.c_str());
if (!ifile.is_open()) {
std::cerr << "Input file not opened! Something went wrong!" << std::endl;
exit(0);
}
std::string temp;
//loop over the file using newlines as your delimiter
while (std::getline(ifile, temp, '\n')) {
//now temp has the information of each line.
//create a stringstream initialized with this information:
std::istringstream iss(temp);//this contains the information of ONE line
//now loop over the string stream object as you would have in your code sample:
while(getline(iss, temp,'~'))
{
//at this point temp is the value of a token, but it is a string
result.push_back(temp); //note: this only stores the TOKENS as strings
//so to store the token as a int or float, you need to convert it to that
//via another stringstream:
std::istringstream ss(temp);
//if your number type is float, change it here as well as in the vector
//initialization of `numbers`:
int num = 0;
//this checks the stream to ensure that conversion occurred.
//if it did, store the number, otherwise, handle the error (quit - but, this is up to you)
//if stringstreams aren't your cup of tea, try some others (refer to this link):
//http://stackoverflow.com/questions/21807658/check-if-the-input-is-a-number-or-string-c/21807705#21807705
if (!(ss >> num).fail()) {
numbers.push_back(num);
}
else {
std::cerr << "There was a problem converting the string to an integer!" << std::endl;
}
}
}
Note: this version stores the numbers verbatim: i.e. without a sense of how many numbers were on a line. However, that is reconcilable as all you have to do is output n numbers per line. In your case, you know every 2 numbers will be represent the numbers in a line.
This requires:
#include <string>
#include <vector>
#include <cstdlib>
#include <sstream>

first string in array of strings is being skipped

Somehow when I run this code and it comes to inputting strings, the first string where i=0 is being skipped and it starts entering strings from A[1]. So I end up with A[0] filled with random stuff from memory. Can someone please point at the problem?
cin>>s;
char** A;
A = new char *[s];
cout<<"now please fill the strings"<<endl;
for (int i=0;i<s;i++)
{
A[i] = new char[100];
cout<<"string "<<i<<": ";
gets(A[i]);
}
That code is horrible. Here's how it should look like in real C++:
#include <string>
#include <iostream>
#include <vector>
int main()
{
std::cout << "Please start entering lines. A blank line or "
<< "EOF (Ctrl-D) will terminate the input.\n";
std::vector<std::string> lines;
for (std::string line; std::getline(std::cin, line) && !line.empty(); )
{
lines.push_back(line);
}
std::cout << "Thank you, goodbye.\n";
}
Note the absence of any pointers or new expressions.
If you like you can add a little prompt print by adding std::cout << "> " && at the beginning of the conditional check in the for loop.
Probably because you're using gets()... never use gets()
Use fgets() instead.
gets vs fgets
The problem is that cin>>s; just picks up the number you want and leaves a \n (newline from the enter press) on stdin that gets() picks up in the first iteration. This is not the nicest way to fix it, but to prove it write this line after that line:
int a = fgetc(stdin);
Check out a afterwards to confirm it has a newline.
Well, you probably get an empty string: when reading s you use formatted input which stops as soon as a non-digit is encountered, e.g., the newline used to indicate its input is finished. gets(), thus, immediately finds a newline, terminating the first string read.
That said, you shall never use gets(): It is a primary security problem and the root cause of many potential attack! You should, instead, use fgets() or, better, yet, std::getline() together with std::strings and a std::vector<std::string> >. Aslo, you should always verify that the attempt to input was successful:
if ((std::cin >> s).ignore(std::numeric_limits<std::streamsize>::max(), `\n`)) {
std::string line;
for (int i(0); i != s && std::getline(std::cin, line); ) {
A.push_back(line);
}
}

String is not printing without new line character in C++

I'm opening a file, and getting lines from it.
The first line should say how many variables there are, and what their names are.
The second line should be a logic equation using these variables.
The assignment is to have it print out a truth table for the variables and equation.
The first line the program is taking in is not printing without me inserting a new line character. I tried converting to a string and using both printf and cout.
Main file that inputs everything:
#include "truthTable2.h"
int main(int argc, const char* argv[]){
ifstream inFile;
if(argc != 2){
cout << "Enter an input file name: ";
char *inFileName = "";
cin >> inFileName;
inFile.open(inFileName);
}
else
inFile.open(argv[1]);
TruthTable tTable;
while(!inFile.eof()){
char variableLine[256];
inFile.getline(variableLine, 256);
printf("%s ", variableLine);
string variable(variableLine);
tTable.setVariables(variable);
char formulaLine[256];
inFile.getline(formulaLine, 256);
cout << formulaLine << "\n";
string formula(formulaLine);
tTable.setFormula(formula);
tTable.printTable();
}
inFile.close();
return 0;
}
Sample input:
2 x y
( \wedge x ( \not y ) )
Output from this:
( \wedge x ( \not y ) )
I think whatever is causing this is giving me problems throughout the rest of the program as well. After I tokenize the variableLine it does not print without a new line character and it does not find the second variable when evaluating the formula.
An std::ostream's output needs to be flushed. It is normally flushed automatically when a line-feed \n is written. If you want to force the stream to flush, you can use the std::flush manipulator like so:
std::cout << "foo" << std::flush;
Edit: Although my post clearly answers the question "Why does my line not show up unless I output a \n character?" You said this does not answer your question, so I will attempt some mind reading to try and answer your real question.
Since I have no idea what you really want know, I'll point out several things here that are wrong with your code and it might help you find your problem or clarify your question.
First, if you are using the file name input from std::cin, when argc<2, you will, a 100% guaranteed, cause a failure in your application. The reason is that the character buffer pointed to by inFileName contains a single byte, reserved for the terminating null character. If someone enters any text whatsoever, you will get a buffer overrun. If someone enters an empty string, your program will open no file and inFile.open(...); will return an error code that you don't check, so your program won't crash, but still won't work.
Second, the other line inputs are needlessly limited to 256 characters and are just as dangerous (i.e. lines longer that 256 characters will cause a bufer overrun). Since you eventually create std::string instances out of the content, you should just plainly use std::getline(). It is shorter to type, more general and safer.
Third, the description of your problem is that no output is generated unless you add a \n character. As I explained, this is perfectly normal. From re-reading your post, I can understand that you don't unhderstand why you should have to add one given that there was already one in the input file. The reason you need to add it is because the getline() functions discard the \n character. It is not inserted into your line's buffer.
I've cleaned up some of your code to show you some clear improvements. From this code you will be able to understand the structure of your program, which should also reflect the structure of your input.
#include "truthTable2.h"
int main(int argc, const char* argv[]){
std::ifstream inFile;
if(argc != 2){
cout << "Enter an input file name: ";
std::string inFileName;
std::getline(std::cin, inFileName);
inFile.open(inFileName.c_str());
}
else {
inFile.open(argv[1]);
}
if ( !inFile.is_open() ) {
// Did not successfully open a file. Print error message and exit!
}
TruthTable tTable;
for (std::string variables; std::getline(inFile,variables); )
{
std::cout << variables << std::endl;
tTable.setVariables(variable);
std::string formula std::getline(formula);
std::cout << formula << std::endl;
tTable.setFormula(formula);
tTable.printTable();
}
return 0;
}
From this, I have a question:how is your input structured? Is your input file only consisted of 2 lines? Are there multiple sets of these line pairs? Is there a single line with variables and a bunch of equations? These three cases will lead me to re-structure the program in one of the following fashions:
2 lines only:
ThruthTable table;
std::string variables, equation;
std::getline(file, variables);
std::getline(file, equation);
// ...
Multiple sets:
while ( !inFile.eof() )
{
ThruthTable table;
std::string variables, equation;
std::getline(file, variables);
std::getline(file, equation);
// ...
}
Multiple equations:
ThruthTable table;
std::string variables;
std::getline(variables);
for ( std::string equation; std::getline(file, equation); )
{
std::getline(file, equation);
// ...
}
If what I am seeing is right, the output from printf is the one that is not showing. In that case, either use
fflush(stdout);
Or better, just go with a std::cout for that line since you're writing it in C++ (using the std::flush technique, of course.)