Thread: strtok and strcmp pointer issues question

  1. #16
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It is quite difficult for us to know what's wrong when you've left out a lot of code. Either post a small compilable snippet that demonstrates the problem or go debug it yourself.
    A good idea is to use assert and put it everywhere in your program to check for things that should never be. For example, a pointer being NULL when you don't expect it to.
    Carefully read the documentation of all functions and see what they take and what they return. Then put asserts to check that what you're giving it is valid and what it returns is valid.


    Example:

    Code:
           char *mass = NULL;
           float m;
           char *WINGSPAN = NULL;
           float wingspan;
           char *s = NULL;
           float S;
    
    for (i=0;i<=lineno; i++) // Should probably be 0 to lineno - 1.
        {
        assert(array[i] != NULL);
           param[i]=strtok(arra[i],delims);
           param2[i]=strtok(NULL,delims);
        assert(param[i] != NULL);
        assert(param2[i] != NULL);
    
               printf("param[i] is %s\n",param[i]);
               printf("param2[i] is %s\n",param2[i]);
    
          if (strcmp("Mass*",param[i])==0) if(mass==NULL) mass=param2[i];
          if (strcmp("Wingspan*",param[i])==0) if (WINGSPAN==NULL) WINGSPAN=param2[i];
          if (strcmp("Wing area*",param[i])==0) if (s==NULL) s=param2[i];
          
        }
    
    m=atof(mass);
    printf("Mass is %f kg\n",m); 
    
    wingspan=atof(WINGSPAN);
    printf("Wingspan is %f m\n",wingspan);
    
    S=atof(s);
    printf("Wing area is %f m2\n",S);
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #17
    Registered User
    Join Date
    Jul 2010
    Location
    Liverpool
    Posts
    34
    Sorry, didn't mean to leave out that section - there are a lot of parameters so I thought it'd be simpler to just show three, but ended up snipping a bit out that I didn't mean to.

    Attempt #2 at posting my code - hopefully has everything needed:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    
    main ()
    
    {
      FILE *parameters;
      char filename[100];  
      int ch=0;
      int lineno=0;
      char line[128]={'\0'};
      char arra[128][3000]={{'\0'}};
      char *mass, *WINGSPAN, *s; 
      mass=WINGSPAN=s=NULL;
      float m,wingspan,S; 
    
      char *param[40]; 
      char *param2[40];
      
    /* Open parameters file */
    
      printf("Type in the name of the file containing aircraft data, e.g. param.txt\n");
      scanf("%100s",filename);
      parameters=fopen(filename,"r");
    if (parameters == NULL)
      {printf("Could not open aircraft parameters file.\n"); }
    
    else
       {
    
     while ((ch = fgetc(parameters)) != EOF)
     {if (ch == '\n')
      ++lineno;
      }
     fseek(parameters, 0, SEEK_SET);
     i=0;
     while(fgets(line,sizeof line,parameters) !=NULL)
       {strcpy (arra[i],line);
     i++;
       }
    
    /* tokenise by equals sign to find parameters */
    
    char delims[]="="; 
    
    for (i=0;i<=lineno; i++)
    	{
    	   param[i]=strtok(arra[i],delims);
    	   param2[i]=strtok(NULL,delims);
    
               printf("param[i] is %s\n",param[i]);
               printf("param2[i] is %s\n",param2[i]);
    /* these prints are coming out correct */
    
    	  if (strcmp("Mass*",param[i])==0) mass=param2[i];
    	  if (strcmp("Wingspan*",param[i])==0) WINGSPAN=param2[i];
    	  if (strcmp("Wing area*",param[i])==0) s=param2[i];
    /* this is what appears to not be working */
    	  
    	}
    
    
    /* converts tokens to float values */
    //mass=param2[4];   this is what I don't want to use as it's too inflexible with line numbers
    m=atof(mass);
    //WINGSPAN=param2[6];
    wingspan=atof(WINGSPAN);
    //s=param2[8];
    S=atof(s);
    WL=param2[10];
    wl=atof(WL);
    // ditto again
    
    printf("Mass is %f\n",m);
    printf("Wingspan is %f\n",wingspan);
    printf("Wing area is %f\n",S);
    
    }
       return(0);
         
    }
    Last edited by snoikey; 07-28-2010 at 07:58 AM.

  3. #18
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
    char arra[128][3000]={{'\0'}};
    Is this supposed to be 128 lines each 3000 in length, or 3000 lines each 128 in length? If the latter, reverse the numbers.

    Your for loop should be "< lineno", unless your final line doesn't necessarily end in a newline, in which case it's as mentioned by Elysia.

    You are still printing param*[ ] before you actually see if they're null or not. Try printing out the current arra line before you tokenize it. Oh, and start checking your return values.

    There's no point in actually trying to help you if you aren't going to learn from what we're telling you.


    Quzah.
    Hope is the first step on the road to disappointment.

  4. #19
    Registered User
    Join Date
    Jul 2010
    Location
    Liverpool
    Posts
    34
    I'm perfectly capable of debugging it, and have done, you're right about the size of arra so I'll change that, thanks. That wouldn't be affecting the program at this stage though as the file I'm reading isn't that big.

    I'm not sure anyone is understanding my question - I already know at which point it's not working, it's the strcmp bit, from my own checks that I haven't necessarily posted on here. The whole point of my thread was to ask what I was doing wrong at the strcmp stage.

    Sorry if this sounds rude, I don't mean it to, but it appears you all think I'm being stupid/asking for help debugging, and that's not it at all. I just want to know how to compare tokenised strings without the program going mad on me :P and thought you might have some experience with it already.

    EDIT: well, technically I am asking for help with debugging a small part of the program, but mainly for another method of doing the same thing as that part does.
    Last edited by snoikey; 07-29-2010 at 02:38 AM.

  5. #20
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    But "going wrong" doesn't tell us much. We can think of a few reasons it would fail, and we have mentioned them. But as you should know, even though the problem is occurring in one part of the program doesn't mean the bug is in the part of the program. It might as well be elsewhere, and indeed, often it is.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #21
    Registered User
    Join Date
    Jul 2010
    Location
    Liverpool
    Posts
    34
    Thank you, that's fair enough. I've tested arra, it works how I think it does, param[i] and param2[i], the tokens, are coming out ok, and if there's nothing else in the tokenising loop apart from param and param2:

    Code:
    mass=param2[6];  // or whatever line number mass is defined on in text file
    m=atof(mass);
    also works, which I think demonstrates well enough that my tokenising part works. If I then put in

    Code:
    if (strcmp("Mass*",param[i])==0) mass=param2[i];
    in the tokenising loop as posted previously, then print 'mass' both within and outside the loop, it's not saving anything to 'mass' - although changing the iteration number start in the loop has taken care of the seg fault, it seems.

    I think it -should- be working. I think you guys probably do too, from the amount of posts suggesting I've gone wrong somewhere else.

  7. #22
    Registered User
    Join Date
    Jun 2010
    Location
    Michigan, USA
    Posts
    143
    Quote Originally Posted by snoikey View Post
    If I then put in

    Code:
    if (strcmp("Mass*",param[i])==0) mass=param2[i];
    in the tokenising loop as posted previously, then print 'mass' both within and outside the loop, it's not saving anything to 'mass' - although changing the iteration number start in the loop has taken care of the seg fault, it seems.

    I think it -should- be working. I think you guys probably do too, from the amount of posts suggesting I've gone wrong somewhere else.
    So what does your data file look like. For this code to work, a line in the data file should look like:

    Mass*=2.000

    The line:

    Mass=2.000

    would not work.

    Are you thinking that the * is a wild card? There are no regular expression or wild card characters in a strcmp strings. Look at the standard or man page or C programming language text book for the description of strcmp.

  8. #23
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Also, mass is not an array. So if you find "Mass*" twice in your loop, it's going to overwrite what you wrote there the first time.


    Quzah.
    Hope is the first step on the road to disappointment.

  9. #24
    Registered User
    Join Date
    Jul 2010
    Location
    Liverpool
    Posts
    34
    That's helpful, yes, I was treating it as a wildcard symbol. The whole of the text file I'm reading is:

    Code:
    Aircraft Parameters to be read.  Do not add extra lines
    or swap the order of parameters as this will make the program give
    VERY unexpected results!  // obviously I'd like to be able to remove this sentence
    
    Air density (kg/m3) = 1.225
    Mass (kg)=500
    Engine power (HP) = 100
    Cruise speed (mph) = 85
    V(stall) (m/s) = 12.96
    Screen height (m) = 15
    Cl for stall (Clmax) = 3.1
    Proportion of Cl(takeoff) to Cl(max) = 0.9
    Proportion of V(takeoff) to V(stall) = 1.1
    Propeller efficiency = 0.8
    
    If Cd = a + bCl^2:
    a = 0.03
    b = 0.06
    
    WING PARAMETERS
    Chord length (m) = 1.4
    Wingspan (m) = 8.23
    Wing area (m2) = 11.4
    Max. wing loading (kg/m2) = 43.8
    Lift curve slope (per rad) from ESDU program = 4.25
    Taper ratio = 1
    Wing twist? (0 for no, 1 for yes) = 0
    Shear modulus G = 25e9
    Torsion constant J = 0.00288
    Wing mount angle on fuselage (deg) = 0
    Moment coefficient at aerodynamic centre = -0.1
    Distance from aerodynamic centre to elastic axis (m) = 0.5
    Distance from centre of gravity to elastic axis (m) = 0.2
    However, if I take out the wildcard and replace it with "Mass (kg)" with varying numbers of spaces after (kg) or even change the file so there's no spaces around the equals signs.. it still doesn't save anything to 'mass'. Are there any other methods of doing this?

  10. #25
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I think a better approach would be:
    Read string + space.
    Store in buffer.
    Read string + space.
    If read string does not begin with '=', copy to buffer and repeat.
    If read string begins with '=', we know we've read the entire name, so then compare it to "mass", etc, to see what it is.
    Now we expect to see the value it is associated with, so read into an integer. Store the result.
    Eat newline.
    Repeat.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #26
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    That's pretty crappy too. Why not just use fgets to read the whole line, then parse it how you need to. You could always use sscanf with something like %[^=] to peel off the first segment, or you could use strchr to find the = sign.


    Quzah.
    Hope is the first step on the road to disappointment.

  12. #27
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Reading can be done from an existing string, or line, or directly from the file. It doesn't matter, really.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. 20q game problems
    By Nexus-ZERO in forum C Programming
    Replies: 24
    Last Post: 12-17-2008, 05:48 PM