0

Good morning to everybody, :)

I have writen a code in C++ that reads information from a txt file. It takes the information in the first row saving it in a string and then I want to work with this info. I want to read this string and when it finds a "|" character it must jump to a new line. Its something quite easy but I'm having problems when executing and I've been trying to find the problem for hours and I haven't suceed. :( I attached the code.

Thanks in advance for your help.

#include <string>
#include <fstream>
#include <vector>
#include <iostream>

using namespace std;

int main()
{

    ifstream ifs( "C:\\a\\text.txt" );
    string temp;

    getline( ifs, temp ); 
    cout<<temp<<endl;

    string * pch;
    pch = strtok (temp,"|");

    while (pch != NULL)
    {
        printf ("%s\n",pch);
        pch = strtok (NULL, "|");
    }

    system("pause");
    return 0;

}
thomas
  • 23
  • 1
  • 4
  • 2
    Which kind of problems are you experiencing? – Simone Feb 07 '11 at 10:55
  • I have problems when compiling. In the second part of the program, when using strok function it seems I have some mistakes: In line 24: Cannot convert `std::string' to `char*' for argument `1' to `char* strtok(char*, const char*)' and in line 29 cannot convert `char*' to `std::string*' in assignment, but I don't really understand this problem, and don't know how to solvent it... :S – thomas Feb 07 '11 at 10:57
  • 1
    Probably that it doesn't compile, since he is using std::string with a function that's made for `char*` – ltjax Feb 07 '11 at 10:58
  • So how could I rewrite my code so that I didn't have any problem when compiling? – thomas Feb 07 '11 at 11:00
  • 1
    Please don't learn from tutorials/books that tell you to put `system("pause")` at the end of your main function. – dreamlax Feb 07 '11 at 11:11
  • Why not use STL algorithms rather than using strtok, when using string ? – DumbCoder Feb 07 '11 at 11:17

4 Answers4

1

strtok works with char*, not string*. That's probably why you're experiencing issues.

Since you're implementing this with c++, I suggest you use the string functions instead of strtok:

int main()
{

    ifstream ifs( "C:\\a\\text.txt" );
    string temp;

    getline( ifs, temp ); 
    cout<<temp<<endl;

    size_t tokenPos = temp.find("|");   

    while (tokenPos != string::npos)
    {
        cout << temp.substr(0, tokenPos) << endl;
        temp.erase(0, tokenPos+1);
        tokenPos = temp.find("|");  
    }

    system("pause");
    return 0;

}

To store your text in the values you described in your comment, you'd do the following:

int main() 
{ 
    ifstream ifs( "C:\\a\\text.txt" ); 

    int id; 
    int type; 
    int columns; 
    string temp; 

    getline( ifs, temp ); 
    cout<<temp<<endl; 

    size_t tokenPos = temp.find("|");
    while (tokenPos != string::npos) 
    { 
        int i=0; 
        tokenPos = temp.find("|"); 
        cout << temp.substr(0, tokenPos) << endl; 

        if(i==0)
        { 
            id = atoi(temp.substr(0, tokenPos).c_str()); 
        }
        else if(i==1) 
        { 
            type = atoi(temp.substr(0, tokenPos).c_str()); 
        } 
        else if(i==2) 
        { 
            columns = atoi(temp.substr(0, tokenPos).c_str()); 
        } 

        ++i; 
        temp.erase(0, tokenPos+1); 
    } 

    cout << "ID: " << id << ", Type: " << type << ", Columns: " << columns << endl; 
    system("pause"); 
    return 0; 
}
badgerr
  • 7,802
  • 2
  • 28
  • 43
  • Working with your idea now I have a problem. Continuing with my code, now I want to identify and assign to a variable every different element read from my file and separated with "|". But when defining it as temp.substr(0, tokenPos) I have problems when compiling. I attached my code: – thomas Feb 07 '11 at 14:31
  • #include #include #include #include using namespace std; int main() { ifstream ifs( "C:\\a\\text.txt" ); int id; int type; int columns; string temp; getline( ifs, temp ); cout< – thomas Feb 07 '11 at 14:33
  • if(i=1) { type=temp.substr(0, tokenPos); } if(i=2) { columns=temp.substr(0, tokenPos); } i++; } cout< – thomas Feb 07 '11 at 14:33
  • You can't assign strings straight to ints. If you want the int from the string, use type = atoi(temp.substr(0, tokenPos).c_str()); and the same for columns. Also, comparason operator is ==, so use if(i==1), instead of if(i=1). Don't forget to do ++i; before the end of the while loop. – badgerr Feb 07 '11 at 14:36
  • Greaaaaaat!!! It works perfectly!! Thanks again!! People like you really motivates me to keep on working with programming! :) – thomas Feb 07 '11 at 15:03
