read() function output

read() is an unformatted Input function.

Please consider the following program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>         /// cin, cout

using namespace std;


void read()
{
    char buf[80];

    cout << "Please enter at least 5 chars: ";

    cin.read(buf, 5);

    if (cin)
    {
        cout << "cin.read() successfully read "
             << cin.gcount() << " characters: ";

        /// Append the null terminator.
///     buf[5] = '0';

        cout << buf << endl;
    }
    else
        cout << "cin.read() was unsuccessful" << endl;
}


int main()
{
    for (int i = 0; i < 4; i++)
       read();
}


https://ideone.com/dzb7ic


I have setup the following input buffer:

abcde
abcd
abcdef



The program output is:


Please enter at least 5 chars: cin.read() successfully read 5 characters: abcde*
Please enter at least 5 chars: cin.read() successfully read 5 characters: 
abcd*
Please enter at least 5 chars: cin.read() successfully read 5 characters: 
abcd*
Please enter at least 5 chars: cin.read() was unsuccessful


I have the following queries:
1) For the 3rd read() function execution, the I/P buffer was abcdef. Yet the O/P shows abcd*. It should have been abcde*, since 5 characters are being read. Why is this happening?
2) We are told that read() doesn't append a terminator. Why is the * displayed then? Is that because of the cout << statement?

Thanks.
> It should have been abcde*, since 5 characters are being read. Why is this happening?

The input
abcde
abcd
abcdef

consists of the following sequence of 17 characters, with the marker || placed after every five characters:

'a'  'b'  'c'  'd'  'e'  ||  '\n'  'a'  'b'  'c'  'd'  ||  '\n'  'a'  'b'  'c'  'd'  ||  'e'  'f'

Each new line counts as one character.



> We are told that read() doesn't append a terminator. Why is the * displayed then?

There is undefined behaviour; the array is uninitialised and need not hold a null terminated byte string.
Initialise the array on line 8: char buf[80] {} ; // initialise to all zeroes
Are you leaving '\n' in the input buffer each time? That would upset your calculations.

Also, when you cout a char* , you get everything until the first zero is hit. So you could get 5kb of data dumped out, and then a crash. You could get 10 characters. You don't know what you're going to get, so if you want to know for sure, you should do something about that so that you only see the characters written into it, rather than whatever random junk happens to be in the memory.

Also, I expect that the memory used for the char buf[80]; is the exact same memory each time, so you'll see anything you wrote in there previously there again, unless you overwrite it. This is another way to make it difficult to see what's going on.

I suggest that you fill the buffer with zeros at the start of your read function.
Yes, this is the correct explanation.

I've tried the following version and the results are fine:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>         /// cin, cout

using namespace std;


void read()
{
    char buf[80] {};

    cout << "Please enter at least 5 chars: ";

    cin.read(buf, 5);

    if (cin)
    {
        cout << "cin.read() successfully read "
             << cin.gcount() << " characters: ";

        cout << buf << endl;

        cout << "next char: " << (char) cin.peek()
             << endl;
    }
    else
        cout << "cin.read() was unsuccessful" << endl;
}


int main()
{
    for (int i = 0; i < 4; i++)
       read();
}


https://ideone.com/P2ffXf

I've put in a diagnostic message that uses cin's peek() function. This function returns an ASCII value which is cast to a char. The diagnostic shows what the next character in the buffer is.

I had also tried to discard the '\n' using:

 
    cin.ignore(1, '\n');


However, the results weren't good. Hence, I used the peek(), which shows what's happening behind the scenes.
Registered users can post here. Sign in or register to post.