Solved

Help with scanf

Posted on 2003-12-04
10
573 Views
Last Modified: 2010-04-15
Hi,

I'm using scanf to parse simple char strings. For example given the string char s[z] = "AB 4.1 6.2", I will use something as this:


char s[MAX];
float fVal1 = 1.0f, fVal2 = 2.0f;

sscanf (sz, "%s %f %f",s, &fVal1, &fVal2);

So now variables s, fVal1 and fVal2 hold the values I need.

But how can I parse a string when the number of arguments is variable? For instance, given the following string:

sz = "ab 2.3 4.5 2 6.7 8.9";

where the number 2 gives the number of parameters that follow it, in this case parameters 6.7 and 8.9

Any help?

Thank you :-)


0
Comment
Question by:elito
  • 3
  • 2
  • 2
  • +3
10 Comments
 
LVL 45

Accepted Solution

by:
sunnycoder earned 100 total points
ID: 9874149
Hi elito,

> sz = "ab 2.3 4.5 2 6.7 8.9";

sscanf (sz, "%s %f %f %d",s, &fVal1, &fVal2, &num);

now number of expected arguments is held in num .... you can repeat sscanf to get two more ints

a more elegant and preferred way is to parse the entire string yourself using strchr() (you can also use strtok)

temp1 = string;
while ( ( temp = strchr(string, ' ')) != NULL )
{
        /* print string between temp1 and temp */
        temp1 = temp + 1;
}

the above snippet assumes that all args are separated by a single space ... if there can be multiple spaces, you can always replace temp1=temp+1 by
temp1 = temp;
while ( isspace (*temp1) )
    temp1++;
temp=temp1;

If you are dealing with variable number of arguments in a function (like printf), look into va_arg

Cheers!
Sunny:o)
0
 
LVL 45

Expert Comment

by:Kdo
ID: 9874272

Hi elito,

This can be broken into two problems, or handled as a single problem.  The single problem solution is much cleaner.  Just expand your sscanf() statement so that it can handle the largest parameter list that you'll accept.  Actually, have it accept one MORE that you'll handle.  That way if N is greater than your limit, you know that too many parameters are on the line.

sscanf (string, " %s %f %f %N %f %f %f %f %f %f %f %f %f %f", s, &Val1, %Val2, N, &F1, &F2, &F3, &F4, &F5, &F6, &F7, &F8, &F9, &F10);

'N' will be set to the number of parameters that follow it, F1..Fn will be set the the value of its corresponding parameter, and the rest of the Fx variables will remain unchanged.

Note that the scan string starts with a space.  This tells sscanf() that the line MIGHT start with whitespace and to ignore the spaces if they are present.


Good Luck,
Kent
0
 

Expert Comment

by:jayesh_j_patel
ID: 9874344
Try this:

char *temp;
char *seperator = " "; // this is a space, also you can add comma, semicolon etc as a seperator
temp = strtok(sz, seperator);
while(temp)
{
    valFlt = atof(temp); // for float data, for int type use valInt = atoi(temp);
    temp = strtok(NULL, seperator); // make sure to use NULL as a first parameter to strtok function
}

Still I have a question how do you know what is the data type for each item in the string. You must have some kind of indication or something to know the data type otherwise how you will parse string into the proper data type?
Hope will help
Jayesh
0
 

Author Comment

by:elito
ID: 9875196
Hi,

Thanks all for your comments. I think the easiest wat for me would be to use the sscanf function using a variable number of arguments va_arg. Does anyone know how to use sscanf and va_arg?

Thanks :-)

0
 
LVL 45

Expert Comment

by:Kdo
ID: 9875300
Hi elito,

va_arg won't help you here.  It's a c macro that extracts formal parameters from within a function.

SomeFunction (char *s, float f1, float f2, int N, ....);

This would be the header format if you were building a function in C to handle the parameters.  But you're trying to extract DATA.  Not code a function.

The sscanf() function that I offered solves the entire problem with one line of C code.  Can't get much cleaner code than that.


Kent
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Author Comment

by:elito
ID: 9875498
Thanks Kent,

