By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,331 Members | 1,454 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,331 IT Pros & Developers. It's quick & easy.

strtok question

P: 10
If I understand it correctly, strtok scans from the first character after the separator. The code below:
Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. #include <fstream>
  3. using namespace std;
  4.  
  5. void main()
  6. {
  7.     char *rules[50];
  8.     int priority[50];
  9.     int i=0;
  10.     char line[100]=" (arule, 12), (brule, 21), (zrule, 70), (drule, 25), (erule, 10)(frule, 3)(grule, 20), (srule, 100)";
  11.  
  12.     char *tok = strtok(line,"(");
  13.     rules[i]=strtok(NULL,",");
  14.  
  15.     tok=strtok(NULL,")");
  16.     priority[i]=atoi(tok);
  17.     i++;
  18.  
  19.     while((tok=strtok(NULL,"("))!=NULL)
  20.     {
  21.         rules[i]=strtok(NULL,",");
  22.         tok=strtok(NULL,")");
  23.         priority[i]=atoi(tok);
  24.         i++;
  25.     }
  26.  
  27.     for(int j=0;j<i;j++)
  28.     {
  29.         cout<<rules[j]<<endl;
  30.         cout<<priority[j]<<endl;
  31.     }
  32. }
gives an output like this:

arule
12
brule
21
zrule
70
drule
25
erule
10

However, if I remove the space between " and (arule, 12) so the line would look like:

Expand|Select|Wrap|Line Numbers
  1.     char line[100]="(arule, 12), (brule, 21), (zrule, 70), (drule, 25), (erule, 10)(frule, 3)(grule, 20), (srule, 100)"; //there's no space between " and (arule, 12)
then the output would become:

brule
21
zrule
70
drule
25
erule
10

Why is a space needed between " and the first separator in order for the program to work correctly? Am I doing something incorrectly?
Mar 23 '07 #1
Share this Question
Share on Google+
8 Replies


