question about scanf

T

TP

Hi everybody,

I want to scan a string for an integer, but I don't want any other character
in the string after the integer, otherwise an error has to be raised.

I have scrutinized the manual page of scanf, the best solution I have found
is something as:

//////////////////
#include <stdio.h>

int main( void )
{
int occurrence;
int nbcharreadjustafteroccurrence;
int nbcharreadatendofthestring;

printf("assignement number=%i\n"
, sscanf( "foo 3bar", "foo %d%n%*s%n"
, &occurrence
, &nbcharreadjustafteroccurrence
, &nbcharreadatendofthestring ) );

printf("characters after assignment=%i\n"
, nbcharreadatendofthestring - nbcharreadjustafteroccurrence );

return 0;
}

//////////////////

$ ./a.out
assignement number=1
characters after assignment=3
$

So I can raise an error if the number of characters is greater than zero.
Is there any better solution?

My idea was at some time to look for "$*[\0]", but of course it does not
work:

http://stackoverflow.com/questions/18024820/difference-between-255-0s-and-255c

Thanks in advance,

TP
 
S

Stefan Ram

TP said:
I want to scan a string for an integer, but I don't want any other character
in the string after the integer, otherwise an error has to be raised.

#include <stdio.h> /* printf */
#include <string.h> /* strpbrk */
#include <stdlib.h> /* exit */

#define ERROR 99
#define OVERFLOW 98
#define raise exit

int main()
{ unsigned long long i = 0;
char const * const string = "abc17";
char const * p = string;
while( *p < '0' || *p > '9' )++p;
while( *p >= '0' && *p <= '9' )
{ unsigned long long i10 = i * 10;
if( i10 / 10 != i )raise( OVERFLOW );
unsigned long long i1p = i10 +( unsigned long long )( *p - '0' );
if( i1p <= i10 )raise( OVERFLOW ); i = i1p; ++p; }
if( *p )raise( ERROR ); else printf( "number = %llu\n", i ); }
 
K

Kaz Kylheku

Hi everybody,

I want to scan a string for an integer, but I don't want any other character
in the string after the integer, otherwise an error has to be raised.

This logically means that the integer must be followed by the end of the
stream.

1. scan just the integer.
2. if feof(stream) is true, you're done
3. otherwise, call getc(stream): if the result is EOF, you're done
4. otherwise, error: characters after integer
 
S

Stefan Ram

#include <string.h> /* strpbrk */

The above line can be removed.
while( *p < '0' || *p > '9' )++p;

The above line should be changed to:

while( *p &&( *p said:
if( *p )raise( ERROR ); else printf( "number = %llu\n", i ); }

The above line should be changed to:

if( !*string || *p )raise( ERROR ); else printf( "number = %llu\n", i ); }
 
B

Ben Bacarisse

TP said:
I want to scan a string for an integer, but I don't want any other character
in the string after the integer, otherwise an error has to be raised.

I have scrutinized the manual page of scanf, the best solution I have found
is something as:

//////////////////
#include <stdio.h>

int main( void )
{
int occurrence;
int nbcharreadjustafteroccurrence;
int nbcharreadatendofthestring;

printf("assignement number=%i\n"
, sscanf( "foo 3bar", "foo %d%n%*s%n"
, &occurrence
, &nbcharreadjustafteroccurrence
, &nbcharreadatendofthestring ) );

printf("characters after assignment=%i\n"
, nbcharreadatendofthestring - nbcharreadjustafteroccurrence );

return 0;
}

I would just try to read another character:

sscanf(target, "foo %d%c", &number, &dummy)

If the result is zero you got nothing. If it's one, you got a number at
the end of the string. A result of 2 means there was a non-null byte
after the number.

<snip>
 
J

James Kuyper

Hi everybody,

I want to scan a string for an integer, but I don't want any other character
in the string after the integer, otherwise an error has to be raised.

I have scrutinized the manual page of scanf, the best solution I have found
is something as:

//////////////////
#include <stdio.h>

