0

I have the following code that read input from txt file as follow

Paris,Juli,5,3,6 
Paris,John,24,2 
Canberra,John,4,3 
London,Mary,29,4,1,2

my code is to load the data into map then I want to print the map content to make sure that it has been inserted correctly, I check the vaue of m as it is used during splitting the line. However, during the execution I get this as continues 0s which means it is never enter the while loop. I have used this part of code before and it works. I could not find where I've made the mistake.

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <vector>
#include<map>
using namespace std;

struct info {
       string Name;
       int places;// i will use the binary value to identfy the visited places example 29 is 100101 
             // this means he visited three places (London,LA,Rome)   
       vector<int> times; // will represent the visiting time,e.g. 1,2,5 means london 1 time, LA 
                   // twice and Rome five times 


       };
map<string,vector<info> > log;
map<string,vector<info> >::iterator i;
fstream out;
int main() {
    out.open("log.txt", std::ios::in | std::ios::out | std::ios::app);
            string line;
            char* pt;
            string temp[19];

    // for each line in the file 
    while (!out.eof())
    {
         getline(out,line);//read line from the file
         pt=strtok(&line[0],"," );//split the line
         int m=0;
         while (pt != NULL)
         {
         temp[m++] = pt; // save the line info to the array
         cout<<m<<"  ";
         pt = strtok (NULL, ",");
         }
         cout<<m<<"  "; // during the execution I get this as continues 0s which means it is never enter the while loop
         info tmp;
         // read the other data
         tmp.Name=temp[1];
         tmp.places=atoi(temp[2].c_str());
         for ( int i=3;i<=m;i++)
         { 
         tmp.times.push_back(atoi(temp[i].c_str()));
         }         
         // create a new object 
         log[temp[0]].push_back(tmp); 
         }

 vector<int>::iterator j; 
    for(i=log.begin();i!=log.end();i++) {
    cout<< "From "<< i->first<<" city people who travels: "<<endl; 
    for (size_t tt = 0; tt < (i->second).size(); tt++) {
    cout<< (i->second[tt]).Name<< " went to distnations "<< (i->second)[tt].places<<" \nwith the folloing number of visiting time "; 
    for (j=((i->second[tt]).times).begin();j!= ((i->second[tt]).times).end();j++) 
    cout<<*j<<" ";
     } 
    }  


          system("PAUSE");
          return 0;
          }
user1749118
  • 57
  • 2
  • 7
  • see also [this question](http://stackoverflow.com/q/236129/1025391) on splitting strings in C++. – moooeeeep Oct 17 '12 at 10:55
  • strtok takes char* but does it take "string" type? I actually don't know. is cstring included in your code? strtok is supposed to be there. – taufique Oct 17 '12 at 10:55
  • Maybe your input txt file is **not** named `log.txt` – Olaf Dietsche Oct 17 '12 at 11:18
  • @Md.TaufiqueHussain The same block of code work with other file where I now exactly how meny elemnts in the line. Here, each line have different number of elements, so I can't make how ment elements in each line. the min number of elements is 3 – user1749118 Oct 17 '12 at 11:29
  • see this [question](https://stackoverflow.com/questions/68439991/read-file-and-split-and-trim-each-line-with-cpp20) implement reading files and splitting strings with c++20. – AmirSalar Jul 19 '21 at 15:35

5 Answers5

3

This is an error

// for each line in the file 
while (!out.eof())
{
     getline(out,line);//read line from the file

should be

// for each line in the file 
while (getline(out,line))
{

I find it frankly incredible how often this error is repeated. eof does not do what you think it does. It tests if the last read failed because of end of file. You are using it to try and predict whether the next read will fail. It simply doesn't work like that.

This line is an error

pt=strtok(&line[0],"," );//split the line

strtok works on C strings, there's no guarantee it will work on std::string.

But neither of these are likely to be your real error. I would suggest opening the file with ios::in only. After all you only want to read from it.

john
  • 85,011
  • 4
  • 57
  • 81
  • actullay I want to read data from the file then append new data to it. I used strtok before in the kind of program and it works. – user1749118 Oct 17 '12 at 11:08
  • if I put the while condition as you wrote, the program does not read any data. – user1749118 Oct 17 '12 at 11:19
  • @user1749118 Sure it works. But you got lucky. There is no guarantee it will always work. The next compiler you use, or the next program you write it may not work. You should do it like Nickolay says. – john Oct 17 '12 at 11:19
  • 1
    @user1749118 OK, remove ios::app and then when you want to append, seek to the end of the file, or even close the file and reopen it. – john Oct 17 '12 at 11:20
1

You can't tokenize an std::string using strtok. Use getline instead:

std::string str("some,comma,separated,data");
std::string token;
while (getline(str, token, ',')) {
    cout << "Token: " << token << end;
}

At each iteration, token contains the next parsed token from str.

nickolayratchev
  • 1,136
  • 1
  • 6
  • 15
1

Your fstream should not open in app mode. That will seek the file to the end of file. Delete std::ios::app from it.

halfelf
  • 9,737
  • 13
  • 54
  • 63
0

This is wrong temp[m++] = pt; // save the line info to the array

Switch to something like this, instead of "temp"

std::vector<std::string> vTemp; 

pt=strtok(&line[0],"," );//split the line       
while (pt != NULL)
{
vTemp.push_back(pt); // save the line info to the array      
pt = strtok (NULL, ",");
}

Also consider using something like this to do the split.

std::vector<std::string> SplitString(const std::string &strInput, char cDelimiter)
{
    std::vector<std::string> vRetValue;

    std::stringstream ss(strInput); 
    string strItem;
    while(std::getline(ss, strItem, cDelimiter))    
    {   
        // Skip Empty
        if(strItem.size()==0)       
            continue;

        vRetValue.push_back(strItem);
    }

    return vRetValue;
}
João Augusto
  • 2,285
  • 24
  • 28
0

@halfelf really great solution for my simple error, it works but the problem is now when I print the data I got this

From Paris  city people who travels:
Juli went to distnations 5
with the folloing number of visiting time 3 6 0 
John went to distnations 24
with the folloing number of visiting time 2 6 
From Canberra  city people who travels:
Johnwent to distnations 4
with the folloing number of visiting time 3  6
From London city people who travels:
Mary went to distnations 29
with the folloing number of visiting time 4 1 2 0

This is not correct as 6 is added to John from Canberra and Paris and 0 is added to Juli and Mary. any idea of where I get it wrong ,, its about the times vector , its seems that I need to reset the value for each line or clear the content after the insertion. what about the extra 0?

user1749118
  • 57
  • 2
  • 7
  • Solve it , just removing the = sign from the for loop `for ( int i=3;i<=m;i++) ` .. Thank you all for your help – user1749118 Oct 17 '12 at 11:55