#include <stdio.h> int main(void) { int i, j, k; float x, y, z; printf("Value of i: %d\n", i); printf("Value of j: %d\n", j); printf("Value of k: %d\n", k); printf("Value of x: %g\n", x); printf("Value of y: %g\n", y); printf("Value of z: %g\n", z); return 0; }
When compiled using GCC and then executed, this program produced the following output:
1 2 3 4 5 6
Value of i: 5618848 Value of j: 0 Value of k: 6844404 Value of x: 3.98979e-34 Value of y: 9.59105e-39 Value of z: 9.59105e-39
The values printed depend on many factors, so the chance that you’ll get exactly these numbers is small.
5. [was #10] (a) is not legal because 100_bottles begins with a digit.
8. [was #12] There are 14 tokens: a, =, (, 3, *, q, -, p, *, p, ), /, 3, and ;.
2. [was #2] Not in C89. Suppose that i is 9 and j is 7. The value of (-i)/j could be either –1 or –2, depending on the implementation. On the other hand, the value of -(i/j) is always –1, regardless of the implementation. In C99, on the other hand, the value of (-i)/j must be equal to the value of -(i/j).
9. [was #6]
(a) 63 8 (b) 3 2 1 (c) 2 -1 3 (d) 0 0 0
13. [was #8] The expression ++i is equivalent to (i += 1). The value of both expressions is i after the increment has been performed.
Answers to Selected Programming Projects
2. [was #4]
#include <stdio.h>
int main(void)
{
int n;
printf(“Enter a three-digit number: “);
scanf(“%d”, &n);
printf(“The reversal is: %d%d%d\n”, n % 10, (n / 10) % 10, n / 100);
return 0;
}
Chapter 5
Answers to Selected Exercises
2. [was #2]
(a) 1 (b) 1 (c) 1 (d) 1
4. [was #4] (i > j) - (i < j)
6. [was #12] Yes, the statement is legal. When n is equal to 5, it does nothing, since 5 is not equal to –9.
10. [was #16] The output is
onetwo
since there are no break statements after the cases.
for (d = 2; d * d <= n; d++) if (n % d == 0) break;
The if statement that follows the loop will need to be modified as well:
1 2 3 4
if (d * d <= n) printf("%d is divisible by %d\n", n, d); else printf("%d is prime\n", n);
14. [was #16] The problem is the semicolon at the end of the first line. If we remove it, the statement is now correct:
1 2
if (n % 2 == 0) printf("n is even\n");
Answers to Selected Programming Projects
2. [was #2]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#include <stdio.h> int main(void) { int m, n, remainder; printf("Enter two integers: "); scanf("%d%d", &m, &n); while (n != 0) { remainder = m % n; m = n; n = remainder; } printf("Greatest common divisor: %d\n", m); return 0; }
#include <stdio.h> int main(void) { float commission, value; printf("Enter value of trade: "); scanf("%f", &value); while (value != 0.0f) { if (value < 2500.00f) commission = 30.00f + .017f * value; else if (value < 6250.00f) commission = 56.00f + .0066f * value; else if (value < 20000.00f) commission = 76.00f + .0034f * value; else if (value < 50000.00f) commission = 100.00f + .0022f * value; else if (value < 500000.00f) commission = 155.00f + .0011f * value; else commission = 255.00f + .0009f * value; if (commission < 39.00f) commission = 39.00f; printf("Commission: $%.2f\n\n", commission); printf("Enter value of trade: "); scanf("%f", &value); } return 0; }
6. [was #6]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#include <stdio.h> int main(void) { int i, n; printf("Enter limit on maximum square: "); scanf("%d", &n); for (i = 2; i * i <= n; i += 2) printf("%d\n", i * i); return 0; }
#include <stdio.h> int main(void) { int i, n, start_day; printf("Enter number of days in month: "); scanf("%d", &n); printf("Enter starting day of the week (1=Sun, 7=Sat): "); scanf("%d", &start_day); /* print any leading "blank dates" */ for (i = 1; i < start_day; i++) printf(" "); /* now print the calendar */ for (i = 1; i <= n; i++) { printf("%3d", i); if ((start_day + i - 1) % 7 == 0) printf("\n"); } return 0; }
Chapter 7
Answers to Selected Exercises
3. [was #4] (b) is not legal.
4. [was #6] (d) is illegal, since printf requires a string, not a character, as its first argument.
10. [was #14] unsignedint, because the (int) cast applies only to j, not j*k.
12. [was #16] The value of i is converted to float and added to f, then the result is converted to double and stored in d.
14. [was #18] No. Converting f to int will fail if the value stored in f exceeds the largest value of type int.
Answers to Selected Programming Projects
1. [was #2] shortint values are usually stored in 16 bits, causing failure at 182. int and longint values are usually stored in 32 bits, with failure occurring at 46341.
#include <stdio.h> int main(void) { int i, n; char ch; printf("This program prints a table of squares.\n"); printf("Enter number of entries in table: "); scanf("%d", &n); ch = getchar(); /* dispose of new-line character following number of entries */ /* could simply be getchar(); */ for (i = 1; i <= n; i++) { printf("%10d%10d\n", i, i * i); if (i % 24 == 0) { printf("Press Enter to continue..."); ch = getchar(); /* or simply getchar(); */ } } return 0; }
#include <ctype.h> #include <stdio.h> int main(void) { int sum = 0; char ch; printf("Enter a word: "); while ((ch = getchar()) != '\n') switch (toupper(ch)) { case 'D': case 'G': sum += 2; break; case 'B': case 'C': case 'M': case 'P': sum += 3; break; case 'F': case 'H': case 'V': case 'W': case 'Y': sum += 4; break; case 'K': sum += 5; break; case 'J': case 'X': sum += 8; break; case 'Q': case 'Z': sum += 10; break; default: sum++; break; } printf("Scrabble value: %d\n", sum); return 0; }
6. [was #12]
1 2 3 4 5 6 7 8 9 10 11 12 13
#include <stdio.h> int main(void) { printf("Size of int: %d\n", (int) sizeof(int)); printf("Size of short: %d\n", (int) sizeof(short)); printf("Size of long: %d\n", (int) sizeof(long)); printf("Size of float: %d\n", (int) sizeof(float)); printf("Size of double: %d\n", (int) sizeof(double)); printf("Size of long double: %d\n", (int) sizeof(long double)); return 0; }
Since the type of a sizeof expression may vary from one implementation to another, it’s necessary in C89 to cast sizeof expressions to a known type before printing them. The sizes of the basic types are small numbers, so it’s safe to cast them to int. (In general, however, it’s best to cast sizeof expressions to unsignedlong and print them using %lu.) In C99, we can avoid the cast by using the %zu conversion specification.
Chapter 8
Answers to Selected Exercises
1. [was #4] The problem with sizeof(a)/sizeof(t) is that it can’t easily be checked for correctness by someone reading the program. (The reader would have to locate the declaration of a and make sure that its elements have type t.)
2. [was #8] To use a digit d (in character form) as a subscript into the array a, we would write a[d-'0']. This assumes that digits have consecutive codes in the underlying character set, which is true of ASCII and other popular character sets.
#include <stdio.h> #define NUM_QUIZZES 5 #define NUM_STUDENTS 5 int main(void) { int grades[NUM_STUDENTS][NUM_QUIZZES]; int high, low, quiz, student, total; for (student = 0; student < NUM_STUDENTS; student++) { printf("Enter grades for student %d: ", student + 1); for (quiz = 0; quiz < NUM_QUIZZES; quiz++) scanf("%d", &grades[student][quiz]); } printf("\nStudent Total Average\n"); for (student = 0; student < NUM_STUDENTS; student++) { printf("%4d ", student + 1); total = 0; for (quiz = 0; quiz < NUM_QUIZZES; quiz++) total += grades[student][quiz]; printf("%3d %3d\n", total, total / NUM_QUIZZES); } printf("\nQuiz Average High Low\n"); for (quiz = 0; quiz < NUM_QUIZZES; quiz++) { printf("%3d ", quiz + 1); total = 0; high = 0; low = 100; for (student = 0; student < NUM_STUDENTS; student++) { total += grades[student][quiz]; if (grades[student][quiz] > high) high = grades[student][quiz]; if (grades[student][quiz] < low) low = grades[student][quiz]; } printf("%3d %3d %3d\n", total / NUM_STUDENTS, high, low); } return 0; }
Chapter 9
Answers to Selected Exercises
2. [was #2]
1 2 3 4
int check(int x, int y, int n) { return (x >= 0 && x <= n - 1 && y >= 0 && y <= n - 1); }
4. [was #4]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
int day_of_year(int month, int day, int year) { int num_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int day_count = 0, i; for (i = 1; i < month; i++) day_count += num_days[i-1]; /* adjust for leap years, assuming they are divisible by 4 */ if (year % 4 == 0 && month > 2) day_count++; return day_count + day; }
Using the expression year%4==0 to test for leap years is not completely correct. Centuries are special cases: if a year is a multiple of 100, then it must also be a multiple of 400 in order to be a leap year. The correct test is
1
year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
6. [was #6; modified]
1 2 3 4 5 6 7 8 9
int digit(int n, int k) { int i; for (i = 1; i < k; i++) n /= 10; return n % 10; }
8. [was #8] (a) and (b) are valid prototypes. (c) is illegal, since it doesn’t specify the type of the parameter. (d) incorrectly specifies that f returns an int value in C89; in C99, omitting the return type is illegal.
10. [was #10]
(a)
1 2 3 4 5 6 7 8 9 10
int largest(int a[], int n) { int i, max = a[0]; for (i = 1; i < n; i++) if (a[i] > max) max = a[i]; return max; }
(b)
1 2 3 4 5 6 7 8 9
int average(int a[], int n) { int i, avg = 0; for (i = 0; i < n; i++) avg += a[i]; return avg / n; }
(c)
1 2 3 4 5 6 7 8 9 10
int num_positive(int a[], int n) { int i, count = 0; for (i = 0; i < n; i++) if (a[i] > 0) count++; return count; }
15. [was #12; modified]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
double median(double x, double y, double z) { double result; if (x <= y) if (y <= z) result = y; else if (x <= z) result = z; else result = x; else { if (z <= y) result = y; else if (x <= z) result = x; else result = z; } return result; }
17. [was #14]
1 2 3 4 5 6 7 8 9
int fact(int n) { int i, result = 1; for (i = 2; i <= n; i++) result *= i; return result; }
19. [was #16] The following program tests the pb function:
#include <stdio.h> void pb(int n); int main(void) { int n; printf("Enter a number: "); scanf("%d", &n); printf("Output of pb: "); pb(n); printf("\n"); return 0; } void pb(int n) { if (n != 0) { pb(n / 2); putchar('0' + n % 2); } }
pb prints the binary representation of the argument n, assuming that n is greater than 0. (We also assume that digits have consecutive codes in the underlying character set.) For example:
1 2
Enter a number: 53 Output of pb: 110101
A trace of pb‘s execution would look like this:
pb(53) finds that 53 is not equal to 0, so it calls pb(26), which finds that 26 is not equal to 0, so it calls pb(13), which finds that 13 is not equal to 0, so it calls pb(6), which finds that 6 is not equal to 0, so it calls pb(3), which finds that 3 is not equal to 0, so it calls pb(1), which finds that 1 is not equal to 0, so it calls pb(0), which finds that 0 is equal to 0, so it returns, causing pb(1) to print 1 and return, causing pb(3) to print 1 and return, causing pb(6) to print 0 and return, causing pb(13) to print 1 and return, causing pb(26) to print 0 and return, causing pb(53) to print 1 and return.
Chapter 10
Answers to Selected Exercises
1. [was #2] (a) a, b, and c are visible. (b) a, and d are visible. (c) a, d, and e are visible. (d) a and f are visible.
#include <stdbool.h> /* C99 only */ #include <stdio.h> #include <stdlib.h> #define NUM_RANKS 13 #define NUM_SUITS 4 #define NUM_CARDS 5 /* external variables */ int num_in_rank[NUM_RANKS]; int num_in_suit[NUM_SUITS]; bool straight, flush, four, three; int pairs; /* can be 0, 1, or 2 */ /* prototypes */ void read_cards(void); void analyze_hand(void); void print_result(void); /********************************************************** * main: Calls read_cards, analyze_hand, and print_result * * repeatedly. * **********************************************************/ int main(void) { for (;;) { read_cards(); analyze_hand(); print_result(); } } /********************************************************** * read_cards: Reads the cards into the external * * variables num_in_rank and num_in_suit; * * checks for bad cards and duplicate cards. * **********************************************************/ void read_cards(void) { bool card_exists[NUM_RANKS][NUM_SUITS]; char ch, rank_ch, suit_ch; int rank, suit; bool bad_card; int cards_read = 0; for (rank = 0; rank < NUM_RANKS; rank++) { num_in_rank[rank] = 0; for (suit = 0; suit < NUM_SUITS; suit++) card_exists[rank][suit] = false; } for (suit = 0; suit < NUM_SUITS; suit++) num_in_suit[suit] = 0; while (cards_read < NUM_CARDS) { bad_card = false; printf("Enter a card: "); rank_ch = getchar(); switch (rank_ch) { case '0': exit(EXIT_SUCCESS); case '2': rank = 0; break; case '3': rank = 1; break; case '4': rank = 2; break; case '5': rank = 3; break; case '6': rank = 4; break; case '7': rank = 5; break; case '8': rank = 6; break; case '9': rank = 7; break; case 't': case 'T': rank = 8; break; case 'j': case 'J': rank = 9; break; case 'q': case 'Q': rank = 10; break; case 'k': case 'K': rank = 11; break; case 'a': case 'A': rank = 12; break; default: bad_card = true; } suit_ch = getchar(); switch (suit_ch) { case 'c': case 'C': suit = 0; break; case 'd': case 'D': suit = 1; break; case 'h': case 'H': suit = 2; break; case 's': case 'S': suit = 3; break; default: bad_card = true; } while ((ch = getchar()) != '\n') if (ch != ' ') bad_card = true; if (bad_card) printf("Bad card; ignored.\n"); else if (card_exists[rank][suit]) printf("Duplicate card; ignored.\n"); else { num_in_rank[rank]++; num_in_suit[suit]++; card_exists[rank][suit] = true; cards_read++; } } } /********************************************************** * analyze_hand: Determines whether the hand contains a * * straight, a flush, four-of-a-kind, * * and/or three-of-a-kind; determines the * * number of pairs; stores the results into * * the external variables straight, flush, * * four, three, and pairs. * **********************************************************/ void analyze_hand(void) { int num_consec = 0; int rank, suit; straight = false; flush = false; four = false; three = false; pairs = 0; /* check for flush */ for (suit = 0; suit < NUM_SUITS; suit++) if (num_in_suit[suit] == NUM_CARDS) flush = true; /* check for straight */ rank = 0; while (num_in_rank[rank] == 0) rank++; for (; rank < NUM_RANKS && num_in_rank[rank] > 0; rank++) num_consec++; if (num_consec == NUM_CARDS) { straight = true; return; } /* check for ace-low straight */ if (num_consec == NUM_CARDS - 1 && num_in_rank[0] > 0 && num_in_rank[NUM_RANKS-1] > 0) { straight = true; return; } /* check for 4-of-a-kind, 3-of-a-kind, and pairs */ for (rank = 0; rank < NUM_RANKS; rank++) { if (num_in_rank[rank] == 4) four = true; if (num_in_rank[rank] == 3) three = true; if (num_in_rank[rank] == 2) pairs++; } } /********************************************************** * print_result: Prints the classification of the hand, * * based on the values of the external * * variables straight, flush, four, three, * * and pairs. * **********************************************************/ void print_result(void) { if (straight && flush) printf("Straight flush"); else if (four) printf("Four of a kind"); else if (three && pairs == 1) printf("Full house"); else if (flush) printf("Flush"); else if (straight) printf("Straight"); else if (three) printf("Three of a kind"); else if (pairs == 2) printf("Two pairs"); else if (pairs == 1) printf("Pair"); else printf("High card"); printf("\n\n"); }
Chapter 11
Answers to Selected Exercises
2. [was #2] (e), (f), and (i) are legal. (a) is illegal because p is a pointer to an integer and i is an integer. (b) is illegal because *p is an integer and &i is a pointer to an integer. (c) is illegal because &p is a pointer to a pointer to an integer and q is a pointer to an integer. (d) is illegal for reasons similar to (c). (g) is illegal because p is a pointer to an integer and *q is an integer. (h) is illegal because *p is an integer and q is a pointer to an integer.
4. [was #4; modified]
1 2 3 4 5 6 7 8
void swap(int *p, int *q) { int temp; temp = *p; *p = *q; *q = temp; }
#include <stdio.h> #define MSG_LEN 80 /* maximum length of message */ int main(void) { char msg[MSG_LEN]; int i; printf("Enter a message: "); for (i = 0; i < MSG_LEN; i++) { msg[i] = getchar(); if (msg[i] == '\n') break; } printf("Reversal is: "); for (i--; i >= 0; i--) putchar(msg[i]); putchar('\n'); return 0; }
#include <stdio.h> #define MSG_LEN 80 /* maximum length of message */ int main(void) { char msg[MSG_LEN], *p; printf("Enter a message: "); for (p = msg; p < msg + MSG_LEN; p++) { *p = getchar(); if (*p == '\n') break; } printf("Reversal is: "); for (p--; p >= msg; p--) putchar(*p); putchar('\n'); return 0; }
Chapter 13
Answers to Selected Exercises
2. [was #2]
(a) Illegal; p is not a character. (b) Legal; output is a. (c) Legal; output is abc. (d) Illegal; *p is not a pointer.
4. [was #4]
(a)
1 2 3 4 5 6 7 8 9 10 11 12
int read_line(char str[], int n) { int ch, i = 0; while ((ch = getchar()) != '\n') if (i == 0 && isspace(ch)) ; /* ignore */ else if (i < n) str[i++] = ch; str[i] = '\0'; return i; }
(b)
1 2 3 4 5 6 7 8 9 10
int read_line(char str[], int n) { int ch, i = 0; while (!isspace(ch = getchar())) if (i < n) str[i++] = ch; str[i] = '\0'; return i; }
(c)
1 2 3 4 5 6 7 8 9 10 11 12
int read_line(char str[], int n) { int ch, i = 0; do { ch = getchar(); if (i < n) str[i++] = ch; } while (ch != '\n'); str[i] = '\0'; return i; }
(d)
1 2 3 4 5 6 7 8 9 10 11 12 13
int read_line(char str[], int n) { int ch, i; for (i = 0; i < n; i++) { ch = getchar(); if (ch == '\n') break; str[i] = ch; } str[i] = '\0'; return i; }
6. [was #6]
1 2 3 4 5 6 7 8
void censor(char s[]) { int i; for (i = 0; s[i] != '\0'; i++) if (s[i] == 'f' && s[i+1] == 'o' && s[i+2] =='o') s[i] = s[i+1] = s[i+2] = 'x'; }
Note that the short-circuit evaluation of && prevents the if statement from testing characters that follow the null character.
8. [was #10] tired-or-wired?
10. [was #12] The value of q is undefined, so the call of strcpy attempts to copy the string pointed to by p into some unknown area of memory. Exercise 2 in Chapter 17 discusses how to write this function correctly.
15. [was #8]
(a) 3 (b) 0 (c) The length of the longest prefix of the string s that consists entirely of characters from the string t. Or, equivalently, the position of the first character in s that is not also in t.
16. [was #16]
1 2 3 4 5 6 7 8 9
int count_spaces(const char *s) { int count = 0; while (*s) if (*s++ == ' ') count++; return count; }
(a) One problem stems from the lack of parentheses around the replacement list. For example, the statement
1
a = 1/AVG(b, c);
will be replaced by
1
a = 1/(b+c)/2;
Even if we add the missing parentheses, though, the macro still has problems, because it needs parentheses around x and y in the replacement list. The preprocessor will turn the statement
1
a = AVG(b<c, c>d);
into
1
a = ((b<c+c>d)/2);
which is equivalent to
1
a = ((b<(c+c)>d)/2);
Here’s the final (corrected) version of the macro:
1
#define AVG(x,y) (((x)+(y))/2)
(b) The problem is the lack of parentheses around the replacement list. For example,
1
a = 1/AREA(b, c);
becomes
1
a = 1/(b)*(c);
Here’s the corrected macro:
1
#define AREA(x,y) ((x)*(y))
5. [was #6]
(a) The call of putchar expands into the following statement:
The character a is less than or equal to s[1] (which is b), yielding a true condition. The character s[2] (which is c) is less than or equal to z, which is also true. The value printed is s[3]-'a'+'A', which is D (assuming that the character set is ASCII).
(b) The character a is not less than or equal to s[1] (which is 1) so the test condition is false. The value printed is s[2], which is 2.
7. [was #8]
(a)
1 2 3 4
long long_max(long x, long y) { return x > y ? x : y; }
The preprocessor would actually put all the tokens on one line, but this version is more readable.
(b) The problem with types such as unsignedlong is that they require two words, which prevents GENERIC_MAX from creating the desired function name. For example, GENERIC_MAX(unsignedlong) would expand into
1 2 3 4
unsigned long unsigned long_max(unsigned long x, unsigned long y) { return x > y ? x : y; }
(c) To make GENERIC_MAX work with any basic type, use a type definition to rename the type:
1
typedef unsigned long ULONG;
We can now write GENERIC_MAX(ULONG).
12. [was #10] (c) and (e) will fail, since M is defined.
14. [was #12; modified] Here’s what the program will look like after preprocessing:
Blank line Blank line Blank line Blank line Blank line Blank line Blank line int main(void) { int a[= 10], i, j, k, m; Blank line i = j; Blank line Blank line Blank line i = 10 * j+1; i = (x,y) x-y(j, k); i = ((((j)*(j)))*(((j)*(j)))); i = (((j)*(j))*(j)); i = jk; puts("i" "j"); Blank line i = SQR(j); Blank line i = (j); return 0; }
Some preprocessors delete white-space characters at the beginning of a line, so your results may vary. Three lines will cause errors when the program is compiled. Two contain syntax errors:
1 2
int a[= 10], i, j, k, m; i = (x,y) x-y(j, k);
The third refers to an undefined variable:
1
i = jk;
Chapter 15
Answers to Selected Exercises
2. [was #2] (b). Function definitions should not be put in a header file. If a function definition appears in a header file that is included by two (or more) source files, the program can’t be linked, since the linker will see two copies of the function.
6. [was #8]
(a) main.c, f1.c, and f2.c. (b) f1.c (assuming that f1.h is not affected by the change). (c) main.c, f1.c, and f2.c, since all three include f1.h. (d) f1.c and f2.c, since both include f2.h.
11. [was #10; modified] The a member will occupy 8 bytes, the union e will take 8 bytes (the largest member, c, is 8 bytes long), and the array f will require 4 bytes, so the total space allocated for s will be 20 bytes.
17. [was #16] All the statements are legal, since C allows integers and enumeration values to be mixed without restriction. Only (a), (d), and (e) are safe. (b) is not meaningful if i has a value other than 0 or 1. (c) will not yield a meaningful result if b has the value 1.
#include <stdio.h> #include "readline.h" #define NAME_LEN 25 #define MAX_PARTS 100 struct part { int number; char name[NAME_LEN+1]; int on_hand; }; int find_part(int number, const struct part inv[], int np); void insert(struct part inv[], int *np); void search(const struct part inv[], int np); void update(struct part inv[], int np); void print(const struct part inv[], int np); /********************************************************** * main: Prompts the user to enter an operation code, * * then calls a function to perform the requested * * action. Repeats until the user enters the * * command 'q'. Prints an error message if the user * * enters an illegal code. * **********************************************************/ int main(void) { char code; struct part inventory[MAX_PARTS]; int num_parts = 0; for (;;) { printf("Enter operation code: "); scanf(" %c", &code); while (getchar() != '\n') /* skips to end of line */ ; switch (code) { case 'i': insert(inventory, &num_parts); break; case 's': search(inventory, num_parts); break; case 'u': update(inventory, num_parts); break; case 'p': print(inventory, num_parts); break; case 'q': return 0; default: printf("Illegal code\n"); } printf("\n"); } } /********************************************************** * find_part: Looks up a part number in the inv array. * * Returns the array index if the part number * * is found; otherwise, returns -1. * **********************************************************/ int find_part(int number, const struct part inv[], int np) { int i; for (i = 0; i < np; i++) if (inv[i].number == number) return i; return -1; } /********************************************************** * insert: Prompts the user for information about a new * * part and then inserts the part into the inv * * array. Prints an error message and returns * * prematurely if the part already exists or the * * array is full. * **********************************************************/ void insert(struct part inv[], int *np) { int part_number; if (*np == MAX_PARTS) { printf("Database is full; can't add more parts.\n"); return; } printf("Enter part number: "); scanf("%d", &part_number); if (find_part(part_number, inv, *np) >= 0) { printf("Part already exists.\n"); return; } inv[*np].number = part_number; printf("Enter part name: "); read_line(inv[*np].name, NAME_LEN); printf("Enter quantity on hand: "); scanf("%d", &inv[*np].on_hand); (*np)++; } /********************************************************** * search: Prompts the user to enter a part number, then * * looks up the part in the inv array. If the * * part exists, prints the name and quantity on * * hand; if not, prints an error message. * **********************************************************/ void search(const struct part inv[], int np) { int i, number; printf("Enter part number: "); scanf("%d", &number); i = find_part(number, inv, np); if (i >= 0) { printf("Part name: %s\n", inv[i].name); printf("Quantity on hand: %d\n", inv[i].on_hand); } else printf("Part not found.\n"); } /********************************************************** * update: Prompts the user to enter a part number. * * Prints an error message if the part can't be * * found in the inv array; otherwise, prompts the * * user to enter change in quantity on hand and * * updates the array. * **********************************************************/ void update(struct part inv[], int np) { int i, number, change; printf("Enter part number: "); scanf("%d", &number); i = find_part(number, inv, np); if (i >= 0) { printf("Enter change in quantity on hand: "); scanf("%d", &change); inv[i].on_hand += change; } else printf("Part not found.\n"); } /********************************************************** * print: Prints a listing of all parts in the inv array, * * showing the part number, part name, and * * quantity on hand. Parts are printed in the * * order in which they were entered into the * * array. * **********************************************************/ void print(const struct part inv[], int np) { int i; printf("Part Number Part Name " "Quantity on Hand\n"); for (i = 0; i < np; i++) printf("%7d %-25s%11d\n", inv[i].number, inv[i].name, inv[i].on_hand); }
5. [was #6] (b) and (c) are legal. (a) is illegal because it tries to reference a member of d without mentioning d. (d) is illegal because it uses -> instead of . to reference the c member of d.
7. [was #8] The first call of free will release the space for the first node in the list, making p a dangling pointer. Executing p=p->next to advance to the next node will have an undefined effect. Here’s a correct way to write the loop, using a temporary pointer that points to the node being deleted:
1 2 3 4 5 6 7 8
struct node *temp; p = first; while (p != NULL) { temp = p; p = p->next; free(temp); }
#include <stdbool.h> /* C99 only */ #include <stdio.h> #include <stdlib.h> #include "stack.h" struct node { int value; struct node *next; }; struct node *top = NULL; void make_empty(void) { struct node *temp; while (top != NULL) { temp = top; top = top->next; free(temp); } } bool is_empty(void) { return top == NULL; } bool push(int i) { struct node *new_node; new_node = malloc(sizeof(struct node)); if (new_node == NULL) return false; new_node->value = i; new_node->next = top; top = new_node; return true; } int pop(void) { struct node *temp; int i; if (is_empty()) { printf("*** Stack underflow; program terminated. ***\n"); exit(EXIT_FAILURE); } i = top->value; temp = top; top = top->next; free(temp); return i; }
15. [was #12] The output of the program is
1
Answer: 3
The program tests the values of f2(0), f2(1), f2(2), and so on, stopping when f2 returns zero. It then prints the argument that was passed to f2 to make it return zero.
17. [was #14] Assuming that compare is the name of the comparison function, the following call of qsort will sort the last 50 elements of a:
#include <stdio.h> #include <stdlib.h> #include "readline.h" #define NAME_LEN 25 #define INITIAL_PARTS 10 struct part { int number; char name[NAME_LEN+1]; int on_hand; }; struct part *inventory; int num_parts = 0; /* number of parts currently stored */ int max_parts = INITIAL_PARTS; /* size of inventory array */ int find_part(int number); void insert(void); void search(void); void update(void); void print(void); /********************************************************** * main: Prompts the user to enter an operation code, * * then calls a function to perform the requested * * action. Repeats until the user enters the * * command 'q'. Prints an error message if the user * * enters an illegal code. * **********************************************************/ int main(void) { char code; inventory = malloc(max_parts * sizeof(struct part)); if (inventory == NULL) { printf("Can't allocate initial inventory space.\n"); exit(EXIT_FAILURE); } for (;;) { printf("Enter operation code: "); scanf(" %c", &code); while (getchar() != '\n') /* skips to end of line */ ; switch (code) { case 'i': insert(); break; case 's': search(); break; case 'u': update(); break; case 'p': print(); break; case 'q': return 0; default: printf("Illegal code\n"); } printf("\n"); } } /********************************************************** * find_part: Looks up a part number in the inventory * * array. Returns the array index if the part * * number is found; otherwise, returns -1. * **********************************************************/ int find_part(int number) { int i; for (i = 0; i < num_parts; i++) if (inventory[i].number == number) return i; return -1; } /********************************************************** * insert: Prompts the user for information about a new * * part and then inserts the part into the * * database. Prints an error message and returns * * prematurely if the part already exists or the * * database is full. * **********************************************************/ void insert(void) { int part_number; struct part *temp; if (num_parts == max_parts) { max_parts *= 2; temp = realloc(inventory, max_parts * sizeof(struct part)); if (temp == NULL) { printf("Insufficient memory; can't add more parts.\n"); return; } inventory = temp; } printf("Enter part number: "); scanf("%d", &part_number); if (find_part(part_number) >= 0) { printf("Part already exists.\n"); return; } inventory[num_parts].number = part_number; printf("Enter part name: "); read_line(inventory[num_parts].name, NAME_LEN); printf("Enter quantity on hand: "); scanf("%d", &inventory[num_parts].on_hand); num_parts++; } /********************************************************** * search: Prompts the user to enter a part number, then * * looks up the part in the database. If the part * * exists, prints the name and quantity on hand; * * if not, prints an error message. * **********************************************************/ void search(void) { int i, number; printf("Enter part number: "); scanf("%d", &number); i = find_part(number); if (i >= 0) { printf("Part name: %s\n", inventory[i].name); printf("Quantity on hand: %d\n", inventory[i].on_hand); } else printf("Part not found.\n"); } /********************************************************** * update: Prompts the user to enter a part number. * * Prints an error message if the part doesn't * * exist; otherwise, prompts the user to enter * * change in quantity on hand and updates the * * database. * **********************************************************/ void update(void) { int i, number, change; printf("Enter part number: "); scanf("%d", &number); i = find_part(number); if (i >= 0) { printf("Enter change in quantity on hand: "); scanf("%d", &change); inventory[i].on_hand += change; } else printf("Part not found.\n"); } /********************************************************** * print: Prints a listing of all parts in the database, * * showing the part number, part name, and * * quantity on hand. Parts are printed in the * * order in which they were entered into the * * database. * **********************************************************/ void print(void) { int i; printf("Part Number Part Name " "Quantity on Hand\n"); for (i = 0; i < num_parts; i++) printf("%7d %-25s%11d\n", inventory[i].number, inventory[i].name, inventory[i].on_hand); }
#include <stdio.h> #include <stdlib.h> #include "readline.h" #define NAME_LEN 25 #define MAX_PARTS 100 struct part { int number; char name[NAME_LEN+1]; int on_hand; } inventory[MAX_PARTS]; int num_parts = 0; /* number of parts currently stored */ int find_part(int number); void insert(void); void search(void); void update(void); void print(void); int compare_parts(const void *p, const void *q); /********************************************************** * main: Prompts the user to enter an operation code, * * then calls a function to perform the requested * * action. Repeats until the user enters the * * command 'q'. Prints an error message if the user * * enters an illegal code. * **********************************************************/ int main(void) { char code; for (;;) { printf("Enter operation code: "); scanf(" %c", &code); while (getchar() != '\n') /* skips to end of line */ ; switch (code) { case 'i': insert(); break; case 's': search(); break; case 'u': update(); break; case 'p': print(); break; case 'q': return 0; default: printf("Illegal code\n"); } printf("\n"); } } /********************************************************** * find_part: Looks up a part number in the inventory * * array. Returns the array index if the part * * number is found; otherwise, returns -1. * **********************************************************/ int find_part(int number) { int i; for (i = 0; i < num_parts; i++) if (inventory[i].number == number) return i; return -1; } /********************************************************** * insert: Prompts the user for information about a new * * part and then inserts the part into the * * database. Prints an error message and returns * * prematurely if the part already exists or the * * database is full. * **********************************************************/ void insert(void) { int part_number; if (num_parts == MAX_PARTS) { printf("Database is full; can't add more parts.\n"); return; } printf("Enter part number: "); scanf("%d", &part_number); if (find_part(part_number) >= 0) { printf("Part already exists.\n"); return; } inventory[num_parts].number = part_number; printf("Enter part name: "); read_line(inventory[num_parts].name, NAME_LEN); printf("Enter quantity on hand: "); scanf("%d", &inventory[num_parts].on_hand); num_parts++; } /********************************************************** * search: Prompts the user to enter a part number, then * * looks up the part in the database. If the part * * exists, prints the name and quantity on hand; * * if not, prints an error message. * **********************************************************/ void search(void) { int i, number; printf("Enter part number: "); scanf("%d", &number); i = find_part(number); if (i >= 0) { printf("Part name: %s\n", inventory[i].name); printf("Quantity on hand: %d\n", inventory[i].on_hand); } else printf("Part not found.\n"); } /********************************************************** * update: Prompts the user to enter a part number. * * Prints an error message if the part doesn't * * exist; otherwise, prompts the user to enter * * change in quantity on hand and updates the * * database. * **********************************************************/ void update(void) { int i, number, change; printf("Enter part number: "); scanf("%d", &number); i = find_part(number); if (i >= 0) { printf("Enter change in quantity on hand: "); scanf("%d", &change); inventory[i].on_hand += change; } else printf("Part not found.\n"); } /********************************************************** * print: Sorts the inventory array by part number, then * * prints a listing of all parts in the database, * * showing the part number, part name, and * * quantity on hand. * **********************************************************/ void print(void) { int i; qsort(inventory, num_parts, sizeof(struct part), compare_parts); printf("Part Number Part Name " "Quantity on Hand\n"); for (i = 0; i < num_parts; i++) printf("%7d %-25s%11d\n", inventory[i].number, inventory[i].name, inventory[i].on_hand); } int compare_parts(const void *p, const void *q) { return ((struct part *) p)->number - ((struct part *) q)->number; }
Chapter 18
Answers to Selected Exercises
2. [was #2]
(a) extern (b) static (c) extern and static (when applied to a local variable)
4. [was #4] If f has never been called previously, the value of f(10) will be 0. If f has been called five times previously, the value of f(10) will be 50, since j is incremented once per call.
8. [was #6; modified]
(a) x is an array of ten pointers to functions. Each function takes an int argument and returns a character. (b) x is a function that returns a pointer to an array of five integers. (c) x is a function with no arguments that returns a pointer to a function with an int argument that returns a pointer to a float value. (d) x is a function with two arguments. The first argument is an integer, and the second is a pointer to a function with an int argument and no return value. x returns a pointer to a function with an int argument and no return value. (Although this example may seem artificially complex, the signal function—part of the standard C library—has exactly this prototype. See p. 632 for a discussion of signal.)
10. [was #8]
(a) char *(*p)(char *); (b) void *f(struct t *p, long int n)(void); (c) void (*a[])(void) = {insert, search, update, print}; (d) struct t (*b[10])(int, int);
13. [was #10] (a), (c), and (d) are legal. (b) is illegal; the initializer for a variable with static storage duration must be a constant expression, and i*i doesn’t qualify.
15. [was #12] (a). Variables with static storage duration are initialized to zero by default; variables with automatic storage duration have no default initial value.
#include <stdio.h> #include <stdlib.h> #include "stack.h" static void terminate(const char *message) { printf("%s\n", message); exit(EXIT_FAILURE); } void make_empty(Stack *s) { while (!is_empty(s)) pop(s); } bool is_empty(const Stack *s) { return *s == NULL; } bool is_full(const Stack *s) { return false; } void push(Stack *s, int i) { struct node *new_node = malloc(sizeof(struct node)); if (new_node == NULL) terminate("Error in push: stack is full."); new_node->data = i; new_node->next = *s; *s = new_node; } int pop(Stack *s) { struct node *old_top; int i; if (is_empty(s)) terminate("Error in pop: stack is empty."); old_top = *s; i = (*s)->data; *s = (*s)->next; free(old_top); return i; }
Chapter 20
Answers to Selected Exercises
2. [was #2] To toggle a bit in a variable i, apply the exclusive-or operator (^) to i and a mask with a 1 bit in the desired position, then store the result back into i. To toggle bit 4, for example, use the statement
#include <stdio.h> unsigned short swap_bytes(unsigned short i); int main(void) { unsigned short i; printf("Enter a hexadecimal number (up to four digits): "); scanf("%hx", &i); printf("Number with bytes swapped: %hx\n", swap_bytes(i)); return 0; } unsigned short swap_bytes(unsigned short i) { unsigned short high_byte = i << 8; unsigned short low_byte = i >> 8; return high_byte | low_byte; }
(b)
1 2 3 4
unsigned short swap_bytes(unsigned short i) { return i << 8 | i >> 8; }
8. [was #8]
(a) The value of ~0 is a number containing all 1 bits. Shifting this number to the left by n places yields a result of the form 1…10…0, where there are n 0 bits. Applying the ~ operator to that number yields a result of the form 0…01…1, where there are n 1 bits.
(b) It returns a bit-field within i of length n starting at position m. Positions are assumed to be numbered starting from the rightmost bit, which is position 0.
14. [was #9]
1 2 3 4 5
struct IEEE_float { unsigned int fraction: 23; /* members may need to be reversed */ unsigned int exponent: 8; unsigned int sign: 1; };
8. [was #8] No. The difference is that "%1s" will store a null character after it reads and stores a nonblank character; " %c" will store only the nonblank character. As a result, the two format strings must be used differently:
1 2 3 4 5 6
char c, s[2]; scanf(" %c", &c); /* stores a nonblank character into c */ scanf("%1s", s); /* stores a nonblank character into s[0] and a null character into s[1] */
10. [was #10] Revise the program’s while loop as follows:
1 2 3 4 5
while ((ch = getc(source_fp)) != EOF) if (putc(ch, dest_fp) == EOF) { fprintf(stderr, "Error during writing; copy terminated\n"); exit(EXIT_FAILURE); }
14. [was #18]
(a)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
char *fget_string(char *s, int n, FILE *stream) { int ch, len = 0; while (len < n - 1) { if ((ch = getc(stream)) == EOF) { if (len == 0 || ferror(stream)) return NULL; break; } s[len++] = ch; if (ch == '\n') break; } s[len] = '\0'; return s; }
(b)
1 2 3 4 5 6 7 8 9 10
int fput_string(const char *s, FILE *stream) { while (*s != '\0') { if (putc(*s, stream) == EOF) return EOF; s++; } return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> #define NAME_LEN 25 struct part { int number; char name[NAME_LEN + 1]; int on_hand; }; int main(int argc, char *argv[]) { FILE *in_fp1, *in_fp2, *out_fp; int num_read1, num_read2; struct part part1, part2; if (argc != 4) { fprintf(stderr, "usage: merge infile1 infile2 outfile\n"); exit(EXIT_FAILURE); } if ((in_fp1 = fopen(argv[1], "rb")) == NULL) { fprintf(stderr, "Can't open %s\n", argv[1]); exit(EXIT_FAILURE); } if ((in_fp2 = fopen(argv[2], "rb")) == NULL) { fprintf(stderr, "Can't open %s\n", argv[2]); exit(EXIT_FAILURE); } if ((out_fp = fopen(argv[3], "wb")) == NULL) { fprintf(stderr, "Can't open %s\n", argv[3]); exit(EXIT_FAILURE); } num_read1 = fread(&part1, sizeof(struct part), 1, in_fp1); num_read2 = fread(&part2, sizeof(struct part), 1, in_fp2); while (num_read1 == 1 && num_read2 == 1) /* successfully read records from both files */ if (part1.number < part2.number) { fwrite(&part1, sizeof(struct part), 1, out_fp); num_read1 = fread(&part1, sizeof(struct part), 1, in_fp1); } else if (part1.number > part2.number) { fwrite(&part2, sizeof(struct part), 1, out_fp); num_read2 = fread(&part2, sizeof(struct part), 1, in_fp2); } else { /* part numbers are equal */ if (strcmp(part1.name, part2.name) != 0) fprintf(stderr, "Names don't match for part %d; using the name %s\n", part1.number, part1.name); part1.on_hand += part2.on_hand; fwrite(&part1, sizeof(struct part), 1, out_fp); num_read1 = fread(&part1, sizeof(struct part), 1, in_fp1); num_read2 = fread(&part2, sizeof(struct part), 1, in_fp2); } /* copy rest of file1 to output file */ while (num_read1 == 1) { fwrite(&part1, sizeof(struct part), 1, out_fp); num_read1 = fread(&part1, sizeof(struct part), 1, in_fp1); } /* copy rest of file2 to output file */ while (num_read2 == 1) { fwrite(&part2, sizeof(struct part), 1, out_fp); num_read2 = fread(&part2, sizeof(struct part), 1, in_fp2); } fclose(in_fp1); fclose(in_fp2); fclose(out_fp); return 0; }
Chapter 23
Answers to Selected Exercises
1. [was #2; modified]
1 2 3 4 5 6 7 8 9
double round_nearest(double x, int n) { double power = pow(10.0, n); if (x < 0.0) return ceil(x * power - 0.5) / power; else return floor(x * power + 0.5) / power; }
6. [was #6]
(a) memmove (b) memmove (we can’t use strcpy because its behavior is undefined when the source of the copy overlaps with the destination) (c) strncpy (d) memcpy
8. [was #8]
1 2 3 4 5 6 7 8 9 10 11 12
int numchar(const char *s, char ch) { int count = 0; s = strchr(s, ch); while (s != NULL) { count++; s = strchr(s + 1, ch); } return count; }
10. [was #10]
1
if (strstr("foo#bar#baz", str) != NULL) …
The assumptions are that str is at least three characters long and doesn’t contain the # character.
int main(void) { char code; for (;;) { setjmp(env); printf("Enter operation code: "); scanf(" %c", &code); while (getchar() != '\n') /* skips to end of line */ ; switch (code) { case 'i': insert(); break; case 's': search(); break; case 'u': update(); break; case 'p': print(); break; case 'q': return 0; default: printf("Illegal code\n"); } printf("\n"); } }
The jmp_buf variable env will need to be global, rather than local to main, so that the function performing the longjmp will be able to supply it as an argument.
Chapter 25
Answers to Selected Exercises
6. [was #4; modified]
1 2 3 4 5 6 7
while ((orig_char = getchar()) != EOF) ??< new_char = orig_char ??' KEY; if (isprint(orig_char) && isprint(new_char)) putchar(new_char); else putchar(orig_char); ??>
#include <locale.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { char *temp, *C_locale; temp = setlocale(LC_ALL, NULL); /* "C" is the current locale by default */ if (temp == NULL) { printf("\"C\" locale information not available\n"); exit(EXIT_FAILURE); } C_locale = malloc(strlen(temp) + 1); if (C_locale == NULL) { printf("Can't allocate space to store locale information\n"); exit(EXIT_FAILURE); } strcpy(C_locale, temp); temp = setlocale(LC_ALL, ""); if (temp == NULL) { printf("Native locale information not available\n"); exit(EXIT_FAILURE); } if (strcmp(temp, C_locale) == 0) printf("Native locale is the same as the \"C\" locale\n"); else printf("Native locale is not the same as the \"C\" locale\n"); return 0; }
void int_printf(const char *format, ...) { va_list ap; const char *p; int digit, i, power, temp; va_start(ap, format); for (p = format; *p != '\0'; p++) { if (*p != '%') { putchar(*p); continue; } if (*++p == 'd') { i = va_arg(ap, int); if (i < 0) { i = -i; putchar('-'); } temp = i; power = 1; while (temp > 9) { temp /= 10; power *= 10; } do { digit = i / power; putchar(digit + '0'); i -= digit * power; power /= 10; } while (i > 0); } } va_end(ap); }
7. [was #4] The statement converts the string that p points to into a long integer, storing the result in value. p is left pointing to the first character not included in the conversion. The base used for the conversion is 10.
#include <stdio.h> #include <stdlib.h> int main(void) { int count = 1000; while (count-- > 0) printf("%d", rand() & 1); printf("\n"); return 0; }
(b) For generating numbers in the range 0 to N-1, the formula rand()/(RAND_MAX/N+1) often gives better results than rand()%N. For example, if N is 2 and RAND_MAX is 32767, the formula works out to rand()/ 16384, which yields 0 if the return value of rand is less than 16384 and 1 if it’s greater than or equal to 16384.