int main( void )
{
int occurrence;
int nbcharreadjustafteroccurrence;
int nbcharreadatendofthestring;

printf("assignement number=%i\n"
, sscanf( "foo 3bar", "foo %d%n%*s%n"
, &occurrence
, &nbcharreadjustafteroccurrence
, &nbcharreadatendofthestring ) );

printf("characters after assignment=%i\n"
, nbcharreadatendofthestring - nbcharreadjustafteroccurrence );

return 0;
}

//////////////////

$ ./a.out
assignement number=1
characters after assignment=3
$

So I can raise an error if the number of characters is greater than zero.
Is there any better solution?

"raise an error" is not very clear, and your example program doesn't
clarify it. I'll just print a message "Error raised", and you can insert
the appropriate code in place of that message:

include <stdio.h>
#include <string.h>

int main( void )
{
int occurrence;
int nbcharreadjustafteroccurrence;
char string[] = "foo 3bar";

printf("assignment number=%i\n"
, sscanf(string, "foo %d%n"
, &occurrence
, &nbcharreadjustafteroccurrence));

if(string[nbcharreadjustafteroccurrence])
{
printf("Error raised\n");
}

printf("characters after assignment=%zu\n"
, strlen(string+nbcharreadjustafteroccurrence));

return 0;
}
 
S

Stefan Ram

James Kuyper said:
"raise an error" is not very clear, and your example program doesn't
clarify it. I'll just print a message "Error raised", and you can insert
the appropriate code in place of that message:

In Ada, IIRC, »raise« raises an exception. In C++, the designers
wanted to copy this wording, but in C we already have

#include <signal.h>
int raise( int sig );

, so »throw« was chosen instead of »raise«. In Java, »raise« would
have been available, but it seems that Java wanted to copy C++.
 
B

Bill Cunningham

Stefan said:
#include <stdio.h> /* printf */
#include <string.h> /* strpbrk */
#include <stdlib.h> /* exit */

#define ERROR 99
#define OVERFLOW 98
#define raise exit

int main()
{ unsigned long long i = 0;
char const * const string = "abc17";
char const * p = string;
while( *p < '0' || *p > '9' )++p;
while( *p >= '0' && *p <= '9' )
{ unsigned long long i10 = i * 10;
if( i10 / 10 != i )raise( OVERFLOW );
unsigned long long i1p = i10 +( unsigned long long )( *p - '0' );
if( i1p <= i10 )raise( OVERFLOW ); i = i1p; ++p; }
if( *p )raise( ERROR ); else printf( "number = %llu\n", i ); }

Wow!! What code.
 
V

viju.kantah

Seriously the code is very complex and difficult to understand. Is this on purpose?
 
K

Kenny McCormack

Seriously the code is very complex and difficult to understand. Is this on purpose?

Gee. Ya think?

--

There are many self-professed Christians who seem to think that because
they believe in Jesus' sacrifice they can reject Jesus' teachings about
how we should treat others. In this country, they show that they reject
Jesus' teachings by voting for Republicans.
 
B

BartC

Seriously the code is very complex and difficult to understand. Is this on
purpose?

Just an odd style.

A more normal-looking version, with some (to me) extraneous features
removed, is this:

#include <stdio.h>
#include <stdlib.h>

#define ERROR 99
#define OVERFLOW 98

int main(void) {
int i = 0;
char* string = "abc17";
char* p = string;

while (*p<'0' || *p>'9')
++p;

while (*p>='0' && *p<='9') {
int i10 = i*10;
if (i10/10 != i)
exit( OVERFLOW );
int i1p = i10 + *p-'0';
if (i1p<=i10)
exit (OVERFLOW);
i = i1p;
++p;
}
if (*p)
exit (ERROR);
else
printf("Number = %d\n", i);
}

All those in-place declarations look like extra clutter to me; ideally
they'd be at the top, out of the way.
 
T

TP

Ben said:
I would just try to read another character:

sscanf(target, "foo %d%c", &number, &dummy)

If the result is zero you got nothing. If it's one, you got a number at
the end of the string. A result of 2 means there was a non-null byte
after the number.

This is indeed the solution I prefer.
Thanks a lot

TP
 

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,981
Messages
2,570,188
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top