Exercise 1-1
See hello.c. Leaving out the whole printf line results in a program that
produces no output. Leaving out the double quotes gives

hello.c: In function `main':
hello.c:5: `hello' undeclared (first use in this function)
hello.c:5: (Each undeclared identifier is reported only once
hello.c:5: for each function it appears in.)
hello.c:5: stray '\' in program
hello.c:5: `world' undeclared (first use in this function)
hello.c:5: parse error before "n"

Leaving out the semicolon gives

hello.c: In function `main':
hello.c:6: parse error before '}' token

Leaving out the #include line doesn't seem to harm anything.

Exercise 1-2
Changing the \n to \a makes a beep when the program is run.

\b makes the program print

hello, worl

\c gives

hello.c:5:16: warning: unknown escape sequence '\c'

\d gives

hello.c:5:16: warning: unknown escape sequence '\d'

\? makes the program print

hello, world?

Exercise 1-3
See fahr.c.

Exercise 1-4
See celsius.c.

Exercise 1-5
See fahr.c.

Exercise 1-6
See getchar.c.

Exercise 1-7
See eof.c.

Exercise 1-8
See countbtn.c.

Exercise 1-9
See catblank.c.

Exercise 1-10
See catescape.c.

Exercise 1-11
Compare its output with that of a known-good wc. Inputs likely to
uncover bugs are zero-length inputs, inputs longer than the maximum
value of an int, and inputs with words that are one character long.

Exercise 1-12
See printlines.c.

Exercise 1-13
See wordlength.c.

Exercise 1-14
See charfreq.c.

Exercise 1-15
See fahrfunc.c

Exercise 1-16
See longest.c. I have chosen to modify getline instead of main.

Exercise 1-17
See 80long.c.

Exercise 1-18
See stripline.c.

Exercise 1-19
See reverse.c.

Exercise 1-20
See detab.c. If n is a variable it will be easy to change it, say by
using a command-line switch. But for this example it will be a symbolic
constant.

Exercise 1-21
See entab.c. A blank should be given preference.

Exercise 1-22
See fold.c.

Exercise 1-23
See uncomment.c.

Exercise 1-24
See syntax.c.

Exercise 2-1
See typerange.c.

Exercise 2-2
for (i=0; i<lim-1; ++i) {
	c = getchar();
	if (c == '\n')
		break;
	if (c == EOF)
		break;
	s[i] = c;
}

Exercise 2-3
See htoi.c.

Exercise 2-4
See squeeze.c.

Exercise 2-5
See any.c.

Exercise 2-6
See bitwise.c.

Exercise 2-7
See bitwise.c.

Exercise 2-8
See bitwise.c.

Exercise 2-9
Subtracting 1 from a number turns the rightmost block of contiguous
zeros to ones, and the rightmost one to a zero. For example, 0101 - 1
gives 0100, and 1000 - 1 gives 0111. ANDing this difference with the
original number leaves the rightmost zeros as they are and makes the
rightmost one a zero. See bitwise.c.

Exercise 2-10
/* lower:  convert c to lower case; ASCII only */
int lower(int c)
{
	return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c;
}

Exercise 3-1
See binsearch.c. The new version is slower by about 15 percent.

Exercise 3-2
See escape.c.

Exercise 3-3
See expand.c.

Exercise 3-4
Because the negative of the largest negative number is itself; if -128
is the largest negative number, -(-128) is -128. The sign of the result
of the modulus operator is machine-dependent for negative operands. See
itoa.c.

Exercise 3-5
See itoa.c.

Exercise 3-6
See itoa.c.

Exercise 4-1
See strindex.c.

Exercise 4-2
See atof.c.

Exercise 4-3
See calc.c.

Exercise 4-4
See calc.c.

Exercise 4-5
See calc.c.

Exercise 4-6
See calc.c.

Exercise 4-7
See calc.c. It should know about buf and bufp.

