scanf question using %[^$]

J

john

I'm trying to use scanf() to get a string that is terminated by a
$sign:

Reading a file line that has: account number, name (terminated by
$sign) and six numbers:
000001 John Doe$ 4 5 6 7 8 9


I'm trying to read it in like so:
int ret, acct, c1, c2, c3, c4, c5, c6;
char name[21];

ret = scanf("%d %[^$] %d %d %d %d %d %d",
&acct, name, &c1, &c2, &c3, &c4, &c5, &c6);


I would think that (ret should == 8), but it's only 2.

Variables acct & name look okay, but the cN vars look like they haven't
been assigne anything.

What am I doing wrong? If I split the name into two seperate strings,
say, first and last names, it works good, but I may not have both a
first & last name on every line.
 
W

Walter Roberson

john said:
000001 John Doe$ 4 5 6 7 8 9
ret = scanf("%d %[^$] %d %d %d %d %d %d",

%[^$] leaves the $ in the input stream. The space you have after
that in the format does not match the $ in the input stream, so
the format conversion terminates.

Try a format of "%d %[^$]$%d%d%d%d%d%d"
 
E

Eric Sosman

john wrote On 08/22/06 13:38,:
I'm trying to use scanf() to get a string that is terminated by a
$sign:

Reading a file line that has: account number, name (terminated by
$sign) and six numbers:
000001 John Doe$ 4 5 6 7 8 9


I'm trying to read it in like so:
int ret, acct, c1, c2, c3, c4, c5, c6;
char name[21];

ret = scanf("%d %[^$] %d %d %d %d %d %d",
&acct, name, &c1, &c2, &c3, &c4, &c5, &c6);


I would think that (ret should == 8), but it's only 2.

Variables acct & name look okay, but the cN vars look like they haven't
been assigne anything.

What am I doing wrong? If I split the name into two seperate strings,
say, first and last names, it works good, but I may not have both a
first & last name on every line.

The "%[^$]" stops when it encounters the '$' character,
leaving the '$' unconsumed. Try "%[^$]$". Better yet, try
"%20[^$]$" (to defend against overlength names).
 
M

Martin Ambuhl

john said:
I'm trying to use scanf() to get a string that is terminated by a
$sign:

Reading a file line that has: account number, name (terminated by
$sign) and six numbers:
000001 John Doe$ 4 5 6 7 8 9


I'm trying to read it in like so:
int ret, acct, c1, c2, c3, c4, c5, c6;
char name[21];

ret = scanf("%d %[^$] %d %d %d %d %d %d",
&acct, name, &c1, &c2, &c3, &c4, &c5, &c6);


I would think that (ret should == 8), but it's only 2.

Variables acct & name look okay, but the cN vars look like they haven't
been assigne anything.

What am I doing wrong?

Note the difference in the format strings below:

#include <stdio.h>

int main(void)
{
char input[] = "000001 John Doe$ 4 5 6 7 8 9";
int ret, acct, c1, c2, c3, c4, c5, c6;
char name[21];

printf("Attempt to read variables with format\n"
"\"%%d %%[^$] %%d %%d %%d %%d %%d %%d\"\n");
ret = sscanf(input, "%d %[^$] %d %d %d %d %d %d",
&acct, name, &c1, &c2, &c3, &c4, &c5, &c6);
printf("return value from scanf = %d\n\n", ret);

printf("Attempt to read variables with format\n"
"\"%%d %%[^$]$ %%d %%d %%d %%d %%d %%d\"\n");
ret = sscanf(input, "%d %[^$]$ %d %d %d %d %d %d",
&acct, name, &c1, &c2, &c3, &c4, &c5, &c6);
printf("return value from scanf = %d\n\n", ret);
return 0;
}

[output]
Attempt to read variables with format
"%d %[^$] %d %d %d %d %d %d"
return value from scanf = 2

Attempt to read variables with format
"%d %[^$]$ %d %d %d %d %d %d"
return value from scanf = 8
 
H

Herbert Rosenau

I'm trying to use scanf() to get a string that is terminated by a
$sign:

Reading a file line that has: account number, name (terminated by
$sign) and six numbers:
000001 John Doe$ 4 5 6 7 8 9


I'm trying to read it in like so:
int ret, acct, c1, c2, c3, c4, c5, c6;
char name[21];

ret = scanf("%d %[^$] %d %d %d %d %d %d",
&acct, name, &c1, &c2, &c3, &c4, &c5, &c6);

Look how scanf works:

%d reads the int.
%d reads until it dedects a whitespace, so it stops reading after John
is readed.
Then it tries to read and eat the '$' but there is none, so it fails
and return 2 as it has filled up 2 variables.
I would think that (ret should == 8), but it's only 2.

No wounder. The format does not match the data coming in.
Variables acct & name look okay, but the cN vars look like they haven't
been assigne anything.

What am I doing wrong? If I split the name into two seperate strings,
say, first and last names, it works good, but I may not have both a
first & last name on every line.

As you reads from stdin and that will mostenly (not always!) assigned
to console (e.g. keyboard) there are lots of lots to get unwanted
data. I would write my own little parser by reading with getc() and
looking at each char if the data coming in is what I want and if not
throwing away the rest of the line (fetc() until newline and printout
an error message to show the user the point he has mistyped.

The C I/O library was designed and written at the tme where punch
cards were the most common input devise and typing something in was
absolutely uncommon. So whenever you have to read some more complex
data you're on your own. It is impossible for scanf() to dedect each
and any typing error a user can made.

Beside that reading simple with %s is an invitation for buffer
overflow, %d can lead to loosing significant digits or if the value is
negative undefined behavior.

However when you have to read text that contains an unknown nuber of
words you lost with scvanf anyway. Even (f)gets() is no solution
because the standard says nothing how many characters are min maxim
can be a simple text line. Buffer overflow can occure.

--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 
E

Eric Sosman

Herbert Rosenau wrote On 08/22/06 16:03,:
I'm trying to use scanf() to get a string that is terminated by a
$sign:

Reading a file line that has: account number, name (terminated by
$sign) and six numbers:
000001 John Doe$ 4 5 6 7 8 9


I'm trying to read it in like so:
int ret, acct, c1, c2, c3, c4, c5, c6;
char name[21];

ret = scanf("%d %[^$] %d %d %d %d %d %d",
&acct, name, &c1, &c2, &c3, &c4, &c5, &c6);


Look how scanf works:

%d reads the int.

Fine so far.
%d reads until it dedects a whitespace, so it stops reading after John
is readed.

Now you've lost me. What "%d" do you refer to? If it's
the first one, then it stops converting the int when it reaches
the white space, but it does not consume the white space and
certainly doesn't consume "John". If you actually meant to
write "%[^$]" instead of "%d", then it will not stop on white
space at all: it will read all the way through "John Doe" and
stop just before the "$".
Then it tries to read and eat the '$' but there is none, so it fails
and return 2 as it has filled up 2 variables.

This cannot be right. Nothing in the format string tries
to "read and eat the '$'". (And that's the cause of the O.P.'s
difficulty.)
 
N

Nick Keighley

The C I/O library was designed and written at the tme where punch
cards were the most common input devise and typing something in was
absolutely uncommon.

really? Are you sure about this?
So whenever you have to read some more complex
data you're on your own. It is impossible for scanf() to dedect each
and any typing error a user can made.

<snip>
 
R

Richard Tobin

The C I/O library was designed and written at the tme where punch
cards were the most common input devise and typing something in was
absolutely uncommon.
[/QUOTE]
really? Are you sure about this?

It's probably true that most computer input was from punched cards at
that time, but that's not really relevant since C's standard i/o
library was written for Unix, which was designed as an interactive
system.

-- Richard
 
D

Dave Thompson

john said:
000001 John Doe$ 4 5 6 7 8 9
ret = scanf("%d %[^$] %d %d %d %d %d %d",

%[^$] leaves the $ in the input stream. The space you have after
Right.

that in the format does not match the $ in the input stream, so
the format conversion terminates.
Wrong. %-specifiers in *scanf must match something (at least one input
char) or they fail and terminate the call, but (any) whitespace
matches zero or more (of any) whitespace and continues on its merry
way even if there was no (aka zero) whitespace matched (and used).

It is the second %d that tries and fails to match the still waiting $.
Try a format of "%d %[^$]$%d%d%d%d%d%d"

Right.

- David.Thompson1 at worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top