This question already has answers here:
Read file line by line using ifstream in C++
(8 answers)
Closed 3 years ago.
I'm trying to read a file line by line. My file is somewhat like this:
a 4 558 5
a 123 145 782
x 47 45 789
If the first character is a, i want to store the three values in front of it in an array. I'm trying this but it doesn't seem to work:
while (std::getline(newfile, line))
{
if (line[0] == 'a')
{
vertex[0] = line[1];
vertex[1] = line[2];
vertex[2] = line[3];
//vertices.push_back(vertex);
}
I'm trying this but it doesn't seem to work:
When you use
vertex[0] = line[1];
the 1-th character of line is assigned to vertex[0]. It's not your intent. You want to assign the first number after a in the line to vertex[0].
You can use std::istringstream to extract the numbers.
if (line[0] == 'a')
{
// Make sure to ignore the the first character of the line when
// constructing the istringstream object.
std::istringstream str(&line[1]);
str >> vertex[0] >> vertex[1] >> vertex[2];
}
This bit of code incorporates the advice and answers to this point.
#include <fstream>
#include <string>
#include <sstream>
#include <iostream>
int main()
{
std::ifstream newfile("vals");
if (!newfile)
std::cout << "Exiting...\n";
std::string line;
int vertex[3][3];
int i = 0;
while(std::getline(newfile, line)) {
if (line.empty()) continue;
if (line[0] == 'a') {
// Make sure to ignore the the first character of the line when
// constructing the istringstream object.
std::istringstream str(&line[1]);
str >> vertex[i][0] >> vertex[i][1] >> vertex[i][2];
}
++i;
}
newfile.close();
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 3; ++k) {
std::cout << vertex[j][k] << ' ';
}
std::cout << '\n';
}
}
The issue is that the variable line is a std::string, and using [n] on a string will get you the character and index n, and you're trying to get the nth word.
Another way to go about this (for the learning, the above code uses the preferred method) would be to manually extract the numbers yourself.
#include <fstream>
#include <string>
#include <iostream>
int main()
{
std::ifstream newfile("vals");
if (!newfile)
std::cout << "Exiting...\n";
std::string line;
int vertex[3][3];
int i = 0;
while(std::getline(newfile, line)) {
if (line.empty()) continue;
if (line[0] == 'a') {
line = line.substr(2);
int j = 0;
std::string::size_type loc;
do {
loc = line.find_first_of(" ");
std::string tmp = line.substr(0, loc);
vertex[i][j] = std::stoi(tmp);
line = line.substr(loc + 1);
++j;
} while(loc != std::string::npos);
}
++i;
}
newfile.close();
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 3; ++k) {
std::cout << vertex[j][k] << ' ';
}
std::cout << '\n';
}
}
It should be pretty clear why the stringstream method is preferred. This method manually chops up line and manually converts the extracted number (still stored as a string) into an int for storing in the array. Meanwhile, the above method hides a lot of the dirty work from you, and does the work pretty darn efficiently as well. While I probably don't have to keep trimming the variable line in the second example (but I'd need another variable instead), my rebuttal is that I simply wouldn't have chosen this route in the first place.
Related
The following C++ program takes two text files, stop_words.txt, and story.txt. It then removes all the stop word occurrences in the story.txt file. For instance,
Monkey is a common name that may refer to groups or species of mammals, in part, the simians of infraorder L. The term is applied descriptively to groups of primates, such as families of new world monkeys and old world monkeys. Many monkey species are tree-dwelling (arboreal), although there are species that live primarily on the ground, such as baboons. Most species are also active during the day (diurnal). Monkeys are generally considered to be intelligent, especially the old world monkeys of Catarrhini.
the text above is story.txt, and the stop_words.txt file is given below:
is
are
be
When I run my code, it doesn't delete all the stop words and keeps some of them. The code also creates a file called stop_words_counter.txt which should display the number of stop word occurrences like so:
is 2
are 4
b 1
But my output file shows the following:
is 1
are 4
be 1
I would be very grateful for some help regarding this code! I have posted it below for your reference.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
const int MAX_NUM_STOPWORDS = 100;
struct Stop_word
{
string word; // stop word
int count; // removal count
};
int stops[100];
string ReadLineFromStory(string story_filename )
{
string x = "";
string b;
ifstream fin;
fin.open(story_filename);
while(getline(fin, b))
{
x += b;
}
return x;
}
void ReadStopWordFromFile(string stop_word_filename, Stop_word words[], int &num_words)
{
ifstream fin;
fin.open(stop_word_filename);
string a;
int i = 0;
if (fin.fail())
{
cout << "Failed to open "<< stop_word_filename << endl;
exit(1);
}
words[num_words].count = 0;
while (fin >> words[num_words].word)
{
++num_words;
}
fin.close();
}
void WriteStopWordCountToFile(string wordcount_filename, Stop_word words[], int num_words)
{
ofstream fout;
fout.open(wordcount_filename);
for (int i = 0; i < 1; i++)
{
fout << words[i].word << " "<< stops[i] + 1 << endl;
}
for (int i = 1; i < num_words; i++)
{
fout << words[i].word << " "<< stops[i] << endl;
}
fout.close();
}
int RemoveWordFromLine(string &line, string word)
{
int length = line.length();
int counter = 0;
int wl = word.length();
for(int i=0; i < length; i++)
{
int x = 0;
if(line[i] == word[0] && (i==0 || (i != 0 && line[i-1]==' ')))
{
for(int j = 1 ; j < wl; j++)
if (line[i+j] != word[j])
{
x = 1;
break;
}
if(x == 0 && (i + wl == length || (i + wl != length && line[i+wl] == ' ')))
{
for(int k = i + wl; k < length; k++)
line[k -wl] =line[k];
length -= wl;
counter++;
}
}
}
line[length] = 0;
char newl[1000] = {0};
for(int i = 0; i < length; i++)
newl[i] = line[i];
line.assign(newl);
return counter;
}
int RemoveAllStopwordsFromLine(string &line, Stop_word words[], int num_words)
{
int counter[100];
int final = 0;
for(int i = 1; i <= num_words; i++)
{
counter[i] = RemoveWordFromLine(line, words[i].word);
final += counter[i];
stops[i] = counter[i];
}
return final;
}
int main()
{
Stop_word stopwords[MAX_NUM_STOPWORDS]; // an array of struct Stop_word
int num_words = 0, total = 0;
// read in two filenames from user input
string a, b, c;
cin >> a >> b;
// read stop words from stopword file and
// store them in an array of struct Stop_word
ReadStopWordFromFile(a, stopwords, num_words);
// open text file
c = ReadLineFromStory(b);
// open cleaned text file
ofstream fout;
fout.open("story_cleaned.txt");
// read in each line from text file, remove stop words,
// and write to output cleaned text file
total = RemoveAllStopwordsFromLine(c, stopwords, num_words) + 1 ;
fout << c;
// close text file and cleaned text file
fout.close();
// write removal count of stop words to files
WriteStopWordCountToFile("stop_words_count.txt", stopwords, num_words);
// output to screen total number of words removed
cout << "Number of stop words removed = " << total << endl;
return 0;
}
There is one major bug in your code.
in function RemoveAllStopwordsFromLine
you are using the wrong array indices. In C++ the first element in an array has the index 0. Also you must compare with "less" than the size.
for (int i = 1; i <= num_words; i++)
So the first stop word "is", will never be checked and counted.
Please modify to
for (int i = 0; i < num_words; i++)
But then you need also to remove your patch in function WriteStopWordCountToFile . You made a special case for element 0. That is wrong.
Please remove
for (int i = 0; i < 1; i++)
{
fout << words[i].word << " " << stops[i] + 1 << endl;
}
and start the next for with 0. And remove the "+" while calculating the total.
Because you are using C-Style arrays, magic numbers and ultra complex code, I will show you a modern C++ solution.
In C++ you have many useful algorithms. Some are specifically designed to address your requirments. So, please use them. Try to get away from C and migrate to C++.
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <regex>
#include <sstream>
// The filenames. Whatever you want
const std::string storyFileName{ "r:\\story.txt" };
const std::string stopWordFileName{ "r:\\stop_words.txt" };
const std::string stopWordsCountFilename{ "r:\\stop_words_count.txt" };
const std::string storyCleanedFileName{ "r:\\story_cleaned.txt" };
// Becuase of the simplicity of the task, put everything in main
int main() {
// Open all 4 needed files
std::ifstream storyFile(storyFileName);
std::ifstream stopWordFile(stopWordFileName);
std::ofstream stopWordsCountFile(stopWordsCountFilename);
std::ofstream storyCleanedFile(storyCleanedFileName);
// Check, if the files could be opened
if (storyFile && stopWordFile && stopWordsCountFile && storyCleanedFile) {
// 1. Read the complete sourcefile with the story into a std::string
std::string story( std::istreambuf_iterator<char>(storyFile), {} );
// 2. Read all "stop words" into a std::vector of std::strings
std::vector stopWords(std::istream_iterator<std::string>(stopWordFile), {});
// 3. Count the occurences of the "stop words" and write them into the destination file
std::for_each(stopWords.begin(), stopWords.end(), [&story,&stopWordsCountFile](std::string& sw) {
std::regex re{sw}; // One of the "stop words"
stopWordsCountFile << sw << " --> " << // Write count to output
std::distance(std::sregex_token_iterator(story.begin(), story.end(), re, 1), {}) << "\n";});
// 4. Replace "stop words" in story and write new story into file
std::ostringstream wordsToReplace; // Build a list of all stop words, followed by an option white space
std::copy(stopWords.begin(), stopWords.end(), std::ostream_iterator<std::string>(wordsToReplace, "\\s?|"));
storyCleanedFile << std::regex_replace(story,std::regex(wordsToReplace.str()), "");
}
else {
// In case that any of the files could not be opened.
std::cerr << "\n*** Error: Could not open one of the files\n";
}
return 0;
}
Please try to study and understand this code. This is a very simple solution.
I have been working the Project 15 in Chapter 12 of Walter Savitch Absolute C++ (5th ed.) for a long time. The problem is at the bottom, which you can check if you are interested in my problem.
I figure out one way to solve this problem which is to read the file containing a paragraph many times and at each time, locate the keyword, the line number and the context. But it sounds to me very tedious. So I tried to read the file only twice. At the first time reading it, I locate all the keywords and line numbers. At the second time reading the file, I determine the context. But I failed.
I do not attempt to fix bugs in my code (
// header file for project 15
#ifndef PROJECT15_H
#define PROJECT15_H
#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
#include<cstring>
#include<iomanip>
#include<vector>
using std::ios;
using std::cout;
using std::endl;
using std::setw;
using std::string;
using std::istream;
using std::ostream;
using std::ifstream;
using std::ofstream;
using std::stringstream;
const int MAX_CHARACTERS = 72;
const int N_CHARACTERS_BEFORE = 2;
const int N_CHARACTERS_AFTER = 1;
namespace
{
void sortKWIX(string** list, int size);
void advanceChain(string chain[], string newStr);
void printKWIX(string** list, int size, ostream& outStream);
} // namespace
namespace project15
{
void getKWIX(string keyWords[], int size, string file, ostream& outStream);
} //namespace project15
#endif // PROJECT15_H
/******************************************************************************//******************************************************************************//******************************************************************************/
// function definitions for project 15
#include"Project15.h"
namespace
{
void sortKWIX(string** list, int size)
{
string tmp;
for (int outer = 0; outer < size - 1; outer++)
for (int inner = outer + 1; inner < size; inner++)
if (strcmp(list[outer][0].c_str(), list[inner][0].c_str()) > 0)
{
for (int index = 0; index < 3; index++)
{
tmp = list[outer][index];
list[outer][index] = list[inner][index];
list[inner][index] = tmp;
}
}
}
void advanceChain(string chain[], string newStr)
{
for (int index = 0; index < N_CHARACTERS_AFTER + N_CHARACTERS_BEFORE; index++)
chain[index] = chain[index + 1];
chain[N_CHARACTERS_AFTER + N_CHARACTERS_BEFORE] = newStr;
}
void printKWIX(string** list, int size, ostream& outStream)
{
outStream.setf(ios::left);
outStream.width(12);
outStream << "KWIX Listing:\n"
<< "Keyword " << "Line Number " << "Keyword in Context\n";
for (int index = 0; index < size; index++)
{
for (int ncol = 0; ncol < 3; ncol++)
outStream << list[index][ncol] << " ";
outStream << endl;
}
}
} // namespace
namespace project15
{
void getKWIX(string keyWords[], int size, string file, ostream& outStream)
{
using namespace std;
ifstream fin(file.c_str());
if (fin.fail())
{
cout << "Input file openning failed.\n";
exit(1);
}
string inp;
char next;
int nChars = 0;
int nline = 0;
int position = 0;
vector<string> keys;
vector<int> positions;
vector<int> nlines;
while (fin >> inp)
{
position++;
if (!fin.eof())
fin.get(next);
else
next = '\0';
// determine line number
if ((nChars + inp.length() > MAX_CHARACTERS) || (next == '\n'))
{
nline++;
nChars = inp.length();
}
else
nChars += inp.length();
if (next != '\n')
nChars++;
if (!fin.eof() && (fin.peek() == '\n'))
nline++;
// determine whether inp is a keyword
// first, determine if the last character in inp is not an alphabet
if (!(isalpha(inp[inp.length() - 1])))
inp = inp.substr(0, inp.length() - 1);
for (int index = 0; index < size;index++)
if (inp == keyWords[index])
{
keys.push_back(inp);
positions.push_back(position);
nlines.push_back(nline);
break;
}
}
fin.close();
// open the file for the 2nd time to get contexts
fin.open(file.c_str());
if (fin.fail())
{
cout << "Input file openning failed.\n";
exit(1);
}
position = 0;
int index = 0;
vector<string> contexts;
string tmp[N_CHARACTERS_AFTER + N_CHARACTERS_BEFORE + 1];
for (int iter = 0; iter < N_CHARACTERS_AFTER + N_CHARACTERS_BEFORE + 1; iter++)
tmp[iter] = "";
while (fin >> inp)
{
//position++;
advanceChain(tmp, inp);
if (!fin.eof())
fin.get(next);
else
next = '\0';
// determine where to start to save contexts
if (positions[index] - position <= N_CHARACTERS_BEFORE)
{
// determine where to start to save strings
string str = "";
if (positions[index] - N_CHARACTERS_BEFORE < 0)
{
for (int iter = N_CHARACTERS_AFTER + N_CHARACTERS_BEFORE - position; iter < N_CHARACTERS_AFTER + N_CHARACTERS_BEFORE + 1; iter++)
str += tmp[iter];
position++;
}
else
{
for (int iter = N_CHARACTERS_AFTER - position + positions[index]; iter < N_CHARACTERS_AFTER + N_CHARACTERS_BEFORE + 1; iter++)
str += tmp[iter];
position++;
}
for (int iter = 0; iter < N_CHARACTERS_AFTER; iter++)
{
if (!fin.eof())
{
fin >> inp;
advanceChain(tmp, inp);
str += inp;
position++;
}
}
contexts.push_back(str);
index++;
}
}
fin.close();
// form a new list
string** list = new string*[keys.size()];
for (int i = 0; i < keys.size(); i++)
list[i] = new string[3];
stringstream ss;
for (int nrow = 0; nrow < keys.size(); nrow++)
{
list[nrow][0] = keys[nrow];
ss.str("");
ss << nlines[nrow];
list[nrow][1] = ss.str();
list[nrow][2] = contexts[nrow];
}
sortKWIX(list, keys.size());
printKWIX(list, keys.size(), outStream);
}
} //namespace project15
) right now, but I want to hear from you what kind of method you would like to use to solve this problem. Would you give me some hint?
===================================================================== Problem:
In this program you are to process text to create a KWIX table (Key Word In conteXt table). The idea is to produce a list of keywords (not programming language keywords, rather words that have important technical meaning in a discussion),then for each instance of each keyword, place the keyword, the line number of the context, and the keyword in its context in the table. There may be more than one context for a given keyword. The sequence of entries within a keyword is to be the order of occurrence in the text. For this problem, “context” is a user-selected number of words before the keyword, the keyword itself, and a user-selected number of words after the keyword. The table has an alphabetized column of keywords followed by a line number(s) where the keyword occurs, followed by a column of all contexts within which the keyword occurs. See the following example.
Hints: To get your list of keywords, you should choose and type in several paragraphs from the text, then omit from your paragraph “boring” words such as forms of the verb “to be”; pronouns such as I, me, he, she, her, you, us, them, who, which, etc. Finally, sort the keyword list and remove duplicates. The better job you do at this, the more useful output you will get.
Example: A paragraph and its KWIX Listing:
There are at least two complications when reading and writing with random access via an fstream : (1) You normally work in bytes using the typechar or arrays of char and need to handle type conversions on your own, and (2) you typically need to position a pointer (indicating where the read or write begins) before each read or write.
KWIX Listing:
Keyword Line Number Keyword in Context
access 2 with random access via
arrays 3 char or arrays of
bytes 2 work in bytes using char 3 the type
char or
char 3 array of char and
conversions 3 handle type conversions on
The table is longer than these sample entries.
I'm designing a program to clean up a text file that contains code. It removes comments, excess spaces/lines, and creates a new line for lines in the file with multiple semi-colons.
I actually got this program to work, but it used arrays. Since I am working on another program that builds on this, except with a more diverse size of data inputs, I'm converting it to use vectors instead of standard arrays so I can re-purpose the program...which is kind of the point.
My problem is that after the program iterates through the first for-loop, the rest of the for-loops initialize the iterator with a value of '3435973836', regardless of proper declaration ('int i = 0', 'int k = 0', etc). I declare them unsigned and omitting singed/unsigned still initializes the value incorrectly (-858993460).
This does 1 of 2 things:
unsigned the loop never starts as the value is too high to start the loop.
omitting makes the loop run for a long, long time.
Any thoughts? I've posted the code below. Please ignore any other errors I've made other than this, as I have been unable to get past this to debug anything else.
EDIT --> SOLVED: the problem that I was passing the vectors by value. But even when I changed it to pass by reference the program would still not work. The actual problem was with Microsoft Visual Studio 2012. Once I PBV once, it corrupted my project. I had to start a new VS project and insert the code. If you do this, be careful you don't run the program while still PBV or you'll have to do it again. I don't know why this happens. Maybe somebody who knows MS Visual Studio could answer that.
Thanks again community!
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void removeComments(vector<string> row, ifstream & myfile);
void sortLines (vector<string> row);
//void cleanCode (vector<string> row);
int main()
{
vector<string> row;
ifstream myfile;
//Open txt file
myfile.open("newdata.txt");
if(myfile.is_open())
{
//Remove comments, create proper lines, and remove/add spaces.
removeComments(row, myfile);
sortLines(row);
//cleanCode(row);
}
else
{
cout<< "ERROR: No file was able to open. Check the file name or location and try again."<< endl << endl;
}
for (unsigned int i = 0; i < row.size(); i++)
{
cout<< row[i] << endl;
}
cout<< endl;
myfile.close();
system("PAUSE");
return 0;
}
//FUNCTIONS
//Removes all comments.
void removeComments(vector<string> row, ifstream & myfile)
{
string line;
while(getline(myfile, line))
{
string tempString;
for(unsigned int i = 0; i < line.length(); i++)
{
//Copy characters to row string array until "//".
//All character following and including "//" will be ignored.
if(line.at(i) == '/' && line.at(i+1) == '/')
{
break;
}
else
{
tempString += line.at(i);
}
}
row.push_back(tempString);
}
}
//Creates a new line after every semi-colon.
void sortLines (vector<string> row)
{
vector<string> tempRow;
string tempLine;
string tempString;
for (unsigned int i = 0; i < row.size(); i++)
{
tempLine = row [i];
for (unsigned int j = 0; j < tempLine.length(); j++)
{
tempString += tempLine[j];
if (tempLine[j] == ';')
{
tempRow.push_back(tempString);
}
}
}
//Revalue row array elements.
//DEBUGGING OUTPUT
for (unsigned int i = 0; i < tempRow.size(); i++)
{
cout<< tempRow[i] << endl;
}
row.clear();
row = tempRow;
}
Okay, this is my by-reference edit:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void removeComments(vector<string> &row, ifstream & myfile);
void sortLines (vector<string> &row);
//void cleanCode (vector<string> &row);
int main()
{
vector<string> row;
ifstream myfile;
//Open txt file
myfile.open("newdata.txt");
if(myfile.is_open())
{
//Remove comments, create proper lines, and remove/add spaces.
removeComments(row, myfile);
sortLines(row);
//cleanCode(row);
}
else
{
cout<< "ERROR: No file was able to open. Check the file name or location and try again."<< endl << endl;
}
for (unsigned int i = 0; i < row.size(); i++)
{
cout<< row[i] << endl;
}
cout<< endl;
myfile.close();
system("PAUSE");
return 0;
}
//FUNCTIONS
//Removes all comments.
void removeComments(vector<string> &row, ifstream & myfile)
{
string line;
while(getline(myfile, line))
{
string tempString;
for(unsigned int i = 0; i < line.length(); i++)
{
//Copy characters to row string array until "//".
//All character following and including "//" will be ignored.
if(line.at(i) == '/' && line.at(i+1) == '/')
{
break;
}
else
{
tempString += line.at(i);
}
}
row.push_back(tempString);
}
}
//Creates a new line after every semi-colon.
void sortLines (vector<string> &row)
{
vector<string> tempRow;
string tempLine;
string tempString;
for (unsigned int i = 0; i < row.size(); i++)
{
tempLine = row [i];
for (unsigned int j = 0; j < tempLine.length(); j++)
{
tempString += tempLine[j];
if (tempLine[j] == ';')
{
tempRow.push_back(tempString);
}
}
}
//Revalue row array elements.
//DEBUGGING OUTPUT
for (unsigned int i = 0; i < tempRow.size(); i++)
{
cout<< tempRow[i] << endl;
}
row.clear();
row = tempRow;
}
As others have noted you're:
Passing vectors by value
Using something possibly uninitialized out-of-my-scope (this is nowhere declared/defined in your question) as increment variable
//Creates a new line after every semi-colon.
void sortLines (vector<string> row)
{
vector<string> tempRow;
string tempLine;
string tempString;
for (unsigned int i = 0; i < row.size(); k++) // <-- what is k??
{
Why pass "string line" to removeComments? It should be local to that function cos you don't use it outside. It looks dodgy for the same reason that the passed vectors did.
I am a high school student programming as a hobby. I make free stuff and I am working on a game using opengl. I need to save and load data but when met with difficulty I made the following to test my methods.
The save file 'shiptest' is correct but when I open the second file 'shipout' which is created with the save data from 'shiptest' only the first line is there. At first I thought that my array wasn't loading any new data and the clear function wasn't getting rid of the first elements. I corrected this assumption by overwriting those lines after saving the data and observing that the saved lines were loaded after all. My new assumption is that the getline func is only getting the first line each time it's called; but i do not know how to fix this.
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
unsigned short int shipPart;
float editShip[256][3];//part ID, x relative, y relative, r,g,b
float activeShip[256][3];
void CLEAR(bool edit)
{
for (int n = 0; n < 256; n++)
{
if (edit)
editShip[n][0] = -1;
else
activeShip[n][0] = -1;
}
}
void saveEdit(std::string name)
{
std::ofstream out;
out.open ("ship" + name + ".txt", std::ofstream::out);
for (int n = 0; n < 256; n++)
{
for (int i = 0; i < 3; i++)
{
if (editShip[n][0] == -1)
break;
out << editShip[n][i] << " ";
}
out << "\n";
}
out.close();
}
void load(std::string name, bool edit)
{
CLEAR(edit);
std::ifstream in;
in.open ("ship" + name + ".txt", std::ifstream::in);
std::string line, buf;
std::stringstream ss;
int i;
for (int n = 0; n < 3; n++)
{
getline(in, line);
ss << line;
i=0;
while (ss >> buf)
{
if (edit)
editShip[n][i] = atof(buf.c_str());
else
activeShip[n][i] = atof(buf.c_str());
i++;
}
}
in.close();
}
int main()
{
for (int n = 0; n < 256; n++)
{
editShip[n][0] = -1;
activeShip[n][0] = -1;
}
editShip[0][0] = 5;
editShip[0][1] = .11;
editShip[0][2] = .22;
editShip[1][0] = 4;
editShip[1][1] = .33;
editShip[1][2] = .44;
editShip[2][0] = 3;
editShip[2][1] = .55;
editShip[2][2] = .66;
saveEdit("test");
editShip[0][0] = 5000;
editShip[0][1] = 8978;
editShip[0][2] = 8888;
load("test",1);
saveEdit("out");
std::cout << "Hello world!" << std::endl;
return 0;
}
In load(), you keep appending more lines to your stringstream ss but its eof flag is probably remaining set from the previous time through the loop, so even though there's more to read from it, eof is already set so it won't continue providing data via operator>>(). If you simply call ss.clear() at the top of the for() loop, you'll start with an empty stringstream on each loop, and I think you'll get what you want.
In your load() function:
for (int n = 0; n < 3; n++)
{
ss.clear(); //< Clear ss here before you use it!
getline(in, line);
ss << line;
i=0;
while (ss >> buf)
{
if (edit)
editShip[n][i] = atof(buf.c_str());
else
activeShip[n][i] = atof(buf.c_str());
i++;
}
}
Getline() was working just fine. Just clear the stringstream before you use it and you're good to go. Ran this code on my computer and it works as desired.
EDIT: Ack! Just saw that phonetagger said the same thing while I was making my answer. He deserves the +1's not me.
How to solve this? https://code.google.com/codejam/contest/351101/dashboard#s=p1?
The code I ended up with is below, but it can only reverse strings up to one space because it was code keeping the literal logic in mind, Reverse the whole string, reverse the words, and done. The spaces are slightly messed up and when I tried a loop to detect number of spaces and act accordingly it failed. Please help! Code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
char revwrd[100];
char revstr[100];
string str;
getline(cin, str);
cout<<str;
int sps[10];
int len,y=0;
len = str.length();
cout<<"\n"<<"The Length of the string is:"<<len;
for(int x=len-1;x>-1;x--)
{
revstr[x] = str[y];
y++;
}
cout<<"\n"<<"The inverse of the string is:"<<"\n";
for(int z = 0;z<len;z++)
{
cout<<revstr[z];
}
cout<<"\n";
int no=0;
int spaces=0;
for(int a=0;a<len;a++)
{
if(revstr[a]== ' ')
{
sps[no]=a;
no++;
spaces++;
}
}
int rinc=0;
int spinc;
cout<<"\n";
spinc=sps[0];
int spinc2 = sps[0]+1;
int lend;
for(rinc=0;rinc<sps[0]+1;rinc++)
{
revwrd[rinc] = revstr[spinc];
spinc--;
}
for(lend=len;lend>sps[0];lend--)
{
revwrd[spinc2] = revstr[lend];
spinc2++;
}
cout<<"Spaces in the string:"<<spaces<<"\n";
cout<<"The words inversed are:"<<"\n";
for(int inc=1;inc<len+1;inc++)
{
cout<<revwrd[inc];
}
return 0;
}
The conditions of the challenge are that there is only a single space between words, and that spaces don't appear at the beginning or the end of the line, so for this particular exercise you don't have to worry about preserving spacing; as long as you write the output with a single space between each word, you're good.
With that in mind, you can read each word using regular formatted input:
std::string word;
...
while ( stream >> word )
// do something with word
You don't have to worry about buffer size, you don't have to worry about detecting spaces, etc. You do have to worry about detecting the newline character, but that's easily done using the peek method:
while ( stream >> word )
{
// do something with word;
if ( stream.peek() == '\n' )
break;
}
The above loop will read individual words from the input stream stream until it sees a newline character (there's probably a better way to do that, but it works).
Now, in order to reverse each line of input, you obviously need to store the strings somewhere as you read them. The easiest thing to do is store them to a vector:
std::vector< std::string > strings;
...
while ( stream >> word )
{
strings.push_back( word );
if ( stream.peek() == '\n' )
break;
}
So now you have a vector containing all the strings in the line, you just have to print them out in reverse order. You can use a reverse iterator to walk through the vector:
std::vector< std::string >::reverse_iterator it;
for ( it = strings.rbegin(); it != strings.rend(); ++it )
{
std::cout << *it << " ";
}
std::cout << std::endl;
The rbegin() method returns an iterator that points to the last element in the vector; the rend() method returns an iterator that points to an element before the first element of the vector; ++it advances the iterator to point to the next item in the vector, going back to front; and *it gives the string that the iterator points to. You can get a little more esoteric and use the copy template function:
std::copy( strings.rbegin(),
strings.rend(),
std::ostream_iterator<std::string>( std::cout, " " )
);
That single method call replaces the loop above. It creates a new ostream_iterator that will write strings to cout, separated by a single space character.
For the conditions of this particular exercise, this is more than adequate. If you were required to preserve spacing, or to account for punctuation or capitalization, then you'd have to do something a bit lower-level.
Just few loops and if's:
// Reverse Words
#include <iostream>
#include <string>
using namespace std;
int main() {
int tc; cin >> tc; cin.get();
for(int t = 0; t < tc; t++) {
string s, k; getline(cin, s);
for(int i = (s.length()- 1); i >= 0; i--) {
if(s[i] == ' ' || (i == 0)) {
if(i == 0) k += ' ';
for(int j = i; j < s.length(); j++) {
k += s[j];
if(s[j+1] == ' ' ) break;
}
}
}
cout << "Case #" << t + 1 << " " << k << endl;
}
return 0;
}
This might handle multi spaces:
std::string ReverseSentence(std::string in)
{
std::vector<string> words;
std::string temp = "";
bool isSpace = false;
for(int i=0; in.size(); i++)
{
if(in[i]!=' ')
{
if(isSpace)
{
words.push_back(temp);
temp = "";
isSpace = false;
}
temp+=in[i];
}
else
{
if(!isSpace)
{
words.push_back(temp);
temp = "";
isSpace = true;
}
temp += " ";
}
}
std::reverse(words.begin(),words.end());
std::string out = "";
for(int i=0; i<words.size(); i++)
{
out+=words[i];
}
return out;
}
you can follow this method :
step 1 : just check for spaces in input array store their index number in an integer array.
step 2 : now iterate through this integer array from end
step a : make a string by copying characters from this index to previous index .
note : since for first element there is no previous element in that case you will copy from this index to end of the input string .
step b : step a will give you a word from end of input string now add these word with a space to make your output string .
I hope this will help you .
This problem is really made for recursion:
void reverse()
{
string str;
cin >> str;
if (cin.peek() != '\n' || cin.eof()) {
str = " " + str;
reverse();
}
cout << str;
}
int main(int argc, const char * argv[])
{
int count = 0;
cin >> count;
for (int i = 0; i < count; i++) {
cout << "Case #" << (i + 1) << ": ";
reverse();
cout << endl;
}
return 0;
}
So I read word by word and add one space in front of the word until end of line or file is reached. Once end of line is reached the recursion unwraps and prints the read strings in reversed order.
I went for the brute force, and I badly wanted to use pointers!
get the sentence
detect every word and put them in a container.
read backwards the container.
This is it:
#include <iostream>
#include <string>
#include <vector>
int main()
{
char *s1 = new char[100];
std::cin.getline(s1, 100);
std::vector<std::string> container;
char* temp = new char[100];
char *p1, *p0;
p1 =p0 = s1;
int i;
do{
if (*p1==' ' || *p1=='\0'){
//std::cout<<p1-p0<<' ';
for(i=0;i<p1-p0;++i) temp[i]=p0[i]; temp[i]='\0';
p0 = p1+1;
container.push_back(temp);
std::cout<<temp;
}
p1++;
}while(*(p1-1)!='\0');
std::cout<<std::endl;
for(int i=container.size()-1;i>=0;i--) std::cout<<container[i]<<' ';
return 0;
}