Expert 100+
P: 1,510
the first token is framed with (, so try
Expand|Select|Wrap|Line Numbers
  1.     char line[100]="(arule, 12), (brule, 21), (zrule, 70), (drule, 25), (erule, 10)(frule, 3)(grule, 20), (srule, 100)";
  2.     char *tok; 
  3.     rules[i]=strtok(line,"(,");
  4.  
Mar 23 '07 #2

P: 10
the first token is framed with (, so try
Expand|Select|Wrap|Line Numbers
  1.     char line[100]="(arule, 12), (brule, 21), (zrule, 70), (drule, 25), (erule, 10)(frule, 3)(grule, 20), (srule, 100)";
  2.     char *tok; 
  3.     rules[i]=strtok(line,"(,");
  4.  
Thank you. That fixes the problem.

I then modified the input into:

Expand|Select|Wrap|Line Numbers
  1. char line[100]="(arule, 12), (brule, 21), (zrule, 70), (drule, 25), (erule, 10)(frule, 3)(grule, 20), (srule, 100)";
Notice that there's no "," between "(erule, 10)", "(frule, 3)", and "(grule, 20)". What I want to do is, let the program read from "(arule, 12)" until "(erule,10)", pause right before "(frule,3)", do something, then continue reading "(frule, 3)", pause before "(grule, 20)", do something, then continue reading "(grule,20), (srule, 100)".

So far I've tried adding:

Expand|Select|Wrap|Line Numbers
  1. char next[2]=")";
and then changing the while loop to:

Expand|Select|Wrap|Line Numbers
  1.     while((num=strtok(NULL,"("))!= NULL && (num=strtok(NULL,"("))!=next)
  2.     {
  3.         rules[i]=strtok(NULL,",");
  4.         num=strtok(NULL,")");
  5.         priority[i]=atoi(num);
  6.         i++;
  7.     }
but the output becomes:

arule
12
zrule
70
erule
10
srule
100

I figured everytime a strtok is called it changes the beginning token so I then changed the while loop into:

Expand|Select|Wrap|Line Numbers
  1.     while((num=strtok(NULL,"("))!= NULL)
  2.     {
  3.         rules[i]=strtok(NULL,",");
  4.         num=strtok(NULL,")");
  5.         priority[i]=atoi(num);
  6.         i++;
  7.  
  8.         if(num==next)
  9.             cout<<"pause"; //to test if the condition works
  10.     }
but the output becomes:
arule
12
brule
21
zrule
70
drule
25
erule
10
grule
20
srule
100

What am I doing wrong?

Thank you.
Mar 24 '07 #3

P: 10
Will someone be so kind to point out why my program hangs? It doesn't give out any error message other than "<program_name has stopped working>".

Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. #include <fstream>
  3. using namespace std;
  4.  
  5. void main()
  6. {
  7.     ifstream infile;
  8.     char c[256],str[64];
  9.     char *rules[50];
  10.     int priority[50];
  11.     int i=0;
  12.     char *num;
  13.  
  14.     cout<<"Enter the name of input file: ";
  15.     cin.get(str, 64);
  16.  
  17.     infile.open(str);
  18.  
  19.     for(i=0;i<256;i++)
  20.     {
  21.         c[i]=infile.get();
  22.         cout<<c[i];
  23.     }
  24.  
  25.     cout<<endl;
  26.     i=0;
  27.  
  28.     rules[i]=strtok(c,"(,");
  29.     num=strtok(NULL,")");
  30.     priority[i]=atoi(num);
  31.  
  32.     cout<<endl;
  33.     cout<<rules[i];
  34.     cout<<endl;
  35.     cout<<priority[i];
  36.     cout<<endl;
  37.  
  38.     i++;
  39.  
  40.     while((num=strtok(NULL,"("))!=NULL)
  41.     {
  42.         rules[i]=strtok(NULL,",");
  43.         cout<<rules[i]<<endl;
  44.         num=strtok(NULL,")");
  45.         priority[i]=atoi(num);
  46.         cout<<priority[i]<<endl;
  47.         i++;
  48.     }
  49. infile.close();
  50. }
The input file has only one line:
(R10, 10), (R20, 20), (R90, 90), (R75, 75), (R35, 35), (R60, 60).

The program works just fine if I include the input line in the program (in other words: char c[100]="(R10, 10), (R20, 20), (R90, 90), (R75, 75), (R35, 35), (R60, 60)"; works just fine). But it would hang at the while loop when the input is reading from a file. It would output

R10
10
R20
20
R90
90
R75
75
R35
35
R60
60

but hangs right after 60. Looks to me it is unable to "satisfy" the !=NULL condition but I can't why.

Any advice appreciated.

Thank you.
Mar 25 '07 #4

Expert 100+
P: 1,510
your program works fine with GNU C++.
The problem may be in your the loop where you read a line from the file
Expand|Select|Wrap|Line Numbers
  1.     for(i=0;i<256;i++)
  2.     {
  3.         c[i]=infile.get();
  4.         cout<<c[i];
  5.     }
  6.  
in that the string is not being properly null terminated with your compiler.
try
Expand|Select|Wrap|Line Numbers
  1.     infile.get(c,256);
  2.  
so you read up to 256 characters or until a newline is found
Mar 25 '07 #5

P: 10
Expand|Select|Wrap|Line Numbers
  1. infile.get(c,256);
  2.  
so you read up to 256 characters or until a newline is found
Thank you! I wasn't aware of the difference between c[i]=infile.get() and infile.get(c,256). Now the program can read the line just fine. However, it hangs again if the input is like this:

(arule, 10), (brule,20)(crule, 30)(drule, 40), (erule, 50)(frule, 60)

I use Visual Studio and it simply says the program (the one I wrote) has stopped working. The output would look like this:

arule
10
brule
20
drule
40
erule
50

(crule, 30) and (frule, 60) are both missing. I think it's got something to do with how the delimiter is set up. What I am trying to do is, let the program read block "(arule, 10), (brule, 20)", do something, read (crule, 30), do something, read block "(drule, 40), (erule, 50)", do something, then read (frule, 60) and do something. So how do I make a condition that says if current token ends with ")" and there's a "(" immediately follows, then do something before continue reading next block?

Thank you.
Mar 25 '07 #6

Expert 100+
P: 1,510
it gives a segmentation error with Visual; C++ on my machine
the problem is if strtok() returns NULL within your loop - you need to check and if so exit the loop, e.g.
Expand|Select|Wrap|Line Numbers
  1.     while((num=strtok(NULL,"("))!=NULL)
  2.     {
  3.         if((rules[i]=strtok(NULL,","))==NULL)break;
  4.         cout<<rules[i]<<endl;
  5.         if((num=strtok(NULL,")"))==NULL)break;
  6.         cout << "num " << num <<endl;
  7.         priority[i]=atoi(num);
  8.         cout<<priority[i]<<endl;
  9.         i++;
  10.     }
  11.  
Mar 25 '07 #7

P: 10
it gives a segmentation error with Visual; C++ on my machine
the problem is if strtok() returns NULL within your loop - you need to check and if so exit the loop, e.g.
Expand|Select|Wrap|Line Numbers
  1.     while((num=strtok(NULL,"("))!=NULL)
  2.     {
  3.         if((rules[i]=strtok(NULL,","))==NULL)break;
  4.         cout<<rules[i]<<endl;
  5.         if((num=strtok(NULL,")"))==NULL)break;
  6.         cout << "num " << num <<endl;
  7.         priority[i]=atoi(num);
  8.         cout<<priority[i]<<endl;
  9.         i++;
  10.     }
  11.  
Shouldn't num=strtok(NULL,"(")) return NULL if there's no more element after the last ")"?
Mar 25 '07 #8

P: 10
Alright I have modified my code into this:

Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. #include <fstream>
  3. #include <string>
  4. using namespace std;
  5.  
  6. #define index 5
  7.  
  8. struct am{
  9.     string rule;
  10.     int priority;
  11. }set[index];
  12.  
  13. void printset(am amg)
  14. {
  15.     cout<<amg.rule<<endl;
  16.     cout<<amg.priority<<endl;
  17. }
  18.  
  19. void main()
  20. {
  21.     ifstream infile;
  22.     char c[256],str[32];
  23.     char *rules[50];
  24.     int priority[50];
  25.     int i=0;
  26.     char *num;
  27.  
  28.     cout<<"Enter the name of input file: ";
  29.     cin.get(str, 32);
  30.  
  31.     infile.open(str);
  32.     infile.get(c,256);
  33.  
  34.     set[i].rule=strtok(c,"(,");
  35.  
  36.     for(i=0;i<index;i++)
  37.     {
  38.         num=strtok(NULL,")");
  39.         set[i].priority=atoi(num);
  40.         num=strtok(NULL,"(");
  41.         set[i+1].rule=strtok(NULL,",");
  42.     }
  43.     for(int n=0;n<index;n++)
  44.         printset(set[n]);
  45.  
  46. infile.close();
  47. }
That solves the while loop problem. But another problem still stands: the program reads just fine with input of (arule, 10), (brule,20), (crule, 30), (drule, 40), (erule, 50), (frule, 60). But if the input is (arule, 10), (brule,20)(crule, 30)(drule, 40), (erule, 50)(frule, 60), the program will hang.

Please advise on how to tell the strtok to separate ") from "(", or pause at ")" if the immediate element is "(". Thank you.
Mar 25 '07 #9

Post your reply

Sign in to post your reply or Sign up for a free account.