|
When I run this, I expect to see Got here
... , and then see a Seg Fault message. Here's what
I get instead:
~/$ ./prog Segmentation fault (core dumped) Q: What happened to the "Got here" message? |
|
When I run this, I expect to see a *, then one second
later see another *, then one second later see another *,
and so on until 10 *'s are printed. Q: Instead, I see nothing for 10 whole seconds, then all at once I see 10 *'s. What's happening? |
The answer in both cases is I/O bufferring is happening. When you write things with cout, the characters you write are "bufferred", that means stored temporarily until either enough have been collected to make writing to the screen worthwhile, or some event has occurred to cause the less-than-full buffer to be written to the screen despite having unused capacity. Such events include:
#include <iostream>
#include <unistd.h>
using namespace std;
int main()
{
for(int i = 0; i < 10; i++)
{
cout << '*' << flush;
sleep(1);
}
cout << endl;
return 0;
}
Reading from unformatted input: cin.get()
and eof
x
with the statement
cin >> x;
cin
skips over leading whitespace in the input stream,
meaning it skips over newline characters ('\n'
), tabs
('\t'
), and spaces (' '
). This is a bit of a
problem if you want to do something like count the number of lines in a
file. You can read input a char
at a time without skipping
over whitespace using cin.get()
, and you can read from
ifstream
object fin
a char
at a
time without skipping over whitespace using fin.get()
.
So, suppose you wanted to read in a line of text from the user and print out how many characters were in the line, you'd write this:
#include <iostream>
using namespace std;
int main()
{
int count = 0;
for(char c = cin.get(); c != '\n'; c = cin.get())
count++;
cout << "There were " << count << " characters!" << endl;
return 0;
}
Suppose fin
is an ifstream
object that you're
reading from (remember to include fstream
if you want to read
and write with files). You can test whether or not you've come to the
end of the file with the expression fin.eof()
which
evaluates to true if you have tried to read beyond the end of the
file, and false otherwise.
So if you wanted to write a program to count the number of characters in
the file Input.txt
, you'd do something like this:
source code | Input.txt | output |
| hello |
0:104(h) 1:101(e) 2:108(l) 3:108(l) 4:111(o) 5:10( ) There were 6 characters! |
The behavior fin.eof()
is somewhat complex: it will return true
when some previous read action failed because the end of file has been
reached. In other words,
fin.eof()
will return false! If you try to read one more
time, then fin.eof()
will return true.
~/$ ./prob1
Problem p4 is hardest (ave = 48.5294%)
Check out this solution.
$ ./prog
#. # # # # #\ /#
# # # # # # # #\_/#
# `# # #===# # # #
# `# # # # #
Here is the solution.
A further challenge is to print out "NAVY" twice on the same line, like this:
$ ./prog
#. # # # # #\ /# #. # # # # #\ /#
# # # # # # # #\_/# # # # # # # # #\_/#
# `# # #===# # # # # `# # #===# # # #
# `# # # # # # `# # # # #
Why is this interesting? Because the challenge here is to
design the right "print" function. We can't print a whole
letter at once now, because printing, for example, the first "N"
requires newlines, and that would mess up printing the
subsequent letters. Part of the Art of Programming is to make
good choices about what functions to make, and exactly what they
should do.
If you're feeling really adventurous, I have a file alphabet.txt in the same format, but with all the letters of the alphabet. You could write a program that takes a message from the user and prints it out in the big letters. Something like this:
~/$ ./prog Enter message (all lower-case, no spaces): beatarmy ######\ ####### # ####### # ###### #\ /# #\ /# #_____/ #____ # # # # # # # # # # # #\_/# # \ # #===# # #===# ###### # * # # ######/ ####### # # # # # # # # # #