strtok question

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • cting76
    New Member
    • Mar 2007
    • 10

    strtok question

    If I understand it correctly, strtok scans from the first character after the separator. The code below:
    Code:
    #include <iostream>
    #include <fstream>
    using namespace std;
    
    void main()
    {
    	char *rules[50];
    	int priority[50];
    	int i=0;
    	char line[100]=" (arule, 12), (brule, 21), (zrule, 70), (drule, 25), (erule, 10)(frule, 3)(grule, 20), (srule, 100)";
    
    	char *tok = strtok(line,"(");
    	rules[i]=strtok(NULL,",");
    
    	tok=strtok(NULL,")");
    	priority[i]=atoi(tok);
    	i++;
    
    	while((tok=strtok(NULL,"("))!=NULL)
    	{
    		rules[i]=strtok(NULL,",");
    		tok=strtok(NULL,")");
    		priority[i]=atoi(tok);
    		i++;
    	}
    
    	for(int j=0;j<i;j++)
    	{
    		cout<<rules[j]<<endl;
    		cout<<priority[j]<<endl;
    	}
    }
    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:

    Code:
    	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?
  • horace1
    Recognized Expert Top Contributor
    • Nov 2006
    • 1510

    #2
    the first token is framed with (, so try
    Code:
    	char line[100]="(arule, 12), (brule, 21), (zrule, 70), (drule, 25), (erule, 10)(frule, 3)(grule, 20), (srule, 100)";
    	char *tok; 
    	rules[i]=strtok(line,"(,");

    Comment

    • cting76
      New Member
      • Mar 2007
      • 10

      #3
      Originally posted by horace1
      the first token is framed with (, so try
      Code:
      	char line[100]="(arule, 12), (brule, 21), (zrule, 70), (drule, 25), (erule, 10)(frule, 3)(grule, 20), (srule, 100)";
      	char *tok; 
      	rules[i]=strtok(line,"(,");
      Thank you. That fixes the problem.

      I then modified the input into:

      Code:
      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:

      Code:
      char next[2]=")";
      and then changing the while loop to:

      Code:
      	while((num=strtok(NULL,"("))!= NULL && (num=strtok(NULL,"("))!=next)
      	{
      		rules[i]=strtok(NULL,",");
      		num=strtok(NULL,")");
      		priority[i]=atoi(num);
      		i++;
      	}
      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:

      Code:
      	while((num=strtok(NULL,"("))!= NULL)
      	{
      		rules[i]=strtok(NULL,",");
      		num=strtok(NULL,")");
      		priority[i]=atoi(num);
      		i++;
      
      		if(num==next)
      			cout<<"pause"; //to test if the condition works
      	}
      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.

      Comment

      • cting76
        New Member
        • Mar 2007
        • 10

        #4
        Will someone be so kind to point out why my program hangs? It doesn't give out any error message other than "<program_n ame has stopped working>".

        Code:
        #include <iostream>
        #include <fstream>
        using namespace std;
        
        void main()
        {
        	ifstream infile;
        	char c[256],str[64];
        	char *rules[50];
        	int priority[50];
        	int i=0;
        	char *num;
        
        	cout<<"Enter the name of input file: ";
        	cin.get(str, 64);
        
        	infile.open(str);
        
        	for(i=0;i<256;i++)
        	{
        		c[i]=infile.get();
        		cout<<c[i];
        	}
        
        	cout<<endl;
        	i=0;
        	
        	rules[i]=strtok(c,"(,");
        	num=strtok(NULL,")");
        	priority[i]=atoi(num);
        
        	cout<<endl;
        	cout<<rules[i];
        	cout<<endl;
        	cout<<priority[i];
        	cout<<endl;
        
        	i++;
        
        	while((num=strtok(NULL,"("))!=NULL)
        	{
        		rules[i]=strtok(NULL,",");
        		cout<<rules[i]<<endl;
        		num=strtok(NULL,")");
        		priority[i]=atoi(num);
        		cout<<priority[i]<<endl;
        		i++;
        	}
        infile.close();
        }
        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.

        Comment

        • horace1
          Recognized Expert Top Contributor
          • Nov 2006
          • 1510

          #5
          your program works fine with GNU C++.
          The problem may be in your the loop where you read a line from the file
          Code:
          	for(i=0;i<256;i++)
          	{
          		c[i]=infile.get();
          		cout<<c[i];
          	}
          in that the string is not being properly null terminated with your compiler.
          try
          Code:
          	infile.get(c,256);
          so you read up to 256 characters or until a newline is found

          Comment

          • cting76
            New Member
            • Mar 2007
            • 10

            #6
            Originally posted by horace1
            Code:
            infile.get(c,256);
            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,25 6). Now the program can read the line just fine. However, it hangs again if the input is like this:

            (arule, 10), (brule,20)(crul e, 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.

            Comment

            • horace1
              Recognized Expert Top Contributor
              • Nov 2006
              • 1510

              #7
              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.
              Code:
              	while((num=strtok(NULL,"("))!=NULL)
              	{
              		if((rules[i]=strtok(NULL,","))==NULL)break;
              		cout<<rules[i]<<endl;
              		if((num=strtok(NULL,")"))==NULL)break;
              		cout << "num " << num <<endl;
              		priority[i]=atoi(num);
              		cout<<priority[i]<<endl;
              		i++;
              	}

              Comment

              • cting76
                New Member
                • Mar 2007
                • 10

                #8
                Originally posted by horace1
                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.
                Code:
                	while((num=strtok(NULL,"("))!=NULL)
                	{
                		if((rules[i]=strtok(NULL,","))==NULL)break;
                		cout<<rules[i]<<endl;
                		if((num=strtok(NULL,")"))==NULL)break;
                		cout << "num " << num <<endl;
                		priority[i]=atoi(num);
                		cout<<priority[i]<<endl;
                		i++;
                	}
                Shouldn't num=strtok(NULL ,"(")) return NULL if there's no more element after the last ")"?

                Comment

                • cting76
                  New Member
                  • Mar 2007
                  • 10

                  #9
                  Alright I have modified my code into this:

                  Code:
                  #include <iostream>
                  #include <fstream>
                  #include <string>
                  using namespace std;
                  
                  #define index 5
                  
                  struct am{
                  	string rule;
                  	int priority;
                  }set[index];
                  
                  void printset(am amg)
                  {
                  	cout<<amg.rule<<endl;
                  	cout<<amg.priority<<endl;
                  }
                  
                  void main()
                  {
                  	ifstream infile;
                  	char c[256],str[32];
                  	char *rules[50];
                  	int priority[50];
                  	int i=0;
                  	char *num;
                  
                  	cout<<"Enter the name of input file: ";
                  	cin.get(str, 32);
                  
                  	infile.open(str);
                  	infile.get(c,256);
                  
                  	set[i].rule=strtok(c,"(,");
                  
                  	for(i=0;i<index;i++)
                  	{
                  		num=strtok(NULL,")");
                  		set[i].priority=atoi(num);
                  		num=strtok(NULL,"(");
                  		set[i+1].rule=strtok(NULL,",");
                  	}
                  	for(int n=0;n<index;n++)
                  		printset(set[n]);
                  
                  infile.close();
                  }
                  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)(crul e, 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.

                  Comment

                  Working...