How to check if EOF (after using getline) - c++

See update below!
My code (now I included more):
while(getline(checkTasks, workingString)){
countTheDays = 0;
// Captures a clean copy of the line in tasks.dat in it's entirety, stores in workingString.
char nlcheck;
checkTasks.get(nlcheck);
if(nlcheck == '\n'){
}
else{
checkTasks.unget();
//getline(checkTasks, workingString);
// Breaks that line up into more usable pieces of information.
getline(check2,tName, '\t');
getline(check2,tDate, '\t');
getline(check2,trDate, '\t');
getline(check2,tComplete, '\n');
// Converts the string form of these pieces into usable integers.
stringstream(tDate.substr(0,tDate.find_first_of('/'))) >> year;
stringstream(tDate.substr(tDate.find_first_of('/')+1,tDate.find_last_of('/'))) >> month;
stringstream(tDate.substr(tDate.find_last_of('/')+1,tDate.length()-1)) >> day;
stringstream(tComplete) >> checkComplete;
stringstream(trDate) >> checkReminder;
// Adds the number of days until your task is due!
if(year != date[0]){
for(int i = date[1]; i <= 12; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays-= date[2];
for (int i = 1; i<= month; i++){
countTheDays +=System::DateTime::DaysInMonth(year, i);
}
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else if(month != date[1]){
for(int i = date[1]; i <= month; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays -= (date[2]);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else{
countTheDays+= System::DateTime::DaysInMonth(date[0], month);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
countTheDays -= date[2];
}
// If the task is nearing it's due date (the time frame specified to be notified) it'll notify user.
// Only coded to work if the task is due in the current or following months.
if(countTheDays <= checkReminder){
if( countTheDays < 0){
cout << endl << endl << tName << " is past due!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}
else{
cout << endl << endl << tName << " is due in " <<countTheDays << " days! Don't forget!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}
// If user doesn't want to be reminded, begins process of converting that line in the file to usable info
// and 'overwriting' the old file by creating a new one, deleting the old one, and renaming the new one.
if(continueToRemind == "n" || continueToRemind == "N"){
fileModified = true;
string line;
/* vector<string> lines;
while(getline(tasksClone, line)){
lines.push_back(line);
}
lines.erase(remove(lines.begin(), lines.end(), workingString), lines.end());
if (!lines.empty()) {
auto i=lines.begin();
auto e=lines.end()-1;
for (; i!=e; ++i) {
saveTasks << *i << '\n';
}
saveTasks << *i;
}*/
// This writes a copy of the tasks.dat file, minus the task that the user elected not to be notified of.'
while(getline(tasksClone, testBuffer)){
if(testBuffer == workingString){
// This condition does nothing. Essentially erasing the 'completed' task from the list.
}
else if(testBuffer != workingString && tasksClone.eof()){
// This writes everything except the specified task to taskbuffer.dat
saveTasks << testBuffer;
}
else {
saveTasks << testBuffer << '\n';
}
}
}
}
}
}
}
else{
cout << "The tasks file is empty, you must not have any tasks!" << endl;
}
I hope that question makes sense!
Thanks
Marcus
UPDATE: Reworked the code, again. After telling it to delete 1 task, it never runs this loop. Current code:
while(getline(tasksClone, testBuffer)){
if(testBuffer == workingString){
// This condition does nothing. Essentially erasing the 'completed' task from the list.
}
else if(testBuffer != workingString && tasksClone.eof()){
// This writes everything except the specified task to taskbuffer.dat
saveTasks << testBuffer;
}
else {
saveTasks << testBuffer << '\n';
}
}
Input file:
test1 2012/12/13 10 0;
test2 2012/12/23 20 0;
test3 2012/12/31 28 0;
\n
Output file (after telling it to delete test1 and 2):
test2 2012/12/23 20 0;
test3 2012/12/31 28 0;
\n

The first thing I would do is just read your whole file into a vector of strings, each string corresponding to a line in the file. That can be done quite easily.
std::vector<std::string> lines;
std::string line;
while (std::getline(tasksClone, line))
lines.push_back(line);
Once you have that, processing becomes much easier. You can check if a line is empty like this:
if (lines[i].empty())
That's equivalent to checking if the next character after a newline is another newline. You can remove any lines from the vector that you don't want like this:
lines.erase(std::remove(lines.begin(), lines.end(), workingString), lines.end());
Instead of that though, you could avoid putting them into the vector in the first place by putting a test in the loop that reads the lines from the file.
Once you've done all your processing, you can just write the lines back out to the other file, inserting the newlines manually.
if (!lines.empty()) {
auto i=lines.begin(), e=lines.end()-1;
for (; i!=e; ++i) {
saveTasks << *i << '\n';
}
saveTasks << *i;
}

Instead of adding a new-line at the end of each line, but only if there's another line to write afterwards, I'd just precede each line by a new-line. That'll get you the new-line at the beginning of the file, and no new-line at the end, just as you want.
As usual, code like while (!your_file.eof()) is broken though. You probably want something like:
while (std::getline(taskClone, buffer)) {
if (buffer.empty())
continue;
if (keep(buffer)) // whatever condition you need
saveTasks << "\n" << buffer;
}
You can do the same thing a little more easily with std::remove_copy_if and my ostream_prefix_iterator:
// prefix_iterator.h
#include <ostream>
#include <iterator>
template <class T,
class charT=char,
class traits=std::char_traits<charT>
>
class prefix_ostream_iterator :
public std::iterator<std::output_iterator_tag,void,void,void,void>
{
charT const* delimiter;
std::basic_ostream<charT,traits> *os;
public:
typedef charT char_type;
typedef traits traits_type;
typedef std::basic_ostream<charT,traits> ostream_type;
prefix_ostream_iterator(ostream_type& s)
: os(&s),delimiter(0)
{}
prefix_ostream_iterator(ostream_type& s, charT const *d)
: os(&s),delimiter(d)
{}
prefix_ostream_iterator<T,charT,traits>& operator=(T const &item)
{
// Here's the only real change from ostream_iterator:
// Normally, the '*os << item;' would come before the 'if'.
if (delimiter != 0)
*os << delimiter;
*os << item;
return *this;
}
prefix_ostream_iterator<T,charT,traits> &operator*() {
return *this;
}
prefix_ostream_iterator<T,charT,traits> &operator++() {
return *this;
}
prefix_ostream_iterator<T,charT,traits> &operator++(int) {
return *this;
}
};
Using this along with a line proxy I posted in an earlier answer, you could do the job with code something like:
#include "line.h"
#include "prefix_iterator.h"
std::remove_copy_if(std::istream_iterator<line>(taskClone),
std::istream_iterator<line>(),
prefix_ostream_iterator<std::string>(taskSave, "\n"),
[](std::string const &line) { /* decide if to keep line*/});

It's not too clear what you are trying to do. std::getline
strips the trailing new line, so any time you output what you've
read, you have to add it. (If you're writing to a text file,
it's undefined behavior if the last character written isn't a
'\n'.)
Note too that your main loop is incorrect. The state of
tasksClone.eof() is indeterminate, and you don't verify that
the input has succeeded after doing the getline. What you
need is something like:
std::string line
while ( std::getline( tasksClone, line ) ) {
if ( line != workingString ) {
saveTasks << line << '\n';
}
}
In your example input, the first line you read will be empty.

I solved my problem, just in case anyone wants to know. It's not as memory efficient as it could be, but it functions:
// Reads the file, checks if it's due, and if it's due prompts user to either save or delete the task.
// Captures a clean copy of the line, in its entirety, and stores it to workingString.
while(getline(checkTasks,workingString)){
countTheDays = 0;
// Handles newline characters.
char nlcheck;
checkTasks.get(nlcheck);
if(nlcheck == '\n'){
}
else{
checkTasks.unget();
// Breaks that line up into more usable pieces of information.
getline(check2,tName, '\t');
getline(check2,tDate, '\t');
getline(check2,trDate, '\t');
getline(check2,tComplete, '\n');
// Converts the string from of these pieces into usable integers.
stringstream(tDate.substr(0,tDate.find_first_of('/'))) >> year; stringstream(tDate.substr(tDate.find_first_of('/')+1,tDate.find_last_of('/'))) >> month; stringstream(tDate.substr(tDate.find_last_of('/')+1,tDate.length()-1)) >> day;
stringstream(tComplete) >> checkComplete;
stringstream(trDate) >> checkReminder;
// Adds the number of days until your task is due!
if(year != date[0]){
for(int i = date[1]; i <= 12; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays-= date[2];
for (int i = 1; i<= month; i++){
countTheDays +=System::DateTime::DaysInMonth(year, i);
}
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else if(month != date[1]){
for(int i = date[1]; i <= month; i++){
countTheDays += System::DateTime::DaysInMonth(date[0], i);
}
countTheDays -= (date[2]);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
}
else{
countTheDays+= System::DateTime::DaysInMonth(date[0], month);
countTheDays -= (System::DateTime::DaysInMonth(year, month) - day);
countTheDays -= date[2];
}
// If the task is nearing it's due date (the time frame specified to be notified) it'll notify user.
if(countTheDays <= checkReminder){
if( countTheDays < 0){
cout << endl << endl << tName << " is past due!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}
else{
cout << endl << endl << tName << " is due in " <<countTheDays << " days! Don't forget!" << endl;
cout << "Should I keep reminding you about this task? Enter Y or N. ";
cin >> continueToRemind;
}
// If user doesn't want to be reminded, begins process of converting that line in the file to usable info
// and 'overwriting' the old file by creating a new one, deleting the old one, and renaming the new one.
if(continueToRemind == "n" || continueToRemind == "N"){
fileModified = true;
// Adds workingString to deleteTasks[] to be compared against later.
deleteTasks.push_back(workingString);
}
}
}
}
int match = 0;
// Iterates through tempTasks.dat and compares lines to workingString.
while(getline(tasksClone, testBuffer)){
for(int i = 0; i< deleteTasks.size(); i++){
// If a match is found, it sets the match flag to delete that line.
if(testBuffer == deleteTasks[i]){
match = 1;
}
}
// Deletes that task.
if(match == 1){
//Do nothing, erasing the task
}
// If EOF, writes only the task, without a newline character.
else if(tasksClone.eof()){
saveTasks << testBuffer;
}
// If !EOF, also writes a newline character.
else{
saveTasks << testBuffer << '\n';
}
match = 0;
}

You problem may be in using "\n" if you are viewing your files in Windows or Mac.
Try to use "\r\n" instead.

Related

C++ Program Assigning 0 to txt File's Empty Lines

I am trying to complete a program that should display a college course summary, and I am having problems to properly display all the student names and scores because my program is assigning the value of 0 to the text file's empty lines. How can I skip to the next line and ignore empty lines... is there any command for that? Here's the part of the code that's giving me problems:
while (getline(studentFile, name))
{
getline(studentFile, str);
score = atoi(str.c_str());
if (min > score)
{
min = score;
}
if (max < score)
{
max = score;
}
sum += score;
count++;
cout << setw(40) << left << name << setw(20) << left << score << endl;
}
Simply check the string that getline() outputs to see if it is empty or not, eg
while (getline(studentFile, name))
{
if (name.empty()) continue;
if (!getline(studentFile, str)) {
// error handling...
}
else if (str.empty()) {
// no value, do something else...
}
else {
// process value...
}
...
}

Reading stack pop/push operations by text-file input

I have a text file with the following contents:
2
S 8
push 2 push 3 push 5 push 7 pop print push 6 print
S 4
pop print push 1 print
An assignment gives:
The first line of the input file means the number of test cases. For each test case, the first character means which container adapter (Stack or Queue) that you need to use Linked lists to implement. The correct output should be:
The values in the stack : 2 3 5
The values in the stack : 2 3 5 6
The values in the stack :
The values in the stack : 1
I've written some working functions for stack and queue struct, though I am working on the input of the stack function first.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void push(int);
int pop();
void printStack();
struct Stack {
int s[100];
int top;
Stack() { top = -1; }
};
Stack st;
void push(int n) {
if (st.top == 99) {
cout << "Stack full" << endl;
}
else {
st.s[++st.top] = n;
}
}
int pop() {
if (st.top == -1) {
cout << "Stack is empty" << endl;
}
else {
return st.s[st.top--];
}
}
void printStack() {
cout << "Elements";
for (int i = 0;i <= st.top;i++) {
cout << st.s[i] << ' ';
}
cout << endl;
}
void clearStack() {
st.top = -1;
}
The main part of the code is giving me trouble. I want to read every token of the text file while keeping the line structure; e.g. being able to parse by order of line. However, I do not know the length of each line, only the number of lines. How may I read the file correctly and finish this assignment?
int main() {
std::ifstream file("input1.txt");
std::string item_name;
int numTestCases;
vector<string> file_content{};
while (std::getline(file, item_name))
{
//cout << item_name << "\n";
char str[252];
strcpy(str, item_name.c_str());
char* pch;
//cout << "str0:" << str[0] << "\n";
file_content.push_back(str);
}
cout << "printing file content:" << endl;
for (int i = 0;i < file_content.size(); i++) {
cout << file_content[i] << endl;
}
}
Okay, you basically have two distinct problems.
Read your input file so you know what actions to perform.
Implement both Stack and Queue.
So start by breaking them up. I looked at your stack code. Your problem says to use linked lists, which isn't what you're doing. Maybe that's just because you haven't gotten that far yet.
Code like this would give you the number of test cases.
std::string numCasesStr;
if (!getline(file, numCasesStr)) {
cout << "early end of file detected\n";
return;
}
int numCases = std::stoi(numCasesStr);
At this point, you can now do this:
for (int testCase = 0; testCase < numCases; ++testCase) {
std::string typeAndCountStr;
if (!getline(file, typeAndCountStr)) {
cout << "early end of file detected\n";
return;
}
char typeC = typeAndCountStr.at(0);
if (typeC == 'S') {
...
}
else if (typeC == 'Q') {
...
}
}
The harder part is parsing the next line. You're going to get input in a similar fashion, but then you have to break it into pieces. This is called tokenizing. Basically you split it at each space. What's useful is the find method on a string.
do {
size_t lastPos = 0;
size_t pos = str.find(' ', lastPos);
string thisArg;
if (pos != string::npos) {
thisArg = str.substr(lastPos, pos);
lastPos = pos + 1;
}
else {
thisArg = str.substr(lastPos);
}
// At this point, thisArg contains one argument. You still have more
// to do, but this is one way to split your string into pieces.
} while (lastPos != string::npos);
What I do with that is stuff the individual pieces into a std::vector<std::string> and now it's a lot easier to deal with. You can traverse the vector, looking at each string, and depending upon what it is, you know if you have to grab the next item in the list (like push 8 -- you get push and then you get the 8) or just use the current item.
Overall -- break the problem down into smaller pieces. For main:
Get the number of test cases
Loop from 0..testCaseCnt
Get the type of tests (stack or queue)
Get the next input
Split it into tokens broken at each space
Traverse the tokens and Do The Right Thing (tm).
Code for main to read inputs:
int main() {
int numTestCases;
vector<string> file_content{};
fstream ifs;
ifs.open("input2.txt");
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
}
else {
ifs >> numTestCases;
char type;
int numberOps;
//ifs >> type;
cout << numTestCases;
for (int j = 0;j < numTestCases;j++) {
ifs >> type;
ifs >> numberOps;
if (type == 'S') {
Stack st;
clearStack();
for (int i = 0;i < numberOps;i++) {
string operation;
ifs >> operation;
if (operation == "push") {
int pushed;
ifs >> pushed;
push(pushed);
}
if (operation == "pop") {
pop();
}
if (operation == "print") {
printStack();
}
}
}
}
ifs.close();
}
}

Visual Studio shows warning C6330: 'char' passed as _Param_(1) when 'unsigned char' is required in call to 'isdigit'. when I try to build

This is only a small part from my code. What I'm trying to do is writing at the end of the file (add record) which in this case is "books.txt" that already has 40 records. But when I debug, it would still prompt the user to enter isbn code but after entering, (process 3296) exited with code 3. came out. Which part am I doing wrong? The counter() function is to count how many records I already have in my file. And I'm also using array of struct to store my records.
int add_record(DATA book[])
{
int count = counter();
system("CLS");
cout << "\t\t\t\t\t\t\t\t : :Add Book Record: :\n\n";
bool cont;
ofstream outfile("books.txt", ios::app);
if (outfile.is_open() && !outfile.eof())
{
do
{
cont = true;
cout << "ISBN Code: ";
cin.getline(book[++count].isbn_code, 14, '\n');
//cin.ignore(numeric_limits<streamsize>::max(), '\n');
int length = strlen(book[++count].isbn_code);
for (int i = 0; i <= length; i++)
{
if (!isdigit(book[++count].isbn_code[i]))
{
cont = false;
cout << "Your input is invalid. Enter again.\n";
break;
}
}
} while (cont == false);
do
{
cont = true;
cout << "Author: ";
cin.getline(book[++count].author, 50, '\n');
int length = strlen(book[++count].author);
for (int i = 0; i <= length; i++)
{
if (isdigit(book[++count].author[i]))
{
cont = false;
cout << "Your input is invalid. Enter again.\n";
break;
}
}
} while (cont == false);
outfile << book[++count].isbn_code << "," << book[++count].author ;
outfile.close();
}
else
cout << "File is not open\n";
return 0;
}
Yes, the error message is completely correct. This is a rare case where using a cast is the correct thing to do
if (isdigit(static_cast<unsigned char>(book[++count].author[i])))
Reference, https://en.cppreference.com/w/cpp/string/byte/isdigit
But this has nothing to do with your crash which is caused by other errors. For instance
cin.getline(book[++count].isbn_code, 14, '\n');
//cin.ignore(numeric_limits<streamsize>::max(), '\n');
int length = strlen(book[++count].isbn_code);
You definitely don't want to increment count twice. I would guess the correct code is
cin.getline(book[count].isbn_code, 14, '\n');
int length = strlen(book[count].isbn_code);
and to increment count once later in your loop.
Remember ++count is not the same as count + 1. The first increments the count variable, that is it changes the value of the count variable, but count + 1 just adds one to count and does not change the value of the count variable.
This is also wrong
for (int i = 0; i <= length; i++)
In C++ string indexes start at zero and go upto the length of the string minus one, so the correct code is
for (int i = 0; i < length; i++)
Also not part of your question but X can be a legal character in an ISBN.

how to store user input into array in C++

I am new to C++, and want to ask this basic question
what i want: user input data like 2:3American, 4:2China (this means my country team wins 2 points lose 3 points againts American. my country team win 4 points and China team win 2 points)
in console:
please input the result for your team against other teams, input negative number to exit
2:3American
4:2China
-1
result win:1
lose:1
draw:0
If there is no specific encoding is given to you by some authority, use as simple as possible. A better was "2 3 American 4 2 China". So that you only deal with a simple for loop.
The result line is not calculated. Convert each string to integer to calculate.
int main( int argc, char* argv[]) {
std::vector<std::string> arguments(argv + 1, argv + argc);
std::cout << "arguments contains \n";
for (std::vector<std::string>::iterator it = arguments.begin() ; it != arguments.end(); ++it) {
int firstPos = it->find_first_of(":");
int secPos = 0;
std::string firstInteger = it->substr(0,firstPos);
std::string secondInteger;
if ( firstInteger.compare("-1") == 0 ) {
std::cout << "breaking \n";
return 0;
} else {
std::cout << " f=<" << firstInteger << ">";
secPos = it->find_first_not_of( "012345678:", firstPos);
if ( secPos == std::string::npos )
std::cout << "not found";
std::cout << " s=<" << it->substr(firstPos+1 ,secPos-firstPos-1 ) << "> ";
std::string teamName = it->substr(secPos);
std::cout << teamName ;
std::cout << std::endl;
}
}
std::cout << '\n';
return 0;
}
I've written a code similar to this problem a long time ago. made a small change to solve your problem.
So i think this is what you want
INPUT "2:3American 4:2China -1" (SINGLE LINE)
OUTPUT as expected
#include <iostream>
using namespace std;
size_t non_int(int index,string* s)
{
int i=index;
for( i=index;i<s->length();i++){
if(s->at(i) >= '0' && s->at(i) <= '9')
{
// cout << s->at(i) << " is a Digit";
}
else{
return (i-1)<index?(std::string::npos):(i-1);
}
}
return (i-1)<index?(std::string::npos):(i-1);;
}
int main()
{
cout << "Please input the match result such as 2:3American " << endl;
string str;
std::getline (std::cin,str);
//cout<<str;// i want to see did the first user input stored in array. But seems the console..does not print out temp[0] and just skipt it
int win,lose,draw=0;
std::size_t found = 0;
string s1,s2;
int i1,i2;
std::size_t f1,f2;
while( found !=std::string::npos)
{
f1 = str.find(":",found);
if (f1!=std::string::npos){
i1 = stoi(str.substr(found,f1-found));
f2 = non_int(f1+1,&str);
if (f2!=std::string::npos){
i2 = stoi(str.substr(f1+1,f2-f1));
if(i1>i2) win++;
else if(i1<i2)lose++;
else draw++;
}
else {
cout<<"ERROR :invalid input ";
}
}
else {
//exit on -ve input
// cout<<"ERROR 45 ";
}
found = str.find(" ",found+1);
}
cout<<"win:"<<win<<"lose:"<<lose<<"draw:"<<draw<<endl;
return 0;
}
Step 1:
Define a class that represents an input token.
struct Segment
{
int myCountryScore;
int otherCountryScore;
std::string otherCountry;
};
Step 2
Define an input function that reads a Segment from a stream.
std::istream& operator>>(std::istream& s, Segment& data)
{
Segment tmp;
char sep;
int firstNumber;
bool good = false;
if (s >> firstNumber && firstNumber >= 0)
{
tmp.myCountryScore = firstNumber;
if (s >> std::noskipws >> sep >> tmp.otherCountryScore >> tmp.otherCountry >> std::skipws) && (sep == ':'))
{
// The read worked. Copy it to the output object.
data = tmp;
good = true;
}
}
if (!good) {
// If there was an error reading.
// Or we reached the end (negative number read)
// Then set the state of the stream to failure mode.
s.setstate(std::ios::failbit);
}
return s;
}
Step 3
Write a loop that reads Segments from a stream in a loop.
Segment object;
while(std::cin >> object) {
// You have correctly read an object
// Add your code to handle it here.
}
Step 3 Alternative.
Rather than read the Segment one by one you can copy them into a vector simply using a stream iterator.
std::vector<Segment> data(std::istream_iterator<Segment>(std::cin),
std::istream_iterator<Segment>());

C++ Novice regarding Vectors and for/while loops

I’m trying to make something that will take lines of input from the user, separate them into strings in a vector, then print them one at a time (8 per line).
so far this is what I’ve got:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
int main(void)
{
using namespace std;
vector<string> svec1;
string temp;
while(getline(cin, temp)) //stores lines of text in temp
{
if(temp.empty()) //checks if temp is empty, exits loop if so.
break;
stringstream ss(temp);
string word;
while(ss >> word) //takes each word and stores it in a slot on the vector svec1
{
svec1.push_back(word);
}
}
}
I’m stuck on getting it to print them 8 at a time, the solutions I’ve tried keep getting subscript out of range errors.
Something like this:
for(int i = 0; i < svec1.size(); i++)
{
cout << svec1[i];
if ((i+1) % 8 == 0)
cout << endl;
else
cout << " ";
}
?
EDIT:
the solution above outputs extra space/newline at the end. It can be avoided by something like this:
for(int i = 0; i < svec1.size(); i++)
{
if (i == 0)
/*do nothing or output something at the beginning*/;
else if (i % 8 == 0)
cout << endl; /*separator between lines*/
else
cout << " "; /*separator between words in line*/
cout << svec1[i];
}
Walk over your vector with an index:
for (unsigned int idx = 0; idx < svec1.size(); ++idx) {
std::cout << svec[idx] << sep(idx); // sep(idx) is conceptual; described below
}
What is this sep(idx)? It is the separator to print after the idxth word. This is
A newline after having printed eight words on a line. idx will be 7, 15, 23, etc: One shy of an integer multiple of 8. In code, (idx+1)%8 == 0.
A newline for the last item in the vector; you probably want the last item to be followed with a newline. In code idx+1 == svec.size().
A space otherwise.
An easy way to do this is with the ternary operator:
for (unsigned int idx = 0; idx < svec1.size(); ++idx) {
const char * sep = (((idx+1)%8 == 0) || (idx+1 == svec.size())) ? "\n" : " ";
std::cout << svec[idx] << sep;
}
If you don't like that,
for (unsigned int idx = 0; idx < svec1.size(); ++idx) {
const char * sep;
if (((idx+1)%8 == 0) || (idx+1 == svec.size())) {
sep = "\n";
}
else {
sep = " ";
}
std::cout << svec[idx] << sep;
}
Normally you iterate over a vector using a for loop clause. So if you want to print all elements of your vector<string> you have to make something like this:
for(vector<string>::iterator it = myvec.begin(); it != myvec.end(); ++it) {
cout << *it;
}
EDIT: as Vlad has posted correctly, you can also use array indices, which are less efficient in lists, but equally efficient with vectors.