fscanf()

This is a discussion on fscanf() within the C Programming forums, part of the General Programming Boards category; Hi deee Ho peeps! I found a new (new to me at least) nifty looking gnu extension in fscanf modifiers. ...

  1. #1
    Maz
    Maz is offline
    Registered User Maz's Avatar
    Join Date
    Nov 2005
    Location
    Finland
    Posts
    194

    fscanf()

    Hi deee Ho peeps!

    I found a new (new to me at least) nifty looking gnu extension in fscanf modifiers.

    Man pages state:
    An optional 'a' character. This is used with string conversions, and relieves the caller of the need to allo-
    cate a corresponding buffer to hold the input: instead, scanf() allocates a buffer of sufficient size, and
    assigns the address of this buffer to the corresponding pointer argument, which should be a pointer to a char *
    variable (this variable does not need to be initialized before the call). The caller should subsequently
    free(3) this buffer when it is no longer required. This is a GNU extension; C99 employs the 'a' character as a
    conversion specifier (and it can also be used as such in the GNU implementation).
    So I tried parsing a textfile, which may have comment lines starting with #, or valid data lines which are form:
    integer:string
    Eg

    #this is a comment line and should be ignored.
    #following is a valid data:
    123:yeah, 123 it is


    I tried following simple thing:

    Code:
    ...
    while(ok)
            {
                int scanned;
                char *reply;
                int eventId;
                scanned=fscanf(readfile,"#%a[^\n]",&reply);
                //Ignore comment lines
                if(scanned>0)
                {
                    free(reply);
                    continue;
                }
    
                scanned=fscanf(readfile,"%d:%a[^\n]",&eventId,&reply);
                if(scanned<=0)
                {
                    ok=0;
                }
                else if(scanned!=2)
                {
                    printf("Error Error Error! Malformed default cb reply file %s\n",data);
                }
                else
                {
    ...
    However this miserably fails. The first line (which is comment line) is not read by first fscanf - at least scanned is set to zero.

    And if I remove comment lines from file, then the second scanf will only read the numeric value from file. (and set scanned to 1)

    Strange thing is, that I have a feeling I had this piece working before I updated my fedora a few days ago... Has anyone used this a specifier successfully, and had it working?

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    Read the man page again: This is used with string conversions, not instead of them.

  3. #3
    Maz
    Maz is offline
    Registered User Maz's Avatar
    Join Date
    Nov 2005
    Location
    Finland
    Posts
    194
    Quote Originally Posted by tabstop View Post
    Read the man page again: This is used with string conversions, not instead of them.
    Thanks tabstop. But i still fail to see my mistake. [ is string specifier, right?
    Last edited by Maz; 08-30-2009 at 07:46 AM.

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    Quote Originally Posted by Maz View Post
    Thanks tabstop. But i still fail to see my mistake. [ is string specifier, right?
    No? I think the a flag only works with s.

  5. #5
    Maz
    Maz is offline
    Registered User Maz's Avatar
    Join Date
    Nov 2005
    Location
    Finland
    Posts
    194
    might be. I just think i had it working with [ before. Thats why i asked if anyone has used it.

  6. #6
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    You could also hit up man scanf on your particular system and make sure it's there.

  7. #7
    Maz
    Maz is offline
    Registered User Maz's Avatar
    Join Date
    Nov 2005
    Location
    Finland
    Posts
    194
    Yeah. man pages were the thing where I found out the a specifier. And [ should be valid specifier to be used with a - according to:

    The GNU C Library

    If someone had time and enthusiasm to test if %a[^\n] works for them.... Well, I'd be gratefull

  8. #8
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    It doesn't work for me, but then I have a BSD scanf and not a GNU one. That's why I asked whether you had checked your own man pages, not the ones on t'internet.

  9. #9
    Maz
    Maz is offline
    Registered User Maz's Avatar
    Join Date
    Nov 2005
    Location
    Finland
    Posts
    194
    Okay. I guess I have done something wrong. So I did a small test code - and looks like there is a bug - or then I have done something wrong again

    (I still bet it is the latter)

    Hence, can someone spot the grande bug in my reasoning:

    I used code:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    
    int main(void)
    {
        FILE *testfile;
        int commentfound,datafound;
        int scanned;
        char *readdata;
        int readint;
        int ok=1;
        testfile=fopen("scanftest.txt","r");
        if(NULL==testfile)
        {
            perror("Could not open file\n");
            return -1;
        }
        while(ok)
        {
            commentfound=datafound=0;
            scanned=fscanf(testfile,"#%a[^\n]\n",&readdata);
            if(scanned<0 || feof(testfile))
                ok=0;
            if(scanned!=1)
            {
                printf("Could not find commentline (scanned=%d)\n",scanned);
            }
            else
            {
                printf("commentline found: \"%s\"\n",readdata);
                free(readdata);
                commentfound=1;
                continue;
            }
            scanned=fscanf(testfile,"%d:%a[^\n]\n",&readint,&readdata);
            if(scanned<0 || feof(testfile))
                ok=0;
            if(scanned!=2)
            {
                printf("could not find realdata (scanned=%d)\n",scanned);
            }
            else
            {
                printf("data found: \"%d:%s\"\n",readint,readdata);
                datafound=1;
                free(readdata);
            }
            if(!commentfound && !datafound)
            {
                readdata=NULL;
                readint=NULL;
                if(0!=(readint=getline(&readdata,&readint,testfile)) && -1!= readint)
                {
                    printf("This line was neither comment, nor data: \"%s\"\n",readdata);
                    free(readdata);
                }
                if(-1==readint)
                {
                    printf("getline noticed problems... %s",strerror(errno));
                    ok=0;
                }
                if(feof(testfile))
                {
                    printf("EOF");
                    ok= 0;
                }
            }
        }
        return 0;
    }
    (I know the feof should be avoided and so on... but hey, this was just a test).

    I used scanftest.txt:
    #OWN_ID:
    0:MazBot_V4@127.0.0.1
    #E_callback_event_file
    1:events.conf
    #E_event_def_reply_file
    2:def_replies.conf
    #E_text_event_prefix_in_use
    3:0
    #E_text_event_prefix
    #4:!
    #E_own_nick
    5:MazBotV4
    #E_user_ident_mode
    #0 = registered users based on nick, nonregged cannot be identified
    #1 = password based - user needs to send password to bot.
    #2 = hostmask
    6:0
    #E_user_level_file_name_reg
    7:userlevel_modeRegNick.conf
    #E_user_level_file_name_pass
    8:userlevel_modePasswd.conf
    #E_user_level_file_name_host
    9:userlevel_modeHostmask.conf
    and compilation spilled expected warning about int Vs. size_t (I misused the readint variable because I was too excited when I wanted to see the results) (Sorry - it's in finnish)

    [Matti@home exe]$ gcc -Wall -ggdb -o scanftest scanftest.c
    scanftest.c: Funktio ”main”:
    scanftest.c:53: varoitus: sijoitus tekee osoittimesta kokonaisluvun ilman tyyppimuunnosta
    scanftest.c:54: varoitus: pointer targets in passing argument 2 of ”getline” differ in signedness
    /usr/include/stdio.h:653: huom: expected ”size_t * __restrict__” but argument is of type ”int *”

    And result was:
    [Matti@home exe]$ ./scanftest
    Could not find commentline (scanned=0)
    could not find realdata (scanned=0)
    This line was neither comment, nor data: "OWN_ID:
    "
    Could not find commentline (scanned=0)
    could not find realdata (scanned=1)
    This line was neither comment, nor data: "MazBot_V4@127.0.0.1
    "
    Could not find commentline (scanned=0)
    could not find realdata (scanned=0)
    This line was neither comment, nor data: "E_callback_event_file
    "
    Could not find commentline (scanned=0)
    could not find realdata (scanned=1)
    This line was neither comment, nor data: "events.conf
    "
    Could not find commentline (scanned=0)
    could not find realdata (scanned=0)
    This line was neither comment, nor data: "E_event_def_reply_file
    "
    Could not find commentline (scanned=0)
    could not find realdata (scanned=1)
    This line was neither comment, nor data: "def_replies.conf
    "
    Could not find commentline (scanned=0)
    could not find realdata (scanned=0)
    This line was neither comment, nor data: "E_text_event_prefix_in_use
    "
    Could not find commentline (scanned=0)
    data found: "3null)"
    Could not find commentline (scanned=0)
    could not find realdata (scanned=0)
    This line was neither comment, nor data: "#E_text_event_prefix
    "
    Muistialueen ylitys
    where "Muistialueen ylitys" = "Segmentation Fault". It crashed inside printf("commentline found: \"%s\"\n",readdata); this call (according to gdb), because readdata was not pointing to valid memory.

    So, can someone spot my bug?

  10. #10
    Maz
    Maz is offline
    Registered User Maz's Avatar
    Join Date
    Nov 2005
    Location
    Finland
    Posts
    194
    Thanks tabstop, I really DO appreciate your help

    (And getline is another GNU extension:

    Function: ssize_t getline (char **lineptr, size_t *n, FILE *stream)
    This function reads an entire line from stream, storing the text (including the newline and a terminating null character) in a buffer and storing the buffer address in *lineptr.

    Before calling getline, you should place in *lineptr the address of a buffer *n bytes long, allocated with malloc. If this buffer is long enough to hold the line, getline stores the line in this buffer. Otherwise, getline makes the buffer bigger using realloc, storing the new buffer address back in *lineptr and the increased size back in *n. See section 3.2.2 Unconstrained Allocation.

    If you set *lineptr to a null pointer, and *n to zero, before the call, then getline allocates the initial buffer for you by calling malloc.

    In either case, when getline returns, *lineptr is a char * which points to the text of the line.

    When getline is successful, it returns the number of characters read (including the newline, but not including the terminating null). This value enables you to distinguish null characters that are part of the line from the null character inserted as a terminator.

    This function is a GNU extension, but it is the recommended way to read lines from a stream. The alternative standard functions are unreliable.

    If an error occurs or end of file is reached without any bytes read, getline returns -1.

  11. #11
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    %a, by itself, means "look for a floating-point number", and I find it highly significant that the only time you get a "found data" message is when the data you should be finding is numeric. If you've got gdb, you can see what readdata is when the crash happens. Is it 0? Better yet, if you change those numbers to say 5, is that what you get there? (Although I would expect differing-arguments warnings if so, since %a should read into a char**.)

  12. #12
    Maz
    Maz is offline
    Registered User Maz's Avatar
    Join Date
    Nov 2005
    Location
    Finland
    Posts
    194
    yep. Readdata is not NULL, it is some garbage memory address:

    Program received signal SIGSEGV, Segmentation fault.
    0x00b07070 in _IO_vfprintf_internal (s=0xc304c0, format=0x8048918 "commentline found: \"%s\"\n", ap=0xbffff354 "") at vfprintf.c:1580
    1580 process_string_arg (((struct printf_spec *) NULL));
    Current language: auto; currently minimal
    (gdb) bt
    #0 0x00b07070 in _IO_vfprintf_internal (s=0xc304c0, format=0x8048918 "commentline found: \"%s\"\n", ap=0xbffff354 "") at vfprintf.c:1580
    #1 0x00b0e0a0 in __printf (format=0x8048918 "commentline found: \"%s\"\n") at printf.c:35
    #2 0x08048683 in main () at scanftest.c:32
    (gdb) frame 3
    #0 0x00000000 in ?? ()
    (gdb) frame 2
    #2 0x08048683 in main () at scanftest.c:32
    32 printf("commentline found: \"%s\"\n",readdata);
    Current language: auto; currently c
    (gdb) inspect readdata
    $1 = 0x40800000 <Address 0x40800000 out of bounds>
    (gdb) break scanftest.c:32
    Breakpoint 1 at 0x804866e: file scanftest.c, line 32.
    (gdb) run
    .
    .
    .
    And just to verify that nothing had messed the readdata in frame 2, I retried:
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y
    Starting program: /home/Matti/MazBotV4_svn/MazBot/test/exe/scanftest
    Could not find commentline (scanned=0)
    could not find realdata (scanned=0)
    This line was neither comment, nor data: "OWN_ID:
    "
    Could not find commentline (scanned=0)
    could not find realdata (scanned=1)
    This line was neither comment, nor data: "MazBot_V4@127.0.0.1
    "
    Could not find commentline (scanned=0)
    could not find realdata (scanned=0)
    This line was neither comment, nor data: "E_callback_event_file
    "
    Could not find commentline (scanned=0)
    could not find realdata (scanned=1)
    This line was neither comment, nor data: "events.conf
    "
    Could not find commentline (scanned=0)
    could not find realdata (scanned=0)
    This line was neither comment, nor data: "E_event_def_reply_file
    "
    Could not find commentline (scanned=0)
    could not find realdata (scanned=1)
    This line was neither comment, nor data: "def_replies.conf
    "
    Could not find commentline (scanned=0)
    could not find realdata (scanned=0)
    This line was neither comment, nor data: "E_text_event_prefix_in_use
    "
    Could not find commentline (scanned=0)
    data found: "3null)"
    Could not find commentline (scanned=0)
    could not find realdata (scanned=0)
    This line was neither comment, nor data: "#E_text_event_prefix
    "

    Breakpoint 1, main () at scanftest.c:32
    32 printf("commentline found: \"%s\"\n",readdata);
    (gdb) inspect readdata
    $2 = 0x40800000 <Address 0x40800000 out of bounds>
    (gdb) next

    Program received signal SIGSEGV, Segmentation fault.
    0x00b07070 in _IO_vfprintf_internal (s=0xc304c0, format=0x8048918 "commentline found: \"%s\"\n", ap=0xbffff354 "") at vfprintf.c:1580
    1580 process_string_arg (((struct printf_spec *) NULL));
    Current language: auto; currently minimal
    (gdb)

  13. #13
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    Just for you, I booted into Debian. My results from your source code and your .txt file:
    Code:
    commentline found: "OWN_ID:"
    Could not find commentline (scanned=0)
    data found: "0:MazBot_V4@127.0.0.1"
    commentline found: "E_callback_event_file"
    Could not find commentline (scanned=0)
    data found: "1:events.conf"
    commentline found: "E_event_def_reply_file"
    Could not find commentline (scanned=0)
    data found: "2:def_replies.conf"
    commentline found: "E_text_event_prefix_in_use"
    Could not find commentline (scanned=0)
    data found: "3:0"
    commentline found: "E_text_event_prefix"
    commentline found: "4:!"
    commentline found: "E_own_nick"
    Could not find commentline (scanned=0)
    data found: "5:MazBotV4"
    commentline found: "E_user_ident_mode"
    commentline found: "0 = registered users based on nick, nonregged cannot be identified"
    commentline found: "1 = password based - user needs to send password to bot."
    commentline found: "2 = hostmask"
    Could not find commentline (scanned=0)
    data found: "6:0"
    commentline found: "E_user_level_file_name_reg"
    Could not find commentline (scanned=0)
    data found: "7:userlevel_modeRegNick.conf"
    commentline found: "E_user_level_file_name_pass"
    Could not find commentline (scanned=0)
    data found: "8:userlevel_modePasswd.conf"
    commentline found: "E_user_level_file_name_host"
    Could not find commentline (scanned=0)
    data found: "9:userlevel_modeHostmask.conf"
    So I guess that's good news and bad news.

  14. #14
    Maz
    Maz is offline
    Registered User Maz's Avatar
    Join Date
    Nov 2005
    Location
    Finland
    Posts
    194
    But yes. When I changed the char after # to be numeric, I got crash right away. So it really seems fscanf mixes the 'a' with float. :/

  15. #15
    Maz
    Maz is offline
    Registered User Maz's Avatar
    Join Date
    Nov 2005
    Location
    Finland
    Posts
    194
    Thousands of thanks tabstop I doubt I would have bothered just for a stranger on a forum

    I owe you one at the local pub

    I guess I could go and file a bug report to fedora :/

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. fscanf causes a SEGMENTATION FAULT
    By yougene in forum C Programming
    Replies: 15
    Last Post: 12-28-2008, 11:11 PM
  2. fscanf in different functions for the same file
    By bchan90 in forum C Programming
    Replies: 5
    Last Post: 12-03-2008, 08:31 PM
  3. Using fscanf with a structure
    By daluu in forum C Programming
    Replies: 10
    Last Post: 10-11-2004, 01:32 PM
  4. fscanf problem in C
    By kepler in forum C Programming
    Replies: 6
    Last Post: 09-30-2003, 06:24 AM
  5. fscanf on sun's
    By brif in forum C Programming
    Replies: 2
    Last Post: 04-14-2002, 01:22 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21