Problems when reading from a file with fscanf

Discussion in 'C Programming' started by Benedicte, Feb 4, 2004.

  1. Benedicte

    Benedicte Guest

    Hi,

    I'm getting some problems when using fscanf to read a file.

    This is a piece of the program code:

    main ()
    {
    /*** Variable declaration ***/
    FILE *vpfile; /*** Data file ***/

    struct line
    {
    char old_al[10];
    char new_al[10];
    char vp[5];
    char new_dl[17];
    };
    struct line l[1000]={0};
    int i=0;
    int nl=0; /*** number of lines read ***/
    int res=0;

    /*** Executable statements ***/
    /*** Open VpMove.txt file ***/
    vpfile=fopen("/export/home/granite/CAPI/prog/bin/VpMove.txt","r");
    if(vpfile==NULL)
    {
    printf("The file VpMove.txt could not be opened\n");
    return;
    }
    /*** Read datafile ***/
    while(fscanf(vpfile,"%s",l.old_al)!=EOF)
    {
    fscanf(vpfile,"%s",l.new_al);
    fscanf(vpfile,"%s",l.vp);
    fscanf(vpfile,"%s",l.new_dl);
    i++;
    }
    nl=i-1; /*** undo i++ ***/
    for(i=0;i<=nl;i++)
    {
    printf("Line %d %s\t %s\t %s\t
    %s\n",i,l.old_al,l.new_al,l.vp,l.new_dl);
    }
    fclose(vpfile);
    }

    The VpMove.txt file looks like this:
    003360073 003362061 240 AP-B_LIE_PP01-523
    003360073 003351154 244 AP-B_LIE_PP01-10
    003360073 003351154 243 AP-B_LIE_PP01

    The output is the following:
    Line 0 003360073 003362061 240 AP-B_LIE_PP01-523003360073
    Line 1 003360073 003351154 244 AP-B_LIE_PP01-10
    Line 2 003360073 003351154 243 AP-B_LIE_PP01

    The problem is that when the word ends with a minus sign followed by 3
    digits (see first line) he takes directly the following word: so
    instead of AP-B_LIE_PP01-523 I receive AP-B_LIE_PP01-523003360073.

    Can someone help me on this one?????
    Benedicte, Feb 4, 2004
    #1
    1. Advertising

  2. In article <>,
    Benedicte <> wrote:
    >Hi,
    >
    >I'm getting some problems when using fscanf to read a file.
    >
    >This is a piece of the program code:
    >


    It's great you posted a working program, but please rember to
    also include apropriate headers, e.g.: 'stdio.h' in this case.

    >main ()
    >{
    > /*** Variable declaration ***/
    > FILE *vpfile; /*** Data file ***/
    >
    > struct line
    > {
    > char old_al[10];
    > char new_al[10];
    > char vp[5];
    > char new_dl[17];
    > };
    > struct line l[1000]={0};
    > int i=0;
    > int nl=0; /*** number of lines read ***/
    > int res=0;
    >
    > /*** Executable statements ***/
    > /*** Open VpMove.txt file ***/
    > vpfile=fopen("/export/home/granite/CAPI/prog/bin/VpMove.txt","r");
    > if(vpfile==NULL)
    > {
    > printf("The file VpMove.txt could not be opened\n");
    > return;
    > }
    > /*** Read datafile ***/
    > while(fscanf(vpfile,"%s",l.old_al)!=EOF)
    > {
    > fscanf(vpfile,"%s",l.new_al);
    > fscanf(vpfile,"%s",l.vp);
    > fscanf(vpfile,"%s",l.new_dl);
    > i++;
    > }
    > nl=i-1; /*** undo i++ ***/
    > for(i=0;i<=nl;i++)
    > {
    > printf("Line %d %s\t %s\t %s\t
    >%s\n",i,l.old_al,l.new_al,l.vp,l.new_dl);
    > }
    > fclose(vpfile);
    >}
    >
    >The VpMove.txt file looks like this:
    >003360073 003362061 240 AP-B_LIE_PP01-523
    >003360073 003351154 244 AP-B_LIE_PP01-10
    >003360073 003351154 243 AP-B_LIE_PP01
    >
    >The output is the following:
    >Line 0 003360073 003362061 240 AP-B_LIE_PP01-523003360073
    >Line 1 003360073 003351154 244 AP-B_LIE_PP01-10
    >Line 2 003360073 003351154 243 AP-B_LIE_PP01
    >
    >The problem is that when the word ends with a minus sign followed by 3
    >digits (see first line) he takes directly the following word: so
    >instead of AP-B_LIE_PP01-523 I receive AP-B_LIE_PP01-523003360073.
    >
    >Can someone help me on this one?????


    The problem is that you overflow the character array of 'new_dl' fields.
    This array is 17 characterss big, 'AP-B_LIE_PP01-523' has 17 characters,
    leaving no space for the '\0' (zero terminator) that fscanf(...) wants
    to insert at the end. When you print the value of 'new_dl' you run into
    UB since printf expects a zero terminator to end strings. You might
    find this zero terminator at the first field of the next record, that
    explains the '003360073' part.
    Increase the size of 'new_dl' from 17 to 18 and you'll see it works,
    this is of course by no means a constructive solution.

    Regards,
    --
    Rob van der Leek | rob(at)ricardis(dot)tudelft(dot)nl
    Ricardishof 73-A | http://www.ricardis.tudelft.nl/~rob
    2614 JE Delft, The Netherlands
    +31 (0)6 155 244 60
    Rob van der Leek, Feb 4, 2004
    #2
    1. Advertising

  3. Benedicte wrote:
    >
    > struct line
    > {
    > char old_al[10];
    > char new_al[10];
    > char vp[5];
    > char new_dl[17];
    > };


    So you have allocated 17 charecters for new_dl

    > fscanf(vpfile,"%s",l.new_dl);


    fscanf has wrote 18 charecters to new_dl. So undefined behavior.
    Really it has wrote ending '\0' to the old_al of the second array member.

    > nl=i-1; /*** undo i++ ***/
    > for(i=0;i<=nl;i++)
    > {


    for (i = 0; i < nl; i++)
    is consider to be standart among programmers. So use it insted of
    decreasing nl

    Using scanf is not safe because of buffer overrun as in your example.
    You can use fgets and break the line into tokens by strtok or strpbrk
    If you don't like fgets you can use some thing like:

    char *afgets (char *s, size_t *lenp, FILE *f)
    {
    char *t;
    ptrdiff_t tmp;
    size_t l = 0;

    if (lenp)
    l = *lenp;
    if (!s)
    l = 0;
    if (l == 0) {
    l = 10;
    s = malloc (l);
    }
    t = s;
    for (;;) {
    fgets (t, l, f);
    t += strlen (t) - 1;
    if (*t == '\n' || feof (f))
    break;
    tmp = t - s;
    if ((t = realloc (s, l *= 2)) == NULL) {
    l /= 2;
    break;
    }
    s = t;
    t += tmp;
    }
    if (lenp)
    *lenp = l;
    return s;
    }
    Victor Nazarov, Feb 4, 2004
    #3
  4. Benedicte

    Al Bowers Guest

    Benedicte wrote:
    > Hi,
    >
    > I'm getting some problems when using fscanf to read a file.
    >
    > This is a piece of the program code:

    #include <stdio.h>
    >
    > main ()

    int main(void)

    > {
    > /*** Variable declaration ***/
    > FILE *vpfile; /*** Data file ***/
    >
    > struct line
    > {
    > char old_al[10];
    > char new_al[10];
    > char vp[5];
    > char new_dl[17];
    > };


    You have not made some of the character arrays in the struct large
    enough for the data. Looking at the data you supplied:

    The VpMove.txt file looks like this:
    003360073 003362061 240 AP-B_LIE_PP01-523
    003360073 003351154 244 AP-B_LIE_PP01-10
    003360073 003351154 243 AP-B_LIE_PP01

    The struct, at a minimum should be:

    struct line
    {
    char old_al[11]; /* allows enough for the string ending '\0' char */
    char new_al[11];
    char vp[4];
    char new_dl[18];
    };

    > struct line l[1000]={0};
    > int i=0;
    > int nl=0; /*** number of lines read ***/
    > int res=0;
    >

    What is res used for?

    > /*** Executable statements ***/
    > /*** Open VpMove.txt file ***/
    > vpfile=fopen("/export/home/granite/CAPI/prog/bin/VpMove.txt","r");
    > if(vpfile==NULL)
    > {
    > printf("The file VpMove.txt could not be opened\n");
    > return;


    main returns an int. You could make this:
    return 1;
    > }



    > /*** Read datafile ***/
    > while(fscanf(vpfile,"%s",l.old_al)!=EOF)
    > {
    > fscanf(vpfile,"%s",l.new_al);
    > fscanf(vpfile,"%s",l.vp);
    > fscanf(vpfile,"%s",l.new_dl);
    > i++;
    > }
    > nl=i-1; /*** undo i++ ***/
    > for(i=0;i<=nl;i++)
    > {
    > printf("Line %d %s\t %s\t %s\t
    > %s\n",i,l.old_al,l.new_al,l.vp,l.new_dl);
    > }


    You can modify the above to:

    for(nl = 0; 4 == fscanf(vpfile, " %s %s %s %s ",l[nl].old_al,
    l[nl].new_al, l[nl].vp, l[nl].new_dl) ; nl++) ;
    for(i=0;i < nl;i++)
    printf("Line %d %s\t %s\t %s\t %s\n",
    i,l.old_al,l.new_al,l.vp,l.new_dl);

    > fclose(vpfile);


    return 0;
    > }


    --
    Al Bowers
    Tampa, Fl USA
    mailto: (remove the x to send email)
    http://www.geocities.com/abowers822/
    Al Bowers, Feb 4, 2004
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris Torek
    Replies:
    0
    Views:
    381
    Chris Torek
    Jul 14, 2003
  2. David Rubin
    Replies:
    0
    Views:
    430
    David Rubin
    Jul 14, 2003
  3. fscanf reading lines

    , Mar 8, 2006, in forum: C Programming
    Replies:
    7
    Views:
    845
    Fred Kleinschmidt
    Mar 8, 2006
  4. John
    Replies:
    4
    Views:
    616
    Keith Thompson
    Sep 27, 2006
  5. V.Subramanian, India

    no error by fscanf on reading from output file

    V.Subramanian, India, Oct 30, 2011, in forum: C Programming
    Replies:
    18
    Views:
    564
    Keith Thompson
    Oct 31, 2011
Loading...

Share This Page