Exercise 4-8
See calc.c.

Exercise 4-9
ungetc(EOF, ...) in the GNU C Library does nothing. That seems
reasonable. Note that no modifications to getch are needed. See calc.c.

Exercise 4-10
See calc.c.

Exercise 4-11
See calc-several/getop-4-11.c.

Exercise 4-12
See itoa-recursive.c.

Exercise 4-13
See reverse-recursive.c.

Exercise 4-14
#define swap(t, x, y) { t tmp; tmp = x; x = y; y = tmp; }

Exercise 5-1
See getint.c.

Exercise 5-2
See getint.c. getfloat returns int, just like getint.

Exercise 5-3
void strcat(char *s, char *t)
{
	while (*s != '\0')
		s++;
	while ((*s++ = *t++) != '\0')
		;
}

Exercise 5-4
int strend(char *s, char *t)
{
	int ls, lt;

	ls = strlen(s);
	lt = strlen(t);
	if (lt > ls)
		return 0;
	while (*s == *t) {
		if (*s == '\0')
			return 1;
		s++;
		t++;
	}

	return 0;
}

Exercise 5-5
See strn.c.

Exercise 5-6
int getline(char *s, int lim)
{
	char *p;

	p = s;
	while (lim-- >= 0 && (c = getchar()) != EOF) {
		*p++ = c;
		if (c == '\n')
			break;
	}
	*p = '\0';

	return p - s;
}

int atoi(char *s)
{
	int n;

	n = 0;
	while (isdigit(*s)) {
		n = 10 * n + (*s - '\0');
		s++;
	}

	return n;
}

void itoa(int n, char *s)
{
	char *p
	int sign;

	if ((sign = n) < 0)
		n = -n;
	p = s;
	do {
		*p++ = n % 10 + '\0';
	} while ((n /= 10) > 0);
	if (sign < 0)
		*p++ = '-';
	*p = '\0';
	reverse(s);
}

void reverse(char *s)
{
	char *p, c;

	for (p = s; *p != '\0'; p++)
		;
	for (p--; p > s; s++, p--) {
		temp = *s;
		*s = *p;
		*p = temp;
	}
}

int strindex(char *s, char *t)
{
	char *p, *j, *k;

	for (p = s; *p != '\0'; p++) {
		for (j = p, k = t; *k != '\0' && *j == *k; j++, k++)
			;
		if (*k == '\0')
			return p - s;
	}

	return -1;
}

int getop(char *s)
{
	int c;

	while ((*s = c = getch()) == ' ' || c == '\t')
		;
	*++s = '\0';
	if (!isdigit(c) && c != '.')
		return c;
	if (isdigit(c))
		while (isdigit(*s++ = c = getch()))
			;
	if (c == '.')
		while (isdigit(*s++ = c = getch()))
			;
	*s = '\0'
	if (c != EOF)
		ungetch(c);
	return NUMBER;
}

Exercise 5-7
See sort.c. It seems to be about 4% slower.

Exercise 5-8
/* day_of_year:  set day of year from month & day */
int day_of_year(int year, int month, int day)
{
	int i, leap;

	leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
	if (month > 12)
		return -1;
	for (i = 1; i < month; i++)
		day += daytab[leap][i];
	return day;
}

/* month_day:  set month, day from day of year */
void month_day(int year, int yearday, int *pmonth, int *pday)
{
	int i, leap;

	leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
	if (!leap && yearday > 365 || leap && yearday > 366) {
		*pmonth = -1;
		*pday = -1;
		return;
	}
	if (i = 1; yearday > daytab[leap][i]; i++)
		yearday -= daytab[leap][i];
	*pmonth = i;
	*pday = yearday;
}

Exercise 5-9
/* day_of_year:  set day of year from month & day */
int day_of_year(int year, int month, int day)
{
	int i, leap;

	leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
	for (i = 1; i < month; i++)
		day += *(daytab + leap * 13 + i);
	return day;
}

