question about scanf

Discussion in 'C Programming' started by TP, Apr 16, 2014.

  1. TP

    TP Guest

    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
     
    TP, Apr 16, 2014
    #1
    1. Advertisements

  2. TP

    Stefan Ram Guest

    #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 ); }
     
    Stefan Ram, Apr 16, 2014
    #2
    1. Advertisements

  3. TP

    Kaz Kylheku Guest

    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
     
    Kaz Kylheku, Apr 16, 2014
    #3
  4. TP

    Stefan Ram Guest

    The above line can be removed.
    The above line should be changed to:

    The above line should be changed to:

    if( !*string || *p )raise( ERROR ); else printf( "number = %llu\n", i ); }
     
    Stefan Ram, Apr 16, 2014
    #4
  5. 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>
     
    Ben Bacarisse, Apr 16, 2014
    #5
  6. TP

    James Kuyper Guest

    "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;
    }
     
    James Kuyper, Apr 16, 2014
    #6
  7. TP

    Stefan Ram Guest

    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++.
     
    Stefan Ram, Apr 16, 2014
    #7
  8. Wow!! What code.
     
    Bill Cunningham, Apr 20, 2014
    #8
  9. TP

    viju.kantah Guest

    Seriously the code is very complex and difficult to understand. Is this on purpose?
     
    viju.kantah, Apr 20, 2014
    #9
  10. 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.
     
    Kenny McCormack, Apr 20, 2014
    #10
  11. TP

    BartC Guest

    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.
     
    BartC, Apr 20, 2014
    #11
  12. TP

    TP Guest

    This is indeed the solution I prefer.
    Thanks a lot

    TP
     
    TP, Apr 21, 2014
    #12
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.