Yes, I'm sure your code will work fine, the main problem is that the number of variable arguments is undefined. Normally they are about 4-8 but they can be *any*number. I thought that as printf accepts variable arguments through va_arg (if I'm correct, not sure ...), the same could be applied to sscanf
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 9876079
Elito,

This is not 'tested' code but I'd do something like:

float f [MAX]; // Some maximum number of floats.
int took; // How manty characters the scanf took.
int i, pos; // Which float and where we are in 's'.
char * s = "1.2 1.3 1.5" // For example.

for ( i = 0; pos = 0; i < MAX && pos < strlen(s) && scanf ( &s[pos], "%f %n", &f[i], &took ) == 2; i++, pos += took );

If you can 'consume' each float inside the loop then you could even remove the limit. The essence here is that %n generates the number of charactes taken and the return value of sscanf is the number of correct scans achieved.

NOTE: You may have to use '== 1'. I cant remember if %n is counted in the return result.

Paul

0
 
LVL 45

Expert Comment

by:Kdo
ID: 9876485
Hi Elito,

*any* number is a lot.  :)  There has to be an upper limit, even if that limit is "whatever memory will hold".  You've got to have some place to store them, you've got to have a way to reference them, and you will also need a use for them.  If all three of these requirements aren't met, then the data is meaningless and can probably be ignored.

How are you getting the string?  read(), fgets(), etc all have defined limits that are the length of the buffer.  If you know the length of the buffer, you know the upper limit.


sidebar -- I just reread the first two paragraphs and they sound a bit antagonistic.  I don't mean to come off that way.


So... to apologize :) here's a bit of code that should do what you want.

char *Data = "ab 2.3 4.5 2 6.7 8.9";  /*  The data to be parsed  */
char *Ptr;          /*  Pointer to field within Data  */

char *DataPrfx;  /*  Ptr to substring that starts the current string  */
float F1,F2;       /*  First two data items  */

int    Expected;       /*  Number of data items expected following the 'header'  */
int    Count;           /*  Number of data items found following the header  */

float *Table;     /*  Data items that follow the Count field  */

  Ptr = strtok (Data, " ");
  DataPrfx = Ptr;  /*  "ab"  */

  Ptr = strtok (NULL, " ");
  F1 = atof (Ptr);  /*  2.3  */

  Ptr = strtok (NULL, " ");
  F2 = atof (Ptr);  /*  4.5  */

  Ptr = strtok (NULL, " ");
  Expected = atoi (Ptr);

  Table = (float *) malloc (Expected * sizeof (float));
  for (Count = 0; Count < Expected; Count++)
  {
    Ptr = strtok (NULL, " ");
    if (Ptr == NULL)  /*  Not enough data items on the line. */
      break;
    Table[Count] = atof (Ptr);
  }

Note that sanity checks should be inserted into the program.  In this example, if the string doesn't contain the first 4 fields, strtok() will return NULL and the results might include core dumps.  :)

Kent
0
 
LVL 3

Expert Comment

by:guynumber5764
ID: 9879327
Elito,
I seem to say this a lot but...Sunny's soln looks like best fit for your needs.  Be careful about *any* number of arguments and fgets() though.  Since the line length is (by definition) unlimited but your buffer is fixed length, there may be a vuln there.

0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 9880993
Hi Elito,

va_args is used to parse arguments in the function which receives variable number of arguments while being called.
Here you have variables in a string and you need to read them ... Thus you will have to rely on string parsing ...

int i = 0;
char buffer[64];
temp1 = string;
while ( ( temp = strchr(string, ' ')) != NULL )  //till string is exhausted, get location of next space char
{
       i++;           //increment counter
       strncpy ( buffer, temp1, temp - temp1 );     //
       buffer [temp-temp1] = 0;
       printf ( "argument number %d -- %s", i, buffer );
       temp1 = temp + 1;
}

this code snippet will parse the string and print out all the arguments irrespective of how many arguments are present ... (you will have to print the last arg after loop
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Suggested Solutions

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
The goal of this video is to provide viewers with basic examples to understand and use structures in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now