/* month_day:  set month, day from day of year */
void month_day(int year, int yearday, int *pmonth, int *pday)
{
	int i, leap;

	leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
	if (i = 1; yearday > daytab[leap][i]; i++)
		yearday -= *(daytab + leap * 13 + i);
	*pmonth = i;
	*pday = yearday;
}

Exercise 5-10
See expr.c.

Exercise 5-11
See entab-cmd.c and detab-cmd.c.

Exercise 5-12
See entab-cmd.c and detab-cmd.c.

Exercise 5-13
See tail.c.

Exercise 5-14
See sort-ptr.c.

Exercise 5-15
See sort-ptr.c.

Exercise 5-16
See sort-ptr.c.

Exercise 5-17
See sort-field.c. (Try ./sort-field -r -1 -df -2 -n < fields.)

Exercise 5-18
See dcl.c.

Exercise 5-19
See undcl.c.

Exercise 5-20
See dcl.c. It doesn't handle abstract declarators in function argument
types, so you have to have a name for each one.

Exercise 6-1
See keytab.c.

Exercise 6-2
See c-vars.c.

Exercise 6-3
See crossref.c.

Exercise 6-4
See wordfreq.c.

Exercise 6-5
See lookup.c.

Exercise 6-6
See simple-cpp.c.

Exercise 7-1
See case.c. Invoke it as "utol" to convert upper case to lower case, or
as "ltou" to convert lower case to upper case.

Exercise 7-2
See quoted-printable.c.

Exercise 7-3
See minprintf.c.

Exercise 7-4
See minscanf.c.

Exercise 7-5
See calc-scanf.c. It's necessary to use getchar and ungetc instead of
getch and ungetch so chacters are pushed back to the same input stream
scanf reads from.

Exercise 7-6
See simple-diff.c.

Exercise 7-7
See find-cmd.c. The file name should be printed when there are more than
one file given on the command line.

Exercise 7-8
See print.c.

Exercises 7-9
Two possibilities are using relation operators and table lookup. The
table lookup version is only about 3.1% faster. Adding another test to
make sure c is in bounds to the lookup version makes it slower than the
relation version. See isupper.c.

Exercise 8-1
See cat-sys.c.

time dd if=/dev/zero bs=1M count=1 | ./cat > /dev/null
real    0m1.968s
user    0m1.700s
sys     0m0.100s

time dd if=/dev/zero bs=1M count=1 | ./cat-sys > /dev/null
real    0m19.757s
user    0m2.860s
sys     0m16.900s

The version using system calls runs much more slowly, because the input
and output are not buffered and more system calls are made.

Exercise 8-2
See stdio-field.c and stdio-field.h. The two versions do not differ much
in terms of lines of source code. The sizes of the previous object file
and the bit-field object file are 2164 and 2128 bytes, respectively,
when compiled with `gcc -c'.

For execution speed, see test-fields.c and the binaries test-fields-f
and test-fields-b. test-fields-f (the flags version) gets 10000000
characters from /dev/zero in 1.61 seconds. test-fields-b (the bit-fields
version) gets 10000000 characters in 4.09 seconds.

Exercise 8-3

See stdio.c and stdio.h. You can use this library with some of the
programs already written, for example:

gcc -I. cat.c stdio.c

Exercise 8-4
See stdio.c, stdio.h, and fseek-test.c.

Exercise 8-5
See fsize.c. I wasn't able to use the book's dirent.h because of name
conflicts in the system library (sys/dir.h pulls in dirent.h), so I
modified fsize to use the system library.

Exercise 8-6
See malloc.c and malloc-test.c.

Exercise 8-7
See malloc.c and malloc-test.c. What's a "plausible" size? Blocks to be
freed must not be inside of the previous block, and must not extend into
the next block.

Exercise 8-8
See malloc.c and malloc-test.c.
