atoi()
expects a C 'NUL terminated string' as input, that is, ASCII characters followed by an ASCII zero byte. That's the only way the function knows where to stop converting.
In your first code listing, you read three bytes into a three byte buffer, but you have no control over the byte that follows in memory. I believe that's undefined behavior in C++, so literally anything can happen. Typically, though, if the following byte happens to be a zero or a non-digit, the string will convert properly; if it happens to be a digit, you get a different number when you were expecting.
The proper fix is to use your first example, but:
char peek[4]; // 4 char buffer instead of 3
inf.read(peek, 3);
peek[3] = '\0'; // ensure the 4th char is zero
i = atoi(peek);