17.1
修改16.3节的程序inventory.c,使其可以对数组inventory进行动态内存分配,并且在以后填满时重新进行内存分配。初始使用malloc为拥有10个part结构的数组分配足够的内存空间。当数组没有足够的空间给新的零件时,使用realloc函数来使内存数量加倍。在每次数组变满时重复加倍操作步骤。
/*********************************************************
* From C PROGRAMMING: A MODERN APPROACH, Second Edition *
* By K. N. King *
* Copyright (c) 2008, 1996 W. W. Norton & Company, Inc. *
* All rights reserved. *
* This program may be freely distributed for class use, *
* provided that this copyright notice is retained. *
*********************************************************/
/* inventory.c (Chapter 16, page 391) */
/* Maintains a parts database (array version) */
/* NB: This program has been modified from its original source */
#include <stdio.h>
#include <stdlib.h> /* malloc etc, exit */
#include "readline.h"
#define NAME_LEN 25
struct part {
int number;
char name[NAME_LEN+1];
int on_hand;
} *inventory;
int max_parts = 10;
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);
/**********************************************************
* 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;
if ((inventory = malloc(max_parts * sizeof(struct part))) == NULL) {
printf("Error: malloc failed\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");
}
return 0;
}
/**********************************************************
* 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) {
if ((inventory = realloc(inventory, sizeof(struct part) * (max_parts *= 2)))
== NULL)
{
printf("Error: realloc failed\n");
exit(EXIT_FAILURE);
}
}
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);
}
17.2
修改16.3节的程序inventory.c,使得p命令在显示零件前调用qsort对inventory数组排序。
inventory.c
/********************************************************* * From C PROGRAMMING: A MODERN APPROACH, Second Edition * * By K. N. King * * Copyright (c) 2008, 1996 W. W. Norton & Company, Inc. * * All rights reserved. * * This program may be freely distributed for class use, * * provided that this copyright notice is retained. * *********************************************************/ /* inventory.c (Chapter 16, page 391) */ /* Maintains a parts database (array version) */ /* NB: This program has been modified from its original source */ #include <stdio.h> #include <stdlib.h> /* malloc etc, exit */ #include "readline.h" #include "quicksort.h" #include "inventory.h" int max_parts = 10; 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; if ((inventory = malloc(max_parts * sizeof(struct part))) == NULL) { printf("Error: malloc failed\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"); } return 0; } /********************************************************** * 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) { if ((inventory = realloc(inventory, sizeof(struct part) * (max_parts *= 2))) == NULL) { printf("Error: realloc failed\n"); exit(EXIT_FAILURE); } } 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; 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); } /********************************************************** * compare_parts: Acts as the comparison function for * * qsort, to sort by part, ascending. * **********************************************************/ int compare_parts(const void *p, const void *q) { return ((struct part *)p)->number - ((struct part *)q)->number; }
inventory.h
#ifndef INVENTORY_H #define INVENTORY_H #define NAME_LEN 25 struct part { int number; char name[NAME_LEN+1]; int on_hand; } *inventory; #endif
17.3
修改17.5节的程序inventory2.c,增加一个e命令(擦除)以允许用户从数据库中删除一个零件。
/********************************************************* * From C PROGRAMMING: A MODERN APPROACH, Second Edition * * By K. N. King * * Copyright (c) 2008, 1996 W. W. Norton & Company, Inc. * * All rights reserved. * * This program may be freely distributed for class use, * * provided that this copyright notice is retained. * *********************************************************/ /* inventory2.c (Chapter 17, page 434) */ /* Maintains a parts database (linked list version) */ /* NB: This file has been altered from its original source */ #include <stdio.h> #include <stdlib.h> #include "readline.h" #define NAME_LEN 25 struct part { int number; char name[NAME_LEN+1]; int on_hand; struct part *next; }; struct part *inventory = NULL; /* points to first part */ struct part *find_part(int number); void insert(void); void search(void); void update(void); void print(void); void erase(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; for (;;) { printf("Enter operation code: "); scanf(" %c", &code); while (getchar() != '\n') /* skips to end of line */ ; switch (code) { case 'i': insert(); break; case 'e': erase(); 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 * * list. Returns a pointer to the node * * containing the part number; if the part * * number is not found, returns NULL. * **********************************************************/ struct part *find_part(int number) { struct part *p; for (p = inventory; p != NULL && number > p->number; p = p->next) ; if (p != NULL && number == p->number) return p; return NULL; } /********************************************************** * insert: Prompts the user for information about a new * * part and then inserts the part into the * * inventory list; the list remains sorted by * * part number. Prints an error message and * * returns prematurely if the part already exists * * or space could not be allocated for the part. * **********************************************************/ void insert(void) { struct part *cur, *prev, *new_node; new_node = malloc(sizeof(struct part)); if (new_node == NULL) { printf("Database is full; can't add more parts.\n"); return; } printf("Enter part number: "); scanf("%d", &new_node->number); for (cur = inventory, prev = NULL; cur != NULL && new_node->number > cur->number; prev = cur, cur = cur->next) ; if (cur != NULL && new_node->number == cur->number) { printf("Part already exists.\n"); free(new_node); return; } printf("Enter part name: "); read_line(new_node->name, NAME_LEN); printf("Enter quantity on hand: "); scanf("%d", &new_node->on_hand); new_node->next = cur; if (prev == NULL) inventory = new_node; else prev->next = new_node; } /********************************************************** * erase: Prompts the user to enter a part number, then * * attempts to erase that part from the database. * * If the part doesn't exist, prints an error * * message. * **********************************************************/ void erase(void) { struct part **pp = &inventory; struct part *temp; int n; printf("Enter part number: "); scanf("%d", &n); while(*pp) { if ((*pp)->number == n) { temp = *pp; *pp = (*pp)->next; free(temp); return; } pp = &(*pp)->next; } printf("Part number %d not found in database\n", n); return; } /********************************************************** * 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 number; struct part *p; printf("Enter part number: "); scanf("%d", &number); p = find_part(number); if (p != NULL) { printf("Part name: %s\n", p->name); printf("Quantity on hand: %d\n", p->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 number, change; struct part *p; printf("Enter part number: "); scanf("%d", &number); p = find_part(number); if (p != NULL) { printf("Enter change in quantity on hand: "); scanf("%d", &change); p->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. Part numbers will appear in * * ascending order. * **********************************************************/ void print(void) { struct part *p; printf("Part Number Part Name " "Quantity on Hand\n"); for (p = inventory; p != NULL; p = p->next) printf("%7d %-25s%11d\n", p->number, p->name, p->on_hand); }
17.4
修改15.3节的程序justify,重新编写line.c文件使其存储链表中的当前行。链表中的每个结点存储一个单词。用一个指向包含第一个单词的结点的指针变量来替换原有的line数组,当行为空时该变量存储空指针。
justify.c
/********************************************************* * From C PROGRAMMING: A MODERN APPROACH, Second Edition * * By K. N. King * * Copyright (c) 2008, 1996 W. W. Norton & Company, Inc. * * All rights reserved. * * This program may be freely distributed for class use, * * provided that this copyright notice is retained. * *********************************************************/ /* justify.c (Chapter 15, page 363) */ /* Formats a file of text */ #include <string.h> #include "line.h" #include "word.h" #define MAX_WORD_LEN 20 int main(void) { char word[MAX_WORD_LEN+2]; int word_len; clear_line(); for (;;) { read_word(word, MAX_WORD_LEN+1); word_len = strlen(word); if (word_len == 0) { flush_line(); return 0; } if (word_len > MAX_WORD_LEN) word[MAX_WORD_LEN] = '*'; if (word_len + 1 > space_remaining()) { write_line(); clear_line(); } add_word(word); } }
line.c
/********************************************************* * From C PROGRAMMING: A MODERN APPROACH, Second Edition * * By K. N. King * * Copyright (c) 2008, 1996 W. W. Norton & Company, Inc. * * All rights reserved. * * This program may be freely distributed for class use, * * provided that this copyright notice is retained. * *********************************************************/ /* line.c (Chapter 15, page 364) */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include "line.h" #define MAX_LINE_LEN 60 int line_len = 0; int num_words = 0; struct node { struct node *next; char word[]; } *line = NULL; void clear_line(void) { struct node *temp; while (line != NULL) { temp = line; line = line->next; free(temp); } line_len = 0; num_words = 0; } void add_word(const char *word) { struct node *new_word, **pp = &line; if ((new_word = malloc(sizeof(struct node) + strlen(word) + 1)) == NULL) { printf("Error: malloc failed\n"); exit(EXIT_FAILURE); } strcpy(new_word->word, word); new_word->next = NULL; while (*pp != NULL) pp = &(*pp)->next; *pp = new_word; line_len += strlen(word); if (num_words > 0) line_len++; /* add a space for every word except the first */ num_words++; } int space_remaining(void) { return MAX_LINE_LEN - line_len; } void write_line(void) { int extra_spaces, spaces_to_insert, i; int char_count = 0; struct node *entry = line; extra_spaces = space_remaining(); while (char_count < line_len && entry != NULL) { printf("%s", entry->word); if (num_words > 1) { spaces_to_insert = extra_spaces / (num_words - 1); for (i = 1; i <= spaces_to_insert + 1; i++) putchar(' '); extra_spaces -= spaces_to_insert; } char_count += strlen(entry->word) + 1; num_words--; entry = entry->next; } putchar('\n'); } void flush_line(void) { int i; struct node *entry = line; if (line_len > 0) { for (i = 0; entry != NULL; i++, entry = entry->next) { if (i > 0 && entry->next != NULL) putchar(' '); printf("%s ", entry->word); } } printf("\n"); clear_line(); }
line.h
/********************************************************* * From C PROGRAMMING: A MODERN APPROACH, Second Edition * * By K. N. King * * Copyright (c) 2008, 1996 W. W. Norton & Company, Inc. * * All rights reserved. * * This program may be freely distributed for class use, * * provided that this copyright notice is retained. * *********************************************************/ /* line.h (Chapter 15, page 362) */ #ifndef LINE_H #define LINE_H /********************************************************** * clear_line: Clears the current line. * **********************************************************/ void clear_line(void); /********************************************************** * add_word: Adds word to the end of the current line. * * If this is not the first word on the line, * * puts one space before word. * **********************************************************/ void add_word(const char *word); /********************************************************** * space_remaining: Returns the number of characters left * * in the current line. * **********************************************************/ int space_remaining(void); /********************************************************** * write_line: Writes the current line with * * justification. * **********************************************************/ void write_line(void); /********************************************************** * flush_line: Writes the current line without * * justification. If the line is empty, does * * nothing. * **********************************************************/ void flush_line(void); #endif
word.c
/********************************************************* * From C PROGRAMMING: A MODERN APPROACH, Second Edition * * By K. N. King * * Copyright (c) 2008, 1996 W. W. Norton & Company, Inc. * * All rights reserved. * * This program may be freely distributed for class use, * * provided that this copyright notice is retained. * *********************************************************/ /* word.c (Chapter 15, page 363) */ #include <stdio.h> #include "word.h" int read_char(void) { int ch = getchar(); if (ch == '\n' || ch == '\t') return ' '; return ch; } void read_word(char *word, int len) { int ch, pos = 0; while ((ch = read_char()) == ' ') ; while (ch != ' ' && ch != EOF) { if (pos < len) word[pos++] = ch; ch = read_char(); } word[pos] = '\0'; }
word.h
/********************************************************* * From C PROGRAMMING: A MODERN APPROACH, Second Edition * * By K. N. King * * Copyright (c) 2008, 1996 W. W. Norton & Company, Inc. * * All rights reserved. * * This program may be freely distributed for class use, * * provided that this copyright notice is retained. * *********************************************************/ /* word.h (Chapter 15, page 361) */ #ifndef WORD_H #define WORD_H /********************************************************** * read_word: Reads the next word from the input and * * stores it in word. Makes word empty if no * * word could be read because of end-of-file. * * Truncates the word if its length exceeds * * len. * **********************************************************/ void read_word(char *word, int len); #endif
17.5
编写程序对用户输入的一系列单词排序:
Enter word: foo
Enter word: bar
Enter word: baz
Enter word: quux
Enter word:
In sorted order: bar baz foo quux
假设每个单词不超过20个字符。当用户输入空单词(即敲击回车键而没有录入任何单词)时停止读取。把每个单词存储在一个动态分配的字符串中,像remind2.c程序(17.2节)那样用一个指针数组来跟踪这些字符串。读完所有的单词后对数组排序(可以使用任何排序算法),然后用一个循环按存储顺序显示这些单词。提示:像remind2.c那样,使用read_line函数读取每个单词。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define WORD_LEN 20
int compare_words(const void *w1, const void *w2);
void *my_malloc(size_t bytes);
int main(void)
{
char **words = NULL, *word = NULL;
int i, size = 1, num_words = 0;
words = (char **) my_malloc((size_t)sizeof(char *));
for (i = 0; ; i++) {
word = (char *) my_malloc((size_t)WORD_LEN + 1);
printf("Enter a word: ");
fgets(word, WORD_LEN + 1, stdin);
if (word[strlen(word) - 1] == '\n')
word[strlen(word) - 1] = '\0';
if (word[0] == '\0')
break;
*(words + i) = word;
num_words++;
if (size == num_words) {
if ((words = (char **) realloc(words,
(size_t)sizeof(char *) * (size *= 2))) == NULL)
{
printf("Error: realloc failed\n");
exit(EXIT_FAILURE);
}
}
}
qsort(words, num_words, sizeof(char *), compare_words);
printf("\nIn sorted order: ");
for (i = 0; i < num_words; i++)
printf("%s ", *(words + i));
printf("\n");
}
void *my_malloc(size_t bytes)
{
void *p;
if ((p = malloc(bytes)) == NULL) {
printf("Error: malloc failed\n");
exit(EXIT_FAILURE);
}
return p;
}
int compare_words(const void *w1, const void *w2)
{
return strcmp(*(char **)w1, *(char **)w2);
}
17.6
修改编程题5,用qsort对指针数组排序。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define WORD_LEN 20
int compare_words(const void *w1, const void *w2);
void *my_malloc(size_t bytes);
int main(void)
{
char **words = NULL, *word = NULL;
int i, size = 1, num_words = 0;
words = (char **) my_malloc((size_t)sizeof(char *));
for (i = 0; ; i++) {
word = (char *) my_malloc((size_t)WORD_LEN + 1);
printf("Enter a word: ");
fgets(word, WORD_LEN + 1, stdin);
if (word[strlen(word) - 1] == '\n')
word[strlen(word) - 1] = '\0';
if (word[0] == '\0')
break;
*(words + i) = word;
num_words++;
if (size == num_words) {
if ((words = (char **) realloc(words,
(size_t)sizeof(char *) * (size *= 2))) == NULL)
{
printf("Error: realloc failed\n");
exit(EXIT_FAILURE);
}
}
}
qsort(words, num_words, sizeof(char *), compare_words);
printf("\nIn sorted order: ");
for (i = 0; i < num_words; i++)
printf("%s ", *(words + i));
printf("\n");
}
void *my_malloc(size_t bytes)
{
void *p;
if ((p = malloc(bytes)) == NULL) {
printf("Error: malloc failed\n");
exit(EXIT_FAILURE);
}
return p;
}
int compare_words(const void *w1, const void *w2)
{
return strcmp(*(char **)w1, *(char **)w2);
}
17.7
修改17.2节的remind2.c程序,使得reminders数组中的每个元素都是指向vstring结构(见17.9节)的指针,而不是指向普通字符串的指针。
/*********************************************************
* From C PROGRAMMING: A MODERN APPROACH, Second Edition *
* By K. N. King *
* Copyright (c) 2008, 1996 W. W. Norton & Company, Inc. *
* All rights reserved. *
* This program may be freely distributed for class use, *
* provided that this copyright notice is retained. *
*********************************************************/
/* remind2.c (Chapter 17, page 418) */
/* Prints a one-month reminder list (dynamic string version) */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_REMIND 50 /* maximum number of reminders */
#define MSG_LEN 60 /* max length of reminder message */
struct vstring {
int len;
char chars[];
};
int read_line(char str[], int n);
int main(void)
{
struct vstring *reminders[MAX_REMIND];
char day_str[3], msg_str[MSG_LEN+1];
int day, i, j, num_remind = 0;
for (;;) {
if (num_remind == MAX_REMIND) {
printf("-- No space left --\n");
break;
}
printf("Enter day and reminder: ");
scanf("%2d", &day);
if (day == 0)
break;
sprintf(day_str, "%2d", day);
read_line(msg_str, MSG_LEN);
for (i = 0; i < num_remind; i++)
if (strcmp(day_str, reminders[i]->chars) < 0)
break;
for (j = num_remind; j > i; j--)
reminders[j] = reminders[j-1];
reminders[i] = malloc(sizeof(struct vstring) + 2 + strlen(msg_str) + 1);
if (reminders[i] == NULL) {
printf("-- No space left --\n");
break;
}
strcpy(reminders[i]->chars, day_str);
strcat(reminders[i]->chars, msg_str);
reminders[i]->len = strlen(reminders[i]->chars);
num_remind++;
}
printf("\nDay Reminder\n");
for (i = 0; i < num_remind; i++) {
for (j = 0; j < reminders[i]->len; j++)
printf("%c", reminders[i]->chars[j]);
printf("\n");
}
return 0;
}
int read_line(char str[], int n)
{
int ch, i = 0;
while ((ch = getchar()) != '\n')
if (i < n)
str[i++] = ch;
str[i] = '\0';
return i;
}