Thread: sscanf matching problems

  1. #1
    Registered User
    Join Date
    Jun 2009
    Posts
    486

    sscanf matching problems

    I need to count the number of "timesteps" in a file (format shown below) I cound this by counting the number of lines that have 2 integers and a single double and nothing else in them using the code

    Code:
    int countTimeSteps(FILE *position)
    {
      char line [MAXNUM]; //lines will be much less than 1000 characters, but it can't hurt
      int check,x,y,N_timeSteps;
      double z;
      N_timeSteps = 0;
      
      while (fgets(line, MAXNUM, position) != NULL) //read in file 1 line at a time
      {
        //puts(line);
        check = sscanf(line,"%d%d%lf",&x,&y,&z); 
        if (check != 0 && check != EOF) //if the line contains an integer value at the start
        {
          ++N_timeSteps;
        }
      }
      return N_timeSteps;
    }
    However, this seems to match every line.... Why is this not working?

    Here is part of the file I am reading from:

    Code:
    5 5 0
     1           0           0           0           0           0           0
     1      5.7993      5.7993           0           0           0           0
     1      5.7993           0     -5.7993           0           0           0
     1      5.7993           0      5.7993           0           0           0
     1      5.7993     -5.7993           0           0           0           0
    -1      2.0504           0           0           0           0           0
    -1      7.8496      5.7993           0           0           0           0
    -1      7.8496           0     -5.7993           0           0           0
    -1      7.8496           0      5.7993           0           0           0
    -1      7.8496     -5.7993           0           0           0           0
    5 5 0.12
     1  2.9581e-06           0           0  1.1595e-06           0           0
     1      5.7993      5.7993           0  1.4193e-06 -6.9289e-08           0
     1      5.7993 -1.3264e-23     -5.7993  1.4193e-06 -3.2084e-24  6.9289e-08
     1      5.7993 -1.3264e-23      5.7993  1.4193e-06 -3.2084e-24 -6.9289e-08
     1      5.7993     -5.7993           0  1.4193e-06  6.9289e-08           0
    -1      1.2922           0           0    -0.29463           0           0
    -1      6.9823      5.8662           0    -0.33479    0.021945           0
    -1      6.9823           0     -5.8662    -0.33479           0   -0.021945
    -1      6.9823           0      5.8662    -0.33479           0    0.021945
    -1      6.9823     -5.8662           0    -0.33479   -0.021945           0
    5 5 0.23
     1  9.5596e-06           0 -1.7237e-23  1.5282e-06           0 -1.6028e-23
     1      5.7993      5.7993 -2.6508e-24  1.6843e-06  1.5394e-08 -6.4124e-24
     1      5.7993  -3.117e-23     -5.7993  1.6843e-06 -1.3807e-40 -1.5394e-08
     1      5.7993  -3.117e-23      5.7993  1.6843e-06 -1.3807e-40  1.5394e-08
     1      5.7993     -5.7993 -2.5042e-24  1.6843e-06 -1.5394e-08 -6.0848e-24
    -1    -0.37038           0  1.9004e-18    -0.38423           0  1.5304e-18
    -1      5.1619      5.9365  2.5342e-18    -0.39775   0.0021853  2.6822e-18
    -1      5.1619           0     -5.9365    -0.39775           0  -0.0021853
    -1      5.1619           0      5.9365    -0.39775           0   0.0021853
    -1      5.1619     -5.9365  2.5358e-18    -0.39775  -0.0021853  2.6835e-18
    The function should return 3, but it is returning the number of lines instead. Why is this happening? I can see why it is matching the second line, perhaps, but not all of them...

    So: Is there a function that I can se to check if a line contains ONLY
    "[integer] [integer] [double]"? and nothing else?
    Last edited by KBriggs; 06-23-2009 at 10:48 AM.

  2. #2
    Registered User
    Join Date
    Jun 2009
    Posts
    486
    Think I got it sorted

    Code:
    int countTimeSteps(FILE *position)
    {
      char line [MAXNUM]; //lines will be much less than 1000 characters, but it can't hurt
      int check,N_timeSteps;
      double x;
      N_timeSteps = 0;
      
      while (fgets(line, MAXNUM, position) != NULL) //read in file 1 line at a time
      {
        //puts(line);
        check = sscanf(line,"%lf%lf%lf%lf%lf%lf%lf",&x,&x,&x,&x,&x,&x,&x); 
        if (check == 3) //if the line contains an integer value at the start
        {
          ++N_timeSteps;
        }
      }
      return N_timeSteps;
    }
    But if anyone has suggestions for a more elegant solution I am all ears

    And I would still like an explanation of why the first code was matching all lines in the file - I must be misunderstanding the way sscanf works.
    Last edited by KBriggs; 06-23-2009 at 10:55 AM.

  3. #3
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Each of those lines starts with an integer and an integer and a double. (Print out the results and you'll see what I mean.)

    You could maybe use strtof three times in a row and see if there's anything in the "leftover" portion. But in general if you have something like you have where the shorter lines are sort-of a subset of the larger ones, then you'll have to check for the larger lines first.

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by tabstop View Post
    Each of those lines starts with an integer and an integer and a double. (Print out the results and you'll see what I mean.)
    Code:
     1  2.9581e-06
    int 1, int 2, double .9581e-06
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    I don't accept 0 as a double. 0.0 is a double. It has to have a decimal point in it.

    Now your job is very easy, every line with only one decimal point in it, gets counted.

    If you're looking for integers, don't you want to use %d, instead of %lf?
    Last edited by Adak; 06-23-2009 at 11:22 AM.

  6. #6
    Registered User
    Join Date
    Jun 2009
    Posts
    486
    %lf will make the ints into doubles, I was only interested in the return value of sscanf there - if it was 3, it means three numbers, which means another timestep. For long lines it would return 7. The one decimal place idea would probably work, but would be less efficient since it involves counting characters in line. Not much of a difference, but it's there ^_^
    Last edited by KBriggs; 06-23-2009 at 12:56 PM.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    You could try this.
    Code:
      while (fgets(line, MAXNUM, position) != NULL) //read in file 1 line at a time
      {
        int pos;
        check = sscanf(line,"%d%d%lf%n",&x,&y,&z,&pos);
        if ( check == 3 && line[pos] == '\n' )
        {
          ++N_timeSteps;
        } 
      }
    Note that %n is NOT counted as a conversion, so it's still == 3
    This assumes an immediate \n at the end of the line. Refine it if you have trailing whitespace.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Jun 2009
    Posts
    486
    Cool, that works too.

    probably not the best idea to declare a variable inside a loop though ^_^

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > probably not the best idea to declare a variable inside a loop though ^_^
    Why not?
    You don't need it to have any greater scope do you?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Registered User
    Join Date
    Jun 2009
    Posts
    486
    It makes runtime take noticeably longer

  11. #11
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    How so?

    Sure, if the object in question was a bloated C++ class with an expensive ctor and dtor, then you would have a point.

    But this is C, and it is an int.
    Unless your compiler is particularly brain-damaged, the space for that variable is allocated just ONCE when the function is called. It is not created and destroyed each time around the loop.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. No clue how to make a code to solve problems!
    By ctnzn in forum C Programming
    Replies: 8
    Last Post: 10-16-2008, 02:59 AM
  2. sscanf()
    By task in forum C Programming
    Replies: 4
    Last Post: 11-22-2003, 04:43 PM
  3. Simple sscanf mystery
    By registering in forum C Programming
    Replies: 4
    Last Post: 06-10-2003, 11:47 PM
  4. sscanf (I think)
    By RyeDunn in forum C Programming
    Replies: 7
    Last Post: 07-31-2002, 08:46 AM
  5. SSCANF help
    By mattz in forum C Programming
    Replies: 7
    Last Post: 12-10-2001, 04:53 PM