1

There are many ways to tokenize a std::string. Here is one way; I chose this primarily because it's simple and self-contained:

int main() {
  using namespace std;
  ifstream ifs("C:/a/text.txt");
  vector<string> bits;  // if you want to save to process
  for (string temp; getline(ifs, temp, '|');) {
    bits.push_back(temp);
    cout << temp << '\n';  // if you want to output each as processed
  }
  return 0;
}
Fred Nurk
  • 13,952
  • 4
  • 37
  • 63
0

You will find some ways to do that in that question. As you use C++, it is usually not the way to resort to C style functions. Concerning your code, try to give us the exact error. It helps ...

I see lots of problems in your code. Here is a working example from C++ reference :

/* strtok example */
#include <stdio.h>
#include <string.h>

int main ()
{
    char str[] ="- This, a sample string.";
    char * pch;
    printf ("Splitting string \"%s\" into tokens:\n",str);
    pch = strtok (str," ,.-");
    while (pch != NULL)
    {
        printf ("%s\n",pch);
        pch = strtok (NULL, " ,.-");
    }
    return 0;
}

As stated in the doc, you need to give strtok a non-const c-string as it will modify it in order to process tokens.

my2c

Community
  • 1
  • 1
neuro
  • 14,948
  • 3
  • 36
  • 59
  • I've attached the mistakes in a previous comment. So how would I have to rewrite my code so that it works properly?? – thomas Feb 07 '11 at 11:04
  • @thomas: I have added an example. It should make the trick :) But prefer the STL way of doing it or boost way :) – neuro Feb 07 '11 at 11:10
0

Try to change this line

  pch = strtok (temp,"|");

to

  pch = strtok (temp.c_str(),"|");

strtok takes char* (c-style string) not ::std::string (c++ string).

UPDATE2 My mistake. I haven't used strtok for so long. Ok. Try this one:

char* s = new char[temp.size() + 1];
memcpy(s, temp.c_str(), temp.size() + 1);  // copy c-style string with '\0' at the end
const char* pch = strtok(s, "|");
...
delete[] s;
f0b0s
  • 2,978
  • 26
  • 30
  • 1
    temp.c_str() is char const*, not char*. – Fred Nurk Feb 07 '11 at 11:07
  • It makes the following mistake: invalid conversion from `const char*' to `char*' – thomas Feb 07 '11 at 11:08
  • the update still don't work, of course, since you are not copying temp into s. – Simone Feb 07 '11 at 11:11
  • The code in the update allocates one too few chars, doesn't copy the data from temp into the array, and you should avoid manual resource release (e.g. the delete) in C++. – Fred Nurk Feb 07 '11 at 11:12
  • I always used ::std::vector in release, but author doesn't really understand difference of c-style strings and ::std::string, so i posted the simpliest decision. Yeah, i've forgotten memcpy, but found this mistake right after post and edited it. – f0b0s Feb 07 '11 at 11:14
  • my bad, i should go sleep now. I've forgotted about null-terminator too. finally edited the code. – f0b0s Feb 07 '11 at 11:15
  • The simplest decision is not always the best. Especially when the OP appears to be learning C++ and so should be making full use of the std:: libraries instead of messing around with heap memory and C string functions. – badgerr Feb 07 '11 at 11:17