#include <stdio.h> // for getchar(), putchar(), EOF
// copy input to output
int main()
{
int c;
while ((c = getchar()) != EOF)
{putchar(c);}
}
/*
gcc copy.c -o copy
./copy // input from the keyboard
Hello, world! // Enter
Hello, world!
Foo and bar stand for fool and bear. // Enter
Foo and bar stand for fool and bear.
-1 // read as two chars, not as EOF
-1
// Ctrl+D or Ctrl+C in Linux, Ctrl+Z then Enter in Windows (EOF)
./copy < copy.c // redirect input to file
./copy < copy.c > copy2.c // output to another file
gcc copy2.c -o copy2
./copy2
./copy2 < copy2.c
./copy < copy > copy2
./copy2 < copy2.c // still working
rm copy2 copy2.c // clean
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 1-6. Verify that the expression getchar() != EOF is 0 or 1.
#include <stdio.h> // for getchar(), putchar(), printf(), EOF
// test boolean value of getchar() != EOF
// true is 1 or not zero, false is 0
int main()
{
int c;
while ((c = getchar()) != EOF)
{ // print as integer:
if (c != '\n') {printf("%d", c != EOF);}
else {putchar('\n');}
}
printf("%d\n", c != EOF);
}
/*
gcc test.c -o test
./test // input from the keyboard
Hello // Enter (not EOF, but two chars)
11111
-1 // Enter
11
// Ctrl+D in Linux, Ctrl+Z then Enter in Windows (EOF)
0
./test < test.c // redirect input to source file
11...110
./test < test // input binary file
11...110
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 1-7. Write a program to print the value of EOF.
#include <stdio.h> // for putchar(), printf(), EOF
// print the value of EOF, as defined by stdio.h
int main()
{
// putchar(EOF); putchar('\n'); // EOF == -1 is converted to max char 255
// putchar(255); putchar('\n'); // (modulo 2 arithmetic)
printf("EOF = %d\n", EOF); // print as integer
}
/*
gcc -E eof.c // preprocessing
# 5 "eof.c"
int main()
{
printf("EOF = %d\n",
# 9 "eof.c" 3 4
(-1) // EOF macro replaced (expanded)
# 9 "eof.c"
);
gcc eof.c -o eof // compiling
./eof
EOF = -1
*/
putchar(EOF); putchar('\n');
The argument of putchar() is an unsigned char, varying from 0 to 255, see Exercise_2-1.
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
#include <stdio.h> // for getchar(), putchar(), printf(), fflush(),
// stdout, EOF
#include <unistd.h> // for sleep()
#define FALSE 0
#define TRUE 1
int main() // copy input to output, then EOF (EOF is not a char, is not part of input)
{ // when reading past the last char in input, getchar() returns EOF
int c;
while ((c = getchar()) != EOF)
{putchar(c);}
do
{
printf("%d", c); // EOF as int (-1)
fflush(stdout); // flush output buffer
sleep(1); // pause for 1 second
c = getchar(); // get EOF indefinitely
} while (TRUE); // for ever
}
/*
gcc copyEOF.c -o copyEOF
./copyEOF // input from keyboard
Hello! // Enter
Hello!
// Ctrl^D in Linux, Ctrl^Z+Enter in Windows (EOF)
-1-1-1-1-1-1-1-1-1-1^C
// end with Ctrl^C
./copyEOF < copyEOF.c // redirect input to file
// end with Ctrl^C
./copyEOF < copyEOF.c > copyEOF.txt
// wait for 10 seconds, then press Ctrl^C
rm copyEOF.txt // clean
*/
printf("%d", c);
fflush(stdout); // flush output buffer
can be replaced with
printf("%d\n", c); // flush output buffer
and then each -1 is printed on a separate line.
EOF is defined (in stdio.h) as a macro (with value -1):
#define EOF (-1) // on disk, /usr/include/stdio.h
As such, EOF is not a character, whose ASCII values vary between 0 and 255 (see the ASCII_code).
The last character in a text file is usually '\n' (newline) with ASCII value 10 (0xA in hexadecimal). You can verify this by opening a text file with a hexadecimal editor like bless or ghex. In Linux, you can install these programs with the following commands:
sudo apt-get install bless
sudo apt-get install ghex
Alternatively, you can use a text editor like Notepad++ and set it to View --> Show Symbol --> Show All Characters (LF is LineFeed, newline).
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
#include <stdio.h> // for getchar(), printf(), EOF
// count characters in input
int main()
{
long nc = 0;
while (getchar() != EOF)
{nc++;}
printf("%ld\n", nc);
}
/*
gcc count.c -o count
./count // input from keyboard
Hello, guys!
Have a nice day!
// Ctrl+D in Linux, Ctrl+Z then Enter in Windows
30 // 12 + 1 + 16 + 1 // 1 for newline
./count < count.c // source file
434
./count < count // binary file
16744
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
#include <stdio.h> // for getchar(), printf(), EOF
// count characters in input (floating-point version)
int main()
{
double nc; // float nc;
for (nc = 0; getchar() != EOF; nc++)
{}
printf("%.0f\n", nc); // 0 fraction digits
}
/*
gcc countf.c -o countf
./countf // input from keyboard
Hello, guys!
Have a nice day!
// Ctrl+D in Linux, Ctrl+Z then Enter in Windows
30 // 12 + 1 + 16 + 1 // 1 for newline
./countf < countf.c // source file
496
./countf < countf // binary file
16008
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 1-8. Write a program to count blanks, tabs, and newlines.
#include <stdio.h> // for getchar(), printf(), EOF
// count whitespaces
int main()
{
int c;
int blanks = 0, tabs = 0;
int lines = 1; // last line in a file may not end with '\n'
int newlines = 0;
long chars = 0;
while ((c = getchar()) != EOF)
{
chars++;
if (c == ' ') {blanks++;}
if (c == '\t') {tabs++;}
if (c == '\n') {lines++,newlines++;}
}
printf("blanks: %d\n", blanks);
printf("tabs: %d\n", tabs);
printf("lines: %d\n", lines);
printf("newlines: %d\n", newlines);
printf("chars: %ld\n", chars);
}
/*
gcc white.c -o white
./white // input from the keyboard
Hello, you!
What's up?
// Ctrl^D in Linux, Ctrl^Z+Enter for Windows (EOF)
blanks: 2
tabs: 0
lines: 3
newlines: 2
chars: 23 // 11 + 1 + 10 + 1 // 1 for newline
./white < white.c // input source file
blanks: 166
tabs: 0
lines: 51
newlines: 50
chars: 957
./white < white // input binary file
blanks: 53
tabs: 7
lines: 9
newlines: 8
chars: 16744
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 1-9. Write a program to copy its input to its output, replacing each string of one or more blanks by a single blank.
#include <stdio.h> // for getchar(), putchar(), EOF
// trim blanks
int main()
{
int c;
while ((c = getchar()) != EOF)
{
putchar(c);
if (c == ' ')
{
while ((c = getchar()) == ' ') // skip remaining blanks
{} // inner while ends here
if (c == EOF)
{
break; // exit outer while() or:
// putchar('\n'); return 0; // exit main()
} // else
putchar(c); // last non-blank character
}
}
}
/*
gcc trim.c -o trim
./trim // input from the keyboard
Hello! // three blanks replaced with one
Hello!
Hi, guys!
Hi, guys!
Hello, there! // tab is not replaced
Hello, there!
Hi, there! // three blanks replaced with one
Hi, there!
// Ctrl^D in Linux, Ctrl^Z+Enter in Windows (EOF)
./trim < trim.c // input from source file
./trim < trim // input from binary file
./trim < trim.c > trim2.c // output to trim2.c
gcc trim2.c -o trim2
./trim2
./trim2 < trim2.c
./trim < trim > trim2
./trim2
./trim2 < trim2.c // still working
rm trim2 trim2.c // clean
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 1-10. Write a program to copy its input to its output, replacing each tab by \t, each backspace by \b, and each backslash by \\. This makes tabs and backspaces visible in an unambiguous way.
#include <stdio.h> // for getchar(), putchar(), EOF
// replace tab by \t, backspace by \b and backslash by \\
int main()
{
int c;
while((c = getchar()) != EOF)
{
if (c == '\t') {putchar('\\');putchar('t');}
else if (c == '\b') {putchar('\\');putchar('b');}
else if (c == '\\') {putchar('\\');putchar('\\');}
else {putchar(c);}
}
}
/*
gcc visible.c -o visible
./visible // input from keyboard
Hello!
Hello!\t
What's up\?
\tWhat's up\\?
// Ctrl^D in Linux, Ctrl^Z+Enter in Windows (EOF)
./visible < visible.c // input from source file
./visible < visible // input from binary file
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
#include <stdio.h> // for getchar(), printf(), EOF
#define IN 1
#define OUT 0
// counts chars, words, and lines
int main()
{
int c;
long nc = 0;
int nw = 0;
int nl = 1; // last line in a file ends with "EOF," not '\n'
int state = OUT;
while ((c = getchar()) != EOF)
{
nc++;
if (c == ' ' || c == '\t') {state = OUT;}
else if (c == '\n')
{
nl++;
state = OUT;
}
else if (state == OUT) // not whitespace
{
state = IN;
nw++;
}
// else c is not whitespace and state == IN
}
printf("chars:\t%ld\n", nc);
printf("words:\t%d\n", nw);
printf("lines:\t%d\n", nl);
}
/*
gcc words.c -o words
./words // input from keyboard
Hello!
What's up?
// Ctrl^D in Linux, Ctrl^Z+Enter in Windows (EOF)
chars: 18
words: 3
lines: 3
./words < words.c // input from source file
chars: 967
words: 170
lines: 58
./words < words // input from binary file
chars: 16744
words: 64
lines: 7
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 1-11. How would you test the word count program? What kinds of input are most likely to uncover bugs if there are any?
We have made nc a long (and can also be a float or double), as in K&R, p. 18. If there are very many short words in input, we can also make nw a long or float.
There are other whitespaces that can separate words, like '\f', '\r', '\v' (see Whitespace_character on Wikipedia). These can be added to the test if (c == ' ' || c == '\t') .
We can test for boundary conditions, like an empty file, a file with only whitespace, with only one big word, a binary file, etc. (see Exercise_1-11 on clc-wiki-kr).
#include <stdio.h> // for getchar(), printf(), EOF
#define IN 1
#define OUT 0
// counts chars, words, and lines
int main()
{
int c;
long nc = 0;
int nw = 0;
int nl = 1; // last line in a file ends with EOF, not '\n'
int state = OUT;
while ((c = getchar()) != EOF)
{
nc++;
if (c == ' ' || c == '\t' || c == '\f' || c == '\r' || c == '\v')
{state = OUT;}
else if (c == '\n')
{
nl++;
state = OUT;
}
else if (state == OUT) // not whitespace
{
state = IN;
nw++;
}
// else c is not whitespace and state == IN
}
printf("chars:\t%ld\n", nc);
printf("words:\t%d\n", nw);
printf("lines:\t%d\n", nl);
}
/*
gcc wordtest.c -o wordtest
./wordtest // input from keyboard
Hello!
What's up?
// Ctrl^D in Linux, Ctrl^Z+Enter in Windows (EOF)
chars: 18
words: 3
lines: 3
./wordtest < wordtest.c // input from source file
chars: 1025
words: 182
lines: 58
./wordtest < wordtest // input from binary file
chars: 16008
words: 77
lines: 6
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 1-12. Write a program that prints its input one word per line.
#include <stdio.h> // for getchar(), putchar(), EOF
#define IN 1
#define OUT 0
// prints one word per line
int main()
{
int c;
int state = OUT;
while ((c = getchar()) != EOF)
{
if (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v')
{
if (state == IN) // previous word
{
putchar('\n');
state = OUT;
}
}
else // not whitespace
{
if (state == OUT) {state = IN;}
putchar(c);
}
}
}
/*
gcc prnwln.c -o prnwln
./prnwln // input from keyboard
Hello, guys!
Hello,
guys!
How are you today?
How
are
you
today?
// Ctrl+D in Linux, Ctrl+Z then Enter in Windows (EOF)
./prnwln < prnwln.c // input from source file
./prnwln < prnwln // input from binary file
*/