strange behavior

Discussion in 'C Programming' started by Marlene Stebbins, Apr 23, 2004.

  1. Something very strange is going on here. I don't know if it's a C
    problem or an implementation problem. The program reads data from
    a file and loads it into two arrays. When xy, x, y, *xlist and
    *ylist are ints or floats there is no apparent problem. If these
    variables are doubles, the program crashes. Furthermore, the
    crashes occur only when xlist and ylist are free()ed. When the
    above variables are doubles and the calls to free() are
    eliminated, the program doesn't crash, but the output is weird.

    If there is anyone out there with enough time on his hands to
    compile this code and play with it, I would appreciate getting
    your opinion. Don't forget to change the format specifiers in the
    calls to fscanf() when changing types. Here are data for the
    input file:

    0 12 5 12 8 9 11 3 10 -2 5 -8 0 -10 -7 -1 -7 12

    /* Read xy data from a file.
    Load x&y values into respective arrays.
    Works with ints, floats, but not doubles???
    */
    #include <stdio.h>
    #include <stdlib.h>

    int main(void)
    {
    double xy, x, y;
    double *xlist, *ylist;
    int xct, yct, xycount, idx;
    FILE *data;

    if((data = fopen("vertices.txt", "r")) == NULL)
    {
    fprintf(stderr, "can't open data file\n");
    exit(EXIT_FAILURE);
    }
    xycount = 0;
    while(fscanf(data, "%lf") == 1)
    xycount++;
    if(xycount%2 != 0)
    {
    fprintf(stderr, "unequal number of x,y values\n");
    exit(EXIT_FAILURE);
    }
    xlist = calloc(xycount/2, sizeof(xlist));
    ylist = calloc(xycount/2, sizeof(ylist));
    rewind(data);
    xct = 0;
    yct = 0;
    while(fscanf(data, "%lf %lf", &x, &y) == 2)
    {
    xlist[xct++] = x;
    ylist[yct++] = y;
    }
    fclose(data);

    for(idx = 0; idx < xycount/2; ++idx)
    printf("%4.f", xlist[idx]);
    putchar('\n');
    for(idx = 0; idx < xycount/2; ++idx)
    printf("%4.f", ylist[idx]);
    putchar('\n');

    free(xlist);
    free(ylist);

    return 0;
    }
     
    Marlene Stebbins, Apr 23, 2004
    #1
    1. Advertising

  2. Marlene Stebbins <> spoke thus:

    > while(fscanf(data, "%lf") == 1)

    ^
    Where is the float you're reading going? If this is your actual code,
    no wonder it crashes. If you want to ignore some input, use

    fscanf( data, "%*lf" ); /* legal */

    I have no idea whether that's the root of the behavior you describe,
    but it's definitely a problem.

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
     
    Christopher Benson-Manica, Apr 23, 2004
    #2
    1. Advertising

  3. Marlene Stebbins

    Neil Cerutti Guest

    In article <>, Marlene Stebbins wrote:
    > Something very strange is going on here.>
    >
    > xlist = calloc(xycount/2, sizeof(xlist));
    > ylist = calloc(xycount/2, sizeof(ylist));


    You want

    xlist = calloc(xycount/2, sizeof *xlist);
    ylist = calloc(xycount/2, sizeof *ylist);

    The reason that other types of lists work is a coincedence of,
    e.g., sizeof xlist and sizeof *xlist.

    --
    Neil Cerutti
    "Do you wanna see 'em?"
    "See what?"
    "The corpses. They're in the basement." --_Return of the Living Dead_.
     
    Neil Cerutti, Apr 23, 2004
    #3
  4. Christopher Benson-Manica wrote:
    > Marlene Stebbins <> spoke thus:
    >
    >
    >> while(fscanf(data, "%lf") == 1)

    >
    > ^
    > Where is the float you're reading going? If this is your actual code,
    > no wonder it crashes. If you want to ignore some input, use
    >
    > fscanf( data, "%*lf" ); /* legal */
    >
    > I have no idea whether that's the root of the behavior you describe,
    > but it's definitely a problem.
    >


    OK, thanks. Doesn't affect the strange behavior though.

    Marlene
     
    Marlene Stebbins, Apr 23, 2004
    #4
  5. Marlene Stebbins

    Kevin Bagust Guest

    In article <>,
    Marlene Stebbins <> wrote:
    > xlist = calloc(xycount/2, sizeof(xlist));
    > ylist = calloc(xycount/2, sizeof(ylist));


    These two lines should be:
    xlist = calloc( xycount/2, sizeof( *xlist ));
    ylist = calloc( xycount/2, sizeof( *ylist ));

    Because without dereferencing xlist or ylist you are getting enough
    memory for pointers to the type, rather that for the type it self.

    From your description I would guess that the size of a pointer is larger
    or equal to the size of an int or a float. Where as the size of a pointer
    is smaller than the size of a double, so with double you were over
    writing other memory and so getting strange results and crashes.

    Kevin.
     
    Kevin Bagust, Apr 23, 2004
    #5
  6. Christopher Benson-Manica <> wrote in
    news:c6bicu$r9k$:

    > Marlene Stebbins <> spoke thus:
    >
    >> while(fscanf(data, "%lf") == 1)

    > ^
    > Where is the float you're reading going? If this is your
    > actual code, no wonder it crashes. If you want to ignore some
    > input, use
    >
    > fscanf( data, "%*lf" ); /* legal */


    But useless when trying to test the number of input items
    assigned as in the OP's program.

    Better:
    while (fscanf(data, "%lf", &xy) == 1)

    > I have no idea whether that's the root of the behavior you
    > describe, but it's definitely a problem.


    Later on in program there is another problem:

    >> xlist = calloc(xycount/2, sizeof(xlist));
    >> ylist = calloc(xycount/2, sizeof(ylist));


    We do not need space for some pointers but for doubles, i.e.
    sizeof(*xlist).

    Ralf
     
    Ralf Damaschke, Apr 23, 2004
    #6
  7. Neil Cerutti wrote:
    > In article <>, Marlene Stebbins wrote:
    >
    >>Something very strange is going on here.>
    >>
    >> xlist = calloc(xycount/2, sizeof(xlist));
    >> ylist = calloc(xycount/2, sizeof(ylist));

    >
    >
    > You want
    >
    > xlist = calloc(xycount/2, sizeof *xlist);
    > ylist = calloc(xycount/2, sizeof *ylist);
    >
    > The reason that other types of lists work is a coincedence of,
    > e.g., sizeof xlist and sizeof *xlist.
    >


    Nice try. Still crashing after this change. :-(
     
    Marlene Stebbins, Apr 23, 2004
    #7
  8. Ralf Damaschke wrote:
    >>If you want to ignore some
    >>input, use
    >>
    >>fscanf( data, "%*lf" ); /* legal */

    >
    >
    > But useless when trying to test the number of input items
    > assigned as in the OP's program.
    >
    > Better:
    > while (fscanf(data, "%lf", &xy) == 1)
    >
    > Later on in program there is another problem:
    >
    >
    >>> xlist = calloc(xycount/2, sizeof(xlist));
    >>> ylist = calloc(xycount/2, sizeof(ylist));

    >>

    >
    > We do not need space for some pointers but for doubles, i.e.
    > sizeof(*xlist).


    Thank you Ralf. These two changes fix the problem. Actually, I had

    while (fscanf(data, "%lf", &xy) == 1)

    originally, and changed it, thinking it inefficient. Live and learn.

    Marlene
     
    Marlene Stebbins, Apr 23, 2004
    #8
  9. On Fri, 23 Apr 2004, Marlene Stebbins wrote:

    > Something very strange is going on here. I don't know if it's a C
    > problem or an implementation problem. The program reads data from
    > a file and loads it into two arrays. When xy, x, y, *xlist and
    > *ylist are ints or floats there is no apparent problem. If these
    > variables are doubles, the program crashes. Furthermore, the
    > crashes occur only when xlist and ylist are free()ed. When the
    > above variables are doubles and the calls to free() are
    > eliminated, the program doesn't crash, but the output is weird.
    >
    > If there is anyone out there with enough time on his hands to
    > compile this code and play with it, I would appreciate getting
    > your opinion. Don't forget to change the format specifiers in the
    > calls to fscanf() when changing types. Here are data for the
    > input file:
    >
    > 0 12 5 12 8 9 11 3 10 -2 5 -8 0 -10 -7 -1 -7 12
    >
    > /* Read xy data from a file.
    > Load x&y values into respective arrays.
    > Works with ints, floats, but not doubles???
    > */
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > int main(void)
    > {
    > double xy, x, y;
    > double *xlist, *ylist;
    > int xct, yct, xycount, idx;
    > FILE *data;
    >
    > if((data = fopen("vertices.txt", "r")) == NULL)
    > {
    > fprintf(stderr, "can't open data file\n");
    > exit(EXIT_FAILURE);
    > }
    > xycount = 0;
    > while(fscanf(data, "%lf") == 1)
    > xycount++;


    Where are you storing the data that fscanf is reading it? This could cause
    a program to crash. I'd use:

    while(fscanf(data, "%lf", &xy) == 1)
    xycount++;

    > if(xycount%2 != 0)
    > {
    > fprintf(stderr, "unequal number of x,y values\n");
    > exit(EXIT_FAILURE);
    > }
    > xlist = calloc(xycount/2, sizeof(xlist));
    > ylist = calloc(xycount/2, sizeof(ylist));


    Obviously the /2 is okay. You want to store half the list in xlist and the
    other half in ylist. The problem here is that sizeof(xlist) is the size of
    a pointer to double. You want the size of a double or sizeof(*xlist). Same
    thing for ylist.

    > rewind(data);
    > xct = 0;
    > yct = 0;
    > while(fscanf(data, "%lf %lf", &x, &y) == 2)
    > {
    > xlist[xct++] = x;
    > ylist[yct++] = y;
    > }
    > fclose(data);
    >
    > for(idx = 0; idx < xycount/2; ++idx)
    > printf("%4.f", xlist[idx]);
    > putchar('\n');
    > for(idx = 0; idx < xycount/2; ++idx)
    > printf("%4.f", ylist[idx]);
    > putchar('\n');


    Just as a side note, a good compiler will do this for you but I'm in the
    habit of taking things like xycount/2 and replacing them with another
    variable. In a for loop, like above, this is a chance division will occur
    on each iteration of the loop. That could have a notble impact.

    > free(xlist);
    > free(ylist);
    >
    > return 0;
    > }
    >
    >
    >
    >


    --
    Send e-mail to: darrell at cs dot toronto dot edu
    Don't send e-mail to
     
    Darrell Grainger, Apr 23, 2004
    #9
  10. Marlene Stebbins wrote:

    > Something very strange is going on here. I don't know if it's a C
    > problem or an implementation problem. The program reads data from a file
    > and loads it into two arrays. When xy, x, y, *xlist and *ylist are ints
    > or floats there is no apparent problem.


    The problem is obvious, but may not be apparent to you. Your program
    relies on sizeof(pointer-to-T) being equal to sizeof(T). You were
    unlucky to have not seen this before because, it seems, your
    implementation does have
    sizeof(*int) == sizeof(int)
    and
    sizeof(*float) == sizeof(float)
    but
    sizeof(*double) != sizeof(double)
    I'll bet
    sizeof(*char) != sizeof(char)
    and probably that
    !(sizeof(*short) == sizeof(short) && sizeof(*long) == sizeof(long))


    > If these variables are doubles,
    > the program crashes.

    [...]
    > double *xlist, *ylist;

    [...]
    > while(fscanf(data, "%lf") == 1)


    Could it be because the above has insufficient arguments for the format?

    > xlist = calloc(xycount/2, sizeof(xlist));
    > ylist = calloc(xycount/2, sizeof(ylist));


    Or because the above makes no sense?

    With these three lines corrected, the program below at least seems to
    work properly:


    /* Read xy data from a file.
    Load x&y values into respective arrays.
    Works with ints, floats, but not doubles???
    */
    #include <stdio.h>
    #include <stdlib.h>

    int main(void)
    {
    double xy, x, y;
    double *xlist, *ylist;
    int xct, yct, xycount, idx;
    FILE *data;

    if ((data = fopen("vertices.txt", "r")) == NULL) {
    fprintf(stderr, "can't open data file\n");
    exit(EXIT_FAILURE);
    }
    xycount = 0;
    while (fscanf(data, "%lf", &xy) == 1)
    xycount++;
    if (xycount % 2 != 0) {
    fprintf(stderr, "unequal number of x,y values\n");
    exit(EXIT_FAILURE);
    }
    if (!(xlist = malloc(xycount / 2 * sizeof *xlist))) {
    fprintf(stderr, "allocation failed for xlist, giving up\n");
    exit(EXIT_FAILURE);
    }
    if (!(ylist = malloc(xycount / 2 * sizeof *ylist))) {
    fprintf(stderr, "allocation failed for ylist, giving up\n");
    free(xlist);
    exit(EXIT_FAILURE);
    }
    rewind(data);
    xct = 0;
    yct = 0;
    while (fscanf(data, "%lf %lf", &x, &y) == 2) {
    xlist[xct++] = x;
    ylist[yct++] = y;
    }
    fclose(data);

    for (idx = 0; idx < xycount / 2; ++idx)
    printf("%4.f", xlist[idx]);
    putchar('\n');
    for (idx = 0; idx < xycount / 2; ++idx)
    printf("%4.f", ylist[idx]);
    putchar('\n');

    free(xlist);
    free(ylist);

    return 0;
    }
     
    Martin Ambuhl, Apr 24, 2004
    #10
  11. Martin Ambuhl wrote:

    > The problem is obvious, but may not be apparent to you. Your program
    > relies on sizeof(pointer-to-T) being equal to sizeof(T).


    Here is a subtle issue that I was unaware of. It's never cropped
    up in any C instruction or book that I have seen (or I missed it
    if it did). I've learned something important.

    Thanks,
    Marlene
     
    Marlene Stebbins, Apr 24, 2004
    #11
  12. Marlene Stebbins <> writes:
    > Martin Ambuhl wrote:
    > > The problem is obvious, but may not be apparent to you. Your
    > > program relies on sizeof(pointer-to-T) being equal to sizeof(T).

    >
    > Here is a subtle issue that I was unaware of. It's never cropped up in
    > any C instruction or book that I have seen (or I missed it if it
    > did). I've learned something important.


    It's pretty obvious once you think about it. It's common (though not
    required) for all pointers to be the same size, typically 32 or 64
    bits. Imagine that type T is some large struct, several kilobytes in
    size. No matter how big or small T is, a pointer-to-T is still going
    to be only 32 or 64 bits (or whatever the size of a pointer is on your
    platform).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    Schroedinger does Shakespeare: "To be *and* not to be"
     
    Keith Thompson, Apr 24, 2004
    #12
    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. sstark
    Replies:
    0
    Views:
    462
    sstark
    Mar 6, 2005
  2. ryang
    Replies:
    1
    Views:
    944
    Wes Groleau
    Apr 11, 2005
  3. Apogee

    Strange Behavior with ViewState

    Apogee, Jul 3, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    326
    Apogee
    Jul 3, 2003
  4. PJ

    DropDownList Strange Behavior

    PJ, Jul 8, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    354
  5. Mantorok Redgormor
    Replies:
    70
    Views:
    1,763
    Dan Pop
    Feb 17, 2004
Loading...

Share This Page