tags:

views:

309

answers:

2

I'm doing a hw assignment and my professor uses this code to test our program:

int main()
{
   const int SZ1 = 10;
   const int SZ2 = 7;
   const int SZ3 = 5;
   float array1[SZ1];
   float array2[SZ2];
   float array3[SZ3];

   DisplayValues(SortValues(GetValues(array1, SZ1), SZ1), SZ1);
   DisplayValues(SortValues(GetValues(array2, SZ2), SZ2), SZ2);
   DisplayValues(SortValues(GetValues(array3, SZ3), SZ3), SZ3);

   return EXIT_SUCCESS;
}

float *DisplayValues(float *p, size_t n)
{
   float previous = *p, *ptr, *end = p + n;

   setiosflags(ios_base::fixed);
   for (ptr = p; ptr < end; ++ptr)  // get each element
   {
      cout << *ptr << '\n';
      if (ptr != p)                 // if not first element...
      {
         if (previous < *ptr)       // ...check sort order
         {
            cerr << "Error - Array sorted incorrectly\n";
            return NULL;
         }
      }
      previous = *ptr;              // save this element
   }
   resetiosflags(ios_base::fixed);

   return p;
}
#endif

I use

float *GetValues(float *p, size_t n) 
{   
    float input;
    float *start = p;

    cout << "Enter " << n << " float values separated by whitespace: \n";

    while (scanf("%f", &input) == 1) {
        *p++ = input;
    }
    return start;
}

to get input from the terminal window as he instructed, and use ctrl + d to input an EOF character in order for the first call to DisplayValues(SortValues(GetValues(array1, SZ1), SZ1), SZ1) to happen. However, the rest of the program just finishes without letting me enter values again when DisplayValues(SortValues(GetValues(array2, SZ2), SZ2), SZ2); is called. Is there a reason or workaround for this? Thanks.

A: 

The problem is with using EOF as your delimiter. scanf will read in the EOF, before it can acquire the next float it wants. scanf will return EOF to tell you what it has found, but the EOF won't leave the buffer, so the next time you call scanf, it will still read EOF and return immediately. See: scanf

In your GetValues function, since you have the size of the array, you should just read in numbers until you have that many floats, instead of waiting for an EOF. That way you prevent an overflow as well as improperly using EOF.

bobDevil
+3  A: 

The CTRLD character (hex 04) is not an end of file character per se. Pressing that key sequence will signal to the terminal driver that this is the end of the input stream and any further reads from that stream will be treated as if the "file" is finished. In fact you can change the character used for this with the stty command under UNIX.

What will happen when you press that sequence is that no further input will be given to the program. You need to find a more intelligent sequence to delimit your data (like, for example, newline (0x10)).

But this will require you to input strings rather than floats (you can use fgets to get a string and sscanf to extract a float after you've checked for an empty line).

Another possibility is to use -1 as a special sentinel value (assuming -1 isn't a valid input) but watch out for floating point comparisons, they're sometimes not what you expect.

My suggestion is to go the fgets/sscanf route but, since you're required to get n floats, your GetValues should go something like this:

float *GetValues (float *p, size_t n) {   
    float input;
    float *start = p;
    cout << "Enter " << n << " float values separated by whitespace: \n";
    while (scanf("%f", &input) == 1) {
        *p++ = input;
        if (--n >= 0)
            break;
    }
    return start;
}

which will stop getting values once you've reached your limit. Keep in mind that's not perfect. I've left at least one problem there due to the fact that it's homework (you may never strike it, depending on your input data).

I should also mention it's somewhat unusual to mix C++ and C I/O semantics (cout and scanf) - you really should choose one or the other. If this is a C++ assignment, you'll find that C++ has a richer way of doing I/O. If it's C, then cout has no place in the code and you should probably use printf. I'm not saying it won't work, just that it's an unusual mix.

paxdiablo