strange behavior

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Marlene Stebbins

    #1

    strange behavior

    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_FAILU RE);
    }
    xycount = 0;
    while(fscanf(da ta, "%lf") == 1)
    xycount++;
    if(xycount%2 != 0)
    {
    fprintf(stderr, "unequal number of x,y values\n");
    exit(EXIT_FAILU RE);
    }
    xlist = calloc(xycount/2, sizeof(xlist));
    ylist = calloc(xycount/2, sizeof(ylist));
    rewind(data);
    xct = 0;
    yct = 0;
    while(fscanf(da ta, "%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;
    }



  • Christopher Benson-Manica

    #2
    Re: strange behavior

    Marlene Stebbins <stebbins@email .com> spoke thus:
    [color=blue]
    > while(fscanf(da ta, "%lf") == 1)[/color]
    ^
    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)cybers pace.org | don't, I need to know. Flames welcome.

    Comment

    • Neil Cerutti

      #3
      Re: strange behavior

      In article <40894820.20808 05@email.com>, Marlene Stebbins wrote:[color=blue]
      > Something very strange is going on here.>
      >
      > xlist = calloc(xycount/2, sizeof(xlist));
      > ylist = calloc(xycount/2, sizeof(ylist));[/color]

      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_.

      Comment

      • Marlene Stebbins

        #4
        Re: strange behavior

        Christopher Benson-Manica wrote:[color=blue]
        > Marlene Stebbins <stebbins@email .com> spoke thus:
        >
        >[color=green]
        >> while(fscanf(da ta, "%lf") == 1)[/color]
        >
        > ^
        > 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.
        >[/color]

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

        Marlene



        Comment

        • Ralf Damaschke

          #5
          Re: strange behavior

          Christopher Benson-Manica <ataru@nospam.c yberspace.org> wrote in
          news:c6bicu$r9k $1@chessie.cirr .com:
          [color=blue]
          > Marlene Stebbins <stebbins@email .com> spoke thus:
          >[color=green]
          >> while(fscanf(da ta, "%lf") == 1)[/color]
          > ^
          > 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 */[/color]

          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)
          [color=blue]
          > I have no idea whether that's the root of the behavior you
          > describe, but it's definitely a problem.[/color]

          Later on in program there is another problem:
          [color=blue][color=green]
          >> xlist = calloc(xycount/2, sizeof(xlist));
          >> ylist = calloc(xycount/2, sizeof(ylist));[/color][/color]

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

          Ralf

          Comment

          • Marlene Stebbins

            #6
            Re: strange behavior

            Neil Cerutti wrote:[color=blue]
            > In article <40894820.20808 05@email.com>, Marlene Stebbins wrote:
            >[color=green]
            >>Something very strange is going on here.>
            >>
            >> xlist = calloc(xycount/2, sizeof(xlist));
            >> ylist = calloc(xycount/2, sizeof(ylist));[/color]
            >
            >
            > 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.
            >[/color]

            Nice try. Still crashing after this change. :-(

            Comment

            • Kevin Bagust

              #7
              Re: strange behavior

              In article <40894820.20808 05@email.com>,
              Marlene Stebbins <stebbins@email .com> wrote:[color=blue]
              > xlist = calloc(xycount/2, sizeof(xlist));
              > ylist = calloc(xycount/2, sizeof(ylist));[/color]

              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.

              Comment

              • Marlene Stebbins

                #8
                Re: strange behavior

                Ralf Damaschke wrote:[color=blue][color=green]
                >>If you want to ignore some
                >>input, use
                >>
                >>fscanf( data, "%*lf" ); /* legal */[/color]
                >
                >
                > 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:
                >
                >[color=green][color=darkred]
                >>> xlist = calloc(xycount/2, sizeof(xlist));
                >>> ylist = calloc(xycount/2, sizeof(ylist));[/color]
                >>[/color]
                >
                > We do not need space for some pointers but for doubles, i.e.
                > sizeof(*xlist).[/color]

                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








                Comment

                • Darrell Grainger

                  #9
                  Re: strange behavior

                  On Fri, 23 Apr 2004, Marlene Stebbins wrote:
                  [color=blue]
                  > 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_FAILU RE);
                  > }
                  > xycount = 0;
                  > while(fscanf(da ta, "%lf") == 1)
                  > xycount++;[/color]

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

                  while(fscanf(da ta, "%lf", &xy) == 1)
                  xycount++;
                  [color=blue]
                  > if(xycount%2 != 0)
                  > {
                  > fprintf(stderr, "unequal number of x,y values\n");
                  > exit(EXIT_FAILU RE);
                  > }
                  > xlist = calloc(xycount/2, sizeof(xlist));
                  > ylist = calloc(xycount/2, sizeof(ylist));[/color]

                  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.
                  [color=blue]
                  > rewind(data);
                  > xct = 0;
                  > yct = 0;
                  > while(fscanf(da ta, "%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');[/color]

                  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.
                  [color=blue]
                  > free(xlist);
                  > free(ylist);
                  >
                  > return 0;
                  > }
                  >
                  >
                  >
                  >[/color]

                  --
                  Send e-mail to: darrell at cs dot toronto dot edu
                  Don't send e-mail to vice.president@ whitehouse.gov

                  Comment

                  • Martin Ambuhl

                    #10
                    Re: strange behavior

                    Marlene Stebbins wrote:
                    [color=blue]
                    > 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.[/color]

                    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))

                    [color=blue]
                    > If these variables are doubles,
                    > the program crashes.[/color]
                    [...][color=blue]
                    > double *xlist, *ylist;[/color]
                    [...][color=blue]
                    > while(fscanf(da ta, "%lf") == 1)[/color]

                    Could it be because the above has insufficient arguments for the format?
                    [color=blue]
                    > xlist = calloc(xycount/2, sizeof(xlist));
                    > ylist = calloc(xycount/2, sizeof(ylist));[/color]

                    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_FAILU RE);
                    }
                    xycount = 0;
                    while (fscanf(data, "%lf", &xy) == 1)
                    xycount++;
                    if (xycount % 2 != 0) {
                    fprintf(stderr, "unequal number of x,y values\n");
                    exit(EXIT_FAILU RE);
                    }
                    if (!(xlist = malloc(xycount / 2 * sizeof *xlist))) {
                    fprintf(stderr, "allocation failed for xlist, giving up\n");
                    exit(EXIT_FAILU RE);
                    }
                    if (!(ylist = malloc(xycount / 2 * sizeof *ylist))) {
                    fprintf(stderr, "allocation failed for ylist, giving up\n");
                    free(xlist);
                    exit(EXIT_FAILU RE);
                    }
                    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;
                    }



                    Comment

                    • Marlene Stebbins

                      #11
                      Re: strange behavior

                      Martin Ambuhl wrote:
                      [color=blue]
                      > The problem is obvious, but may not be apparent to you. Your program
                      > relies on sizeof(pointer-to-T) being equal to sizeof(T).[/color]

                      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

                      Comment

                      • Keith Thompson

                        #12
                        Re: strange behavior

                        Marlene Stebbins <stebbins@email .com> writes:[color=blue]
                        > Martin Ambuhl wrote:[color=green]
                        > > The problem is obvious, but may not be apparent to you. Your
                        > > program relies on sizeof(pointer-to-T) being equal to sizeof(T).[/color]
                        >
                        > 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.[/color]

                        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_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
                        San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
                        Schroedinger does Shakespeare: "To be *and* not to be"

                        Comment

                        Working...