第十四章 结构和其他数据形式

文章通过多个C语言程序实例展示了图书目录管理的不同方面,包括单本图书信息录入、多本图书目录维护、结构体内嵌与指针操作、按标题和价格排序功能、以及用户交互和错误处理机制。同时,涉及了结构体作为函数参数和返回值的应用,以及如何读写文件来存储和恢复数据。
摘要由CSDN通过智能技术生成
  • 程序清单14.1,book.c:

/* book.c -- 一本书的图书目录 */ 
#include <stdio.h>
#include <string.h>
#define MAXTITL 41           /* 书名的最大长度 + 1 */ 
#define MAXAUTL 31           /* 作者姓名的最大长度 + 1 */
 
char * s_gets(char * st, int n);

struct book {                /* 结构模板:标记是 book */ 
    char title[MAXTITL];     /* 书名 */ 
    char author[MAXAUTL];    /* 作者 */ 
    float value;             /* 价格 */ 
};                           /* 结构模板结束 */

int main(void)
{
    struct book library;     /* 把 library 声明为一个 book 类型的变量 */ 
    
    printf("Please enter the book title.\n");
    s_gets(library.title, MAXTITL); /* 访问 title 部分 */
    printf("Now enter the author.\n");
    s_gets(library.author, MAXAUTL);
    printf("Now enter the value.\n");
    scanf("%f", &library.value);
    printf("%s by %s: $%.2f\n", library.title, library.author, library.value);
    printf("%s: \"%s\" ($%.2f)\n", library.author, library.title, library.value);
    printf("Done.\n");
    
    return 0;
} 

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n');          // 查找换行符 
        if (find)                         // 如果地址不为NULL 
            *find = '\0';                 // 在此处放置一个空字符 
        else
            while (getchar() != '\n')     // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

输出结果:

  • 程序清单14.2,manybook.c:

/* manybook.c -- 包含多本书的图书目录 */ 
#include <stdio.h>
#include <string.h>
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 100      /* 书籍的最大数量 */ 

char * s_gets(char * st, int n);

struct book{
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};

int main(void)
{
    struct book library[MAXBKS];  /* book 类型结构的数组 */ 
    int count = 0;
    int index;
    
    printf("Please enter the book title.\n");
    printf("Press [enter] at the start of a line to stop.\n");
    while (count < MAXBKS && s_gets(library[count].title, MAXTITL) != NULL 
            && library[count].title[0] != '\0')
    {
        printf("Now enter the author.\n");
        s_gets(library[count].author, MAXAUTL);
        printf("Now enter the value.\n");
        scanf("%f", &library[count++].value);
        while (getchar() != '\n')
            continue;
        if (count < MAXBKS)
            printf("Enter the next title.\n");
    }
    if (count > 0)
    {
        printf("Here is the list of your books:\n");
        for (index = 0; index < count; index++)
            printf("%s by %s: $%.2f\n", library[index].title, library[index].author, library[index].value);
    }
    else
        printf("No books? Too bad.\n");
    
    return 0;
}

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n'); //查找换行符 
        if (find)                //如果地址不为NULL 
            *find = '\0';        // 在此处放置一个空字符 
        else
            while (getchar() != '\n') // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

输出结果:

  • 程序清单14.3,friend.c:

// friend.c -- 嵌套结构示例 
#include <stdio.h>
#define LEN 20

const char * msgs[5] =  // 指针数组,每一个数组元素都是一个 char 类型的指针 
{
    "    Thank you for wonderful evening, ",
    "You certainly prove that a ",
    "is a special kind of guy. We must get together",
    "over a delicious ",
    " and have a few laughs"
};

struct names {              // 第一个结构 
    char first[LEN];
    char last[LEN];
};

struct guy {             // 第二个结构 
    struct names handle; // 嵌套结构
    char favfood[LEN];
    char job[LEN];
    float income; 
};

int main(void)
{
    struct guy fellow = {  // 初始化一个结构体变量
            { "Ewen", "Villard" },
            "grilled salmon",
            "personality coach",
            68112.00
    };
    
    printf("Dear %s, \n\n", fellow.handle.first);
    printf("%s%s.\n", msgs[0], fellow.handle.first);
    printf("%s%s\n", msgs[1], fellow.job);
    printf("%s\n", msgs[2]);
    printf("%s%s%s", msgs[3], fellow.favfood, msgs[4]);
    if (fellow.income > 150000.0)
        puts("!!");
    else if (fellow.income > 75000.0)
        puts("!");
    else
        puts(".");
    printf("\n%40s%s\n", " ", "See you soon,");
    printf("%40s%s\n", " ", "Shalala");
    
    return 0;
}

输出结果:

  • 程序清单14.4,friends.c:

/* friends.c -- 使用指向结构的指针 */ 
#include <stdio.h>
#define LEN 20

struct names {
    char first[LEN];
    char last[LEN];
};

struct guy {
    struct names handle;
    char favfood[LEN];
    char job[LEN];
    float income;
};

int main(void)
{
    struct guy fellow[2] = {
        { { "Ewen", "Villard" },
            "grilled salmon",
            "personality coach",
            68112.00    
        },
        { { "Rodney", "Swillbelly" },
            "tripe",
            "tabloid editor",
            432400.00    
        }
    };
    struct guy * him; // 指向结构的指针
    
    printf("address #1: %p #2: %p\n", &fellow[0], &fellow[1]);
    him = &fellow[0];
    printf("pointer #1: %p #2: %p\n", him, him + 1);
    printf("him->income is $%.2f: (*him).income is $%.2f\n", him->income, (*him).income);
    him++;            // 指向下一个结构 
    printf("him->favfood is %s: him->handle.last is %s\n", him->favfood, him->handle.last);
    
    return 0;
}

输出结果:

  • 程序清单14.5,funds1.c:

/* funds1.c -- 把结构成员看作参数传递 */ 
#include <stdio.h>
#define FUNDLEN 50

struct funds {
    char bank[FUNDLEN];
    double bankfund;
    char save[FUNDLEN];
    double savefund;
};

double sum(double, double);

int main(void)
{
    struct funds stan = {
        "Garlic-Melon Bank",
        4032.27,
        "Lucky's Savings and Loan",
        8543.94
    };
    
    printf("Stan has a total of $%.2f.\n", sum(stan.bankfund, stan.savefund));
    
    return 0;
}

double sum(double x, double y)
{
    return (x + y);
}

输出结果:

  • 程序清单14.6,funds2.c:

/* funds2.c -- 传递指向结构的指针 */ 
#include <stdio.h>
#define FUNDLEN 50

struct funds {
    char bank[FUNDLEN];
    double bankfund;
    char save[FUNDLEN];
    double savefund;
};

double sum(const struct funds *); // 参数是一个指针 

int main(void)
{
    struct funds stan = {
        "Garlic-Melon Bank",
        4032.27,
        "Lucky's Savings and Loan",
        8543.94
    };
    
    printf("Stan has a total of $%.2f.\n", sum(&stan));
    
    return 0;
}

double sum(const struct funds * money)
{
    return (money->bankfund + money->savefund);
}

输出结果:

  • 程序清单14.7,funds3.c:

/* funds3.c -- 传递一个结构 */ 
#include <stdio.h>
#define FUNDLEN 50

struct funds {
    char bank[FUNDLEN];
    double bankfund;
    char save[FUNDLEN];
    double savefund;
};

double sum(const struct funds moolah); /* 参数是一个结构 */ 

int main(void)
{
    struct funds stan = {
        "Garlic-Melon Bank",
        4032.27,
        "Lucky's Savings and Loan",
        8543.94
    };
    
    printf("Stan has a total of $%.2f.\n", sum(stan));
    
    return 0;
}

double sum(const struct funds moolah)
{
    return (moolah.bankfund + moolah.savefund);
}

输出结果:

  • 程序清单14.8,names1.c:

/* names1.c -- 使用指向结构的指针 */ 
#include <stdio.h>
#include <string.h>
#define NLEN 30

struct namect {
    char fname[NLEN];
    char lname[NLEN];
    int letters;
};

void getinfo(struct namect *);
void makeinfo(struct namect *);
void showinfo(const struct namect *);
char * s_gets(char * st, int n);

int main(void)
{
    struct namect person;
    
    getinfo(&person);
    makeinfo(&person);
    showinfo(&person);
    
    return 0;
}

void getinfo(struct namect * pst)
{
    printf("Please enter you first name.\n");
    s_gets(pst->fname, NLEN);
    printf("Please enter your last name.\n");
    s_gets(pst->lname, NLEN);
}

void makeinfo(struct namect * pst)
{
    pst->letters = strlen(pst->fname) + strlen(pst->lname);
}

void showinfo(const struct namect * pst)
{
    printf("%s %s, your name contains %d letters.\n", pst->fname, pst->lname, pst->letters);
}

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n'); //查找换行符 
        if (find)                //如果地址不为NULL 
            *find = '\0';        // 在此处放置一个空字符 
        else
            while (getchar() != '\n') // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

输出结果:

  • 程序清单14.9,names2.c:

/* names2.c -- 传递并返回结构 */ 
#include <stdio.h>
#include <string.h>
#define NLEN 30

struct namect {
    char fname[NLEN];
    char lname[NLEN];
    int letters;
};

struct namect getinfo(void);
struct namect makeinfo(struct namect); //不用指针一定要返回,否则只是局部变量的值改变 
void showinfo(struct namect);
char * s_gets(char * st, int n);

int main(void)
{
    struct namect person;
    
    person = getinfo();
    person = makeinfo(person);
    showinfo(person);
    
    return 0;
}

struct namect getinfo(void)
{
    struct namect temp;
    
    printf("Please enter you first name.\n");
    s_gets(temp.fname, NLEN);
    printf("Please enter your last name.\n");
    s_gets(temp.lname, NLEN);
    
    return temp;
}

struct namect makeinfo(struct namect info)
{
    info.letters = strlen(info.fname) + strlen(info.lname);
    
    return info; //操作后返回值 
}

void showinfo(struct namect info)
{
    printf("%s %s, your name contains %d letters.\n", info.fname, info.lname, info.letters);
}

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n'); //查找换行符 
        if (find)                //如果地址不为NULL 
            *find = '\0';        // 在此处放置一个空字符 
        else
            while (getchar() != '\n') // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

输出结果:

  • 程序清单14.10,names3.c:

/* names3.c -- 使用指针与 malloc() */ 
#include <stdio.h>
#include <string.h> //提供 strcpy()、strlen()
#include <stdlib.h> // 提供 malloc()、free() 
#define SLEN 30

struct namect {
    char * fname; // 使用指针 
    char * lname;
    int letters;
};

void getinfo(struct namect *);         // 分配内存 
void makeinfo(struct namect *);
void showinfo(const struct namect *);
void cleanup(struct namect *);         // 调用该函数时释放内存 
char * s_gets(char * st, int n);

int main(void)
{
    struct namect person;
    
    getinfo(&person);
    makeinfo(&person);
    showinfo(&person);
    cleanup(&person);
    
    return 0;
}

void getinfo(struct namect * pst)
{
    char temp[SLEN];
    
    printf("Please enter you first name.\n");
    s_gets(temp, SLEN);
    // 分配内存以存储名 
    pst->fname = (char *) malloc(strlen(temp) + 1);
    // 把名拷贝到动态分配的内存中 
    strcpy(pst->fname, temp);
    printf("Please enter your last name.\n");
    s_gets(temp, SLEN);
    pst->lname = (char *) malloc(strlen(temp) + 1);
    strcpy(pst->lname, temp);
}

void makeinfo(struct namect * pst)
{
    pst->letters = strlen(pst->fname) + strlen(pst->lname);
}

void showinfo(const struct namect * pst)
{
    printf("%s %s, your name contains %d letters.\n", pst->fname, pst->lname, pst->letters);
}

void cleanup(struct namect * pst)
{
    free(pst->fname);
    free(pst->lname);
}
char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n'); //查找换行符 
        if (find)                //如果地址不为NULL 
            *find = '\0';        // 在此处放置一个空字符 
        else
            while (getchar() != '\n') // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

输出结果:

  • 程序清单14.11,complit.c:

/* complit.c -- 复合字面量 */ 
#include <stdio.h>
#define MAXTITL 41
#define MAXAUTL 31

struct book {    // 结构模板:标记是book 
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};

int main(void)
{
    struct book readfirst;
    int score;
    
    printf("Enter test score: ");
    scanf("%d", &score);
    if (score >= 84)
        readfirst = (struct book) { "Crime and Punishment",
                                    "Fyodor Dostoyevsky",
                                    11.25};
    else
        readfirst = (struct book) { "Mr. Bouncy's Nice Hat",
                                    "Fred Winsome",
                                    5.99};
    printf("Your assigned reading:\n");
    printf("%s by %s: $%.2f\n", readfirst.title, readfirst.author, readfirst.value);
    
    return 0;
}

输出结果:

  • 程序清单14.12,flexmemb.c:

// flexmemb.c -- 伸缩型数组成员(C99 新增特性) 
#include <stdio.h>
#include <stdlib.h>

struct flex {
    size_t count;
    double average;
    double scores []; // 伸缩型数组成员 
};

void showFlex(const struct flex * p);

int main(void)
{
    struct flex * pf1, * pf2;
    int n = 5;
    int i;
    int tot = 0;
    
    pf1 = malloc(sizeof(struct flex) + n * sizeof(double));
    pf1->count = n;
    for (i = 0; i < n; i++)
    {
        pf1->scores[i] = 20.0 - i;
        tot += pf1->scores[i];
    }
    pf1->average = tot / n;
    showFlex(pf1);
    
    n = 9;
    tot = 0;
    pf2 = malloc(sizeof(struct flex) + n * sizeof(double));
    pf2->count = n;
    for (i = 0; i < n; i++)
    {
        pf2->scores[i] = 20.0 - i / 2.0;
        tot += pf2->scores[i];
    }
    pf2->average = tot / n;
    showFlex(pf2);
    free(pf1);
    free(pf2);
    
    return 0;
}

void showFlex(const struct flex * p)
{
    int i;
    printf("Scores: ");
    for (i = 0; i < (int) p->count; i++)
        printf("%g ", p->scores[i]);
    printf("\nAverage: %g\n", p->average);
}

输出结果:

  • 程序清单14.13,funds4.c:

/* funds4.c -- 把结构数组传递给函数 */ 
#include <stdio.h>
#define FUNDLEN 50
#define N 2

struct funds {
    char bank[FUNDLEN];
    double bankfund;
    char save[FUNDLEN];
    double savefund;
};

double sum(const struct funds money [], int n);

int main(void)
{
    struct funds jones[N] = {
            {
                "Garlic-Melon Bank",
                4032.27,
                "Lucky's Saving and Loan",
                8543.94
            },
            {
                "Honest Jack's Bank",
                3620.88,
                "Party Time Savings",
                3802.91
            }
    };
    
    printf("The Joneses have a total of  $%.2f.\n", sum(jones, N));
    
    return 0;
}

double sum(const struct funds money [], int n)
{
    double total;
    int i;
    
    for (i = 0; i < n; i++)
        total += (money + i)->bankfund + (money + i)->savefund; //用指针操作 
        //total += money[i].bankfund + money[i].savefund;
    
    return total;
}

输出结果:

  • 程序清单14.14 ,booksave.c:

/* booksave.c -- 在文件中保存结构中的内容 */ 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 10          /* 最大书籍数量 */ 

char * s_gets(char * st, int n);

struct book {              /* 建立 book 模板 */ 
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};

int main(void)
{
    struct book library[MAXBKS]; /* 结构数组 */ 
    int count = 0;
    int index, filecount;
    FILE * pbooks;
    int size = sizeof(struct book);
    
    if ((pbooks = fopen("book.dat", "a+b")) == NULL) // 在文件末尾追加内容 
    {
        fputs("Can't open book.dat file\n", stderr);
        exit(1);
    }
    rewind(pbooks);            /* 定位到文件开始 */ 
    while (count < MAXBKS && fread(&library[count], size, 1, pbooks) == 1) //从文件中读入到数组中 
    {
        if (count == 0)
            puts("Current contens of book.dat:");
        printf("%s by %s: $%.2f\n", library[count].title, library[count].author, library[count].value);
        count++;
    }
    filecount = count; // 备份以在写入时使用地址 
    if (count == MAXBKS)
    {
        fputs("The book.dat file is full.", stderr);
        exit(2);
    }
    puts("Please add new book title.");
    puts("Press [enter] at the start of a line to stop.");
    while (count < MAXBKS && s_gets(library[count].title, MAXTITL) != NULL &&library[count].title[0] != '\0')
    {
        puts("Now enter the author.");
        s_gets(library[count].author, MAXAUTL);
        puts("Now enter the value.");
        scanf("%f", &library[count++].value);
        while (getchar() != '\n')
            continue;
        if (count < MAXBKS)
            puts("Enter the next title.");
    }
    if (count > 0)
    {
        puts("Here is the list of your books:");
        for (index = 0; index < count; index++)
            printf("%s by %s: $%.2f\n", library[index].title, library[index].author, library[index].value);
        fwrite(&library[filecount], size, count - filecount, pbooks);
    }
    else
     puts("No books? Too bad.\n");
    puts("Bye.\n");
    fclose(pbooks);
    
    return 0;
}

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n'); //查找换行符 
        if (find)                //如果地址不为NULL 
            *find = '\0';        // 在此处放置一个空字符 
        else
            while (getchar() != '\n') // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

输出结果:

  • 程序清单14.15,enum.c:

/* enum.c -- 使用枚举类型的值 */ 
#include <stdio.h>
#include <string.h>       // 提供 strcmp() 、strchr() 函数原型 
#include <stdbool.h>
#define LEN 30

char * s_gets(char * st, int n);

enum spectrum { red, orange, yellow, green, blue, violet };
const char * colors [] = { "red", "orange", "yellow", "green", "blue", "violet" };

int main(void)
{
    char choice[LEN];
    enum spectrum color;
    bool color_is_found = false;
    
    puts("Enter a color (empty line to quit):");
    while (s_gets(choice, LEN) != NULL && choice[0] != '\0')
    {
        for (color = red; color <= violet; color++)
        {
            if (strcmp(choice, colors[color]) == 0)
            {
                color_is_found = true;
                break;
            }
        }
        if (color_is_found)
            switch (color)
            {
                case red: puts("Rose are red.");
                    break;
                case orange: puts("Poppies are orange.");
                    break;
                case yellow: puts("Sunflowers are yellow.");
                    break;
                case green: puts("Grass is green.");
                    break;
                case blue: puts("Bluebells are blue.");
                    break;
                case violet: puts("Violets are violet.");
                    break;
            }
        else
            printf("I don't know about the color %s.\n", choice);
        color_is_found = false;
        puts("Next color, please (empty line to quit):");
    }
    puts("Goodbye!");
    
    return 0;
}

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n'); //查找换行符 
        if (find)                //如果地址不为NULL 
            *find = '\0';        // 在此处放置一个空字符 
        else
            while (getchar() != '\n') // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

输出结果:

  • 程序清单14.16,func_ptr.c:

// func_ptr.c -- 使用函数指针 
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define LEN 81

char * s_gets(char * st, int n);
char showmenu(void);
void eatline(void);     // 读取至行末尾 
void show(void (*fp) (char *), char * str);
void ToUpper(char *);   // 把字符串转换为大写 
void ToLower(char *);   // 把字符串转换为小写 
void Transpose(char *); // 大小写转置 
void Dummy(char *);     // 不更改字符串 

int main(void)
{
    char line[LEN];
    char copy[LEN];
    char choice;
    void (*pfun) (char *); //函数指针
    
    puts("Enter a string (empty line to quit):");
    while (s_gets(line, LEN) != NULL && line[0] != '\0')
    {
        while ((choice = showmenu()) != 'n')
        {
            switch (choice)
            {
                case 'u': pfun = ToUpper; break;
                case 'l': pfun = ToLower; break;
                case 't': pfun = Transpose; break;
                case 'o': pfun = Dummy; break;
            }
            strcpy(copy, line); //让原始数据不动,操作备份数据即copy 
            show(pfun, copy);
        }
        puts("Enter a string (empty line to quit):");
    }
    puts("Bye!");
    
    return 0;
}

char showmenu(void)
{
    char ans;
    
    puts("Enter menu choice:");
    puts("u) uppercase           1) lowercase");
    puts("t) tansepose case      o) original case");
    puts("n) next string");
    ans = getchar();
    ans = tolower(ans);
    eatline();
    while (strchr("ulton", ans) == NULL)
    {
        puts("Please enter a u, l, t, o, or n:");
        ans = tolower(getchar());
        eatline();
    }
    
    return ans;
}

void eatline(void)
{
    while (getchar() != '\n')
        continue;
}

void ToUpper(char * str)
{
    while (*str)
    {
        *str = toupper(*str);
        str++;
    }
}

void ToLower(char * str)
{
    while (*str)
    {
        *str = tolower(*str);
        str++;
    }
}

void Transpose(char * str)
{
    while (*str)
    {
        if (islower(*str))
            *str = toupper(*str);
        else if (isupper(*str))
            *str = tolower(*str);
        str++;
    }
}

void Dummy(char * str)
{
    *str = *str;
}

void show(void (*fp) (char *), char * str)
{
    (*fp)(str);
    //fp(str); 也可直接操作,理解为函数名表地址 
    puts(str);
}

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n'); //查找换行符 
        if (find)                //如果地址不为NULL 
            *find = '\0';        // 在此处放置一个空字符 
        else
            while (getchar() != '\n') // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

输出结果:

  • 编程练习

题目1,方法:重新编写复习题5。示例代码14_1.c:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define LEN 12

typedef struct {
    char name[10];
    char abbrev[4];
    int days;
    int monumb;
} MONTH;

const MONTH months[LEN] =
{
    {"January", "Jan", 31, 1},
    {"February", "Feb", 28, 2},
    {"March", "Mar", 31, 3},
    {"April", "Apr", 30, 4},
    {"May", "May", 31, 5},
    {"June", "Jun", 30, 6},
    {"July", "Jul", 31, 7},
    {"August", "Aug", 31, 8},
    {"September", "Sep", 30, 9},
    {"October", "Oct", 31, 10},
    {"November", "Nov", 30, 11},
    {"December", "Dec", 31, 12}
};

int days(char *); // 获取指定月份及之前的所有天数 

int main(void)
{
    int daynum;
    char mname[LEN];
    
    printf("Please enter the name of the month(q to quit): ");
    while (scanf("%11s", mname) == 1 && mname[0] != 'q')
    {
        daynum = days(mname);
        if (daynum > 0)
            printf("Totally %d days.\n", daynum);
        else
            printf("%s is not a valid month.\n", mname);
        printf("You can enter again: ");
        while (getchar() != '\n')
            continue;
    }
    printf("Done!\n");
    
    return 0;
}

int days(char * str)
{
    int i = 0;
    int total = 0;

    str[0] = toupper(str[0]); //首字母大写 
    while (*(str + ++i)) //其他字母小写 
        *(str + i) = tolower(*(str + i));
    for (i = 0; i < LEN; i++)
        if (0 == strcmp(months[i].name, str))
            return total + months[i].days;
        else
            total += months[i].days;
    
    return -1;
}

输出结果:

题目2,方法:获取该年到指定日期(包括该日期)的天数。示例代码14_2.c:

#include <stdio.h>
#include <string.h> //提供 strcmp() 函数 
#include <ctype.h> //提供 toupper() 函数 
#include <stdbool.h> //提供 bool 类型 
#include <stdlib.h> // 提供 atoi() 函数 
#define LEN 12

typedef struct {
    char name[10];
    char abbrev[4];
    int days;
    int monumb;
} MONTH;

typedef struct {
    int year;
    char mname[LEN];
    int day;
} DATE; 

bool is_leap_year(int);
int days(DATE *, MONTH *);

int main(void)
{
    int daynum; //总天数
    DATE dates; //日期
    MONTH months[LEN] = {
        { "January", "Jan", 31, 1 },
        { "February", "Feb", 28, 2 },
        { "March", "Mar", 31, 3 },
        { "April", "Apr", 30, 4 },
        { "May", "May", 31, 5 },
        { "June", "Jun", 30, 6 },
        { "July", "Jul", 31, 7 },
        { "August,", "Aug", 31, 8 },
        { "September", "Sep", 30, 9 },
        { "October", "Oct", 31, 10 },
        { "November", "Nov", 30, 11 },
        { "December", "Dec", 31, 12 }
    };
    
    printf("Please enter the year, month, day: ");
    while (scanf("%d%11s%d", &dates.year, dates.mname, &dates.day) == 3)
    {
        if ((daynum = days(&dates, months)) >= 0)
            printf("Totally %d days.\n", daynum);
        else
            printf("Illigal input.\n");
        (months + 1)->days = 28; // 重置为非闰年 2 月份的天数 
        printf("You can enter the year , month, day again: ");
    }
    
    return 0;
}

bool is_leap_year(int n)
{
    if ((n % 4 == 0 && n % 100 != 0) || n % 400 == 0)
        return true;
    else
        return false;
}

int days(DATE * pd, MONTH * pm)
{
    int is_num = 1, i = 0, total = 0;
    
    if (is_leap_year(pd->year)) //判断是否闰年 
        (pm + 1)->days = 29; //闰年则更改 2 月份的天数,也可考虑传递结构参数不传递指针 
    is_num = atoi(pd->mname); //尝试转换为数字,不成功则返回 0 
    if (!is_num) //非数字转换 
    {
        *(pd->mname) = toupper(*(pd->mname)); //首字母大写 
        while (*(pd->mname + ++i)) //其他字母小写 
            *(pd->mname + i) = tolower(*(pd->mname + i));
    }
    for (i = 0; i < LEN; i++)
        if (strcmp((pm + i)->name, pd->mname) == 0 
            || strcmp((pm + i)->abbrev, pd->mname) == 0 ||
            is_num == (pm + i)->monumb)
            if (pd->day > (pm + i)->days)
                return -1;
            else
                return total + pd->day;
        else
            total += (pm + i)->days;
    
    return -1;
}

输出结果:

题目3,方法1:按要求修改程序清单14.3。示例代码14_3.c:

#include <stdio.h>
#include <string.h>
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 100

typedef struct{
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
} BOOK;

char * s_gets(char * st, int n);
void sort_title(BOOK **, int);
void sort_price(BOOK **, int);
typedef void (* pfun)(BOOK **, int); //函数指针 
void sort_func(pfun fp, BOOK **, int); //包含函数指针的函数 
pfun fun[2] = { sort_title, sort_price }; //函数指针数组 

int main(void)
{
    BOOK library[MAXBKS];
    BOOK * book[MAXBKS]; // 指针数组 
    int count = 0;
    int index;
    
    printf("Please enter the book title.\n");
    printf("Press [enter] at the start of a line to stop.\n");
    while (count < MAXBKS && s_gets(library[count].title, MAXTITL) != NULL && library[count].title[0] != '\0')
    {
        printf("Now enter the author.\n");
        s_gets(library[count].author, MAXAUTL);
        printf("Now enter the value.\n");
        book[count] = &library[count]; // 保存地址以备用 
        scanf("%f", &library[count++].value);
        while (getchar() != '\n')
            continue;
        if (count < MAXBKS)
            printf("Enter the next title.\n");
    }
    if (count > 0)
    {
        printf("Here is the original list of your books:\n");
        for (index = 0; index < count; index++)
            printf("%s by %s: $%.2f\n", library[index].title, library[index].author, library[index].value);
        printf("Here is the list ordered by title:\n");
        sort_func(fun[0], book, count);
        for (index = 0; index < count; index++)
            printf("%s by %s: $%.2f\n", book[index]->title, book[index]->author, book[index]->value);
        printf("Here is the list ordered by price:\n");
        sort_func(fun[1], book, count);
        for (index = 0; index < count; index++)
            printf("%s by %s: $%.2f\n", book[index]->title, book[index]->author, book[index]->value);
    }
    else
        printf("No books? Too bad.\n");
    
    return 0;
}

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n'); //查找换行符 
        if (find)                //如果地址不为NULL 
            *find = '\0';        // 在此处放置一个空字符 
        else
            while (getchar() != '\n') // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

void sort_title(BOOK ** pb, int n)
{
    int i, j;
    BOOK * temp;
    
    for (i = 0; i < n - 1; i++) // 冒泡排序 
        for (j = i + 1; j < n; j++)
            if (strcmp((*(pb + i))->title, (*(pb + j))->title) > 0) // ASCII 码升序,交换地址 
            {
                temp = *(pb + i);
                *(pb + i) = *(pb + j);
                *(pb + j) = temp;
            }
}

void sort_price(BOOK ** pb, int n)
{
    int i, j;
    BOOK * temp;
    
    for (i = 0; i < n - 1; i++) // 冒泡排序 
        for (j = i + 1; j < n; j++)
            if ((*(pb + i))->value > (*(pb + j))->value) //价格升序,交换地址 
            {
                temp = *(pb + i);
                *(pb + i) = *(pb + j);
                *(pb + j) = temp;
            }
}

void  sort_func(pfun fp, BOOK ** pb, int n)
{
    fp(pb, n);
}

输出结果:

方法2,示例代码14_3_2.c:

#include <stdio.h> // ->的优先级高于 *,因此要加括号 
#include <string.h> //变量(左值)才能被赋值 
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 100

typedef struct{
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
} BOOK;

char * s_gets(char * st, int n);
void sort(BOOK **, int, int);

int main(void)
{
    BOOK library[MAXBKS];
    BOOK * book[MAXBKS];
    int count = 0;
    int index;
    
    printf("Please enter the book title.\n");
    printf("Press [enter] at the start of a line to stop.\n");
    while (count < MAXBKS && s_gets(library[count].title, MAXTITL) != NULL && library[count].title[0] != '\0')
    {
        printf("Now enter the author.\n");
        s_gets(library[count].author, MAXAUTL);
        printf("Now enter the value.\n");
        book[count] = &library[count];
        scanf("%f", &library[count++].value);
        while (getchar() != '\n')
            continue;
        if (count < MAXBKS)
            printf("Enter the next title.\n");
    }
    if (count > 0)
    {
        printf("Here is the original list of your books:\n");
        for (index = 0; index < count; index++)
            printf("%s by %s: $%.2f\n", library[index].title, library[index].author, library[index].value);
        printf("Here is the list ordered by title:\n");
        sort(book, count, 1);
        for (index = 0; index < count; index++)
            printf("%s by %s: $%.2f\n", book[index]->title, book[index]->author, book[index]->value);
        printf("Here is the list ordered by price:\n");
        sort(book, count, 2);
        for (index = 0; index < count; index++)
            printf("%s by %s: $%.2f\n", book[index]->title, book[index]->author, book[index]->value);
    }
    else
        printf("No books? Too bad.\n");
    
    return 0;
}

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n'); //查找换行符 
        if (find)                //如果地址不为NULL 
            *find = '\0';        // 在此处放置一个空字符 
        else
            while (getchar() != '\n') // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

void sort(BOOK ** pb, int n, int type)
{
    int i, j;
    BOOK * temp;
    
    for (i = 0; i < n - 1; i++)
        for (j = i + 1; j < n; j++)
            if (type == 1)
            {
                if (strcmp((*(pb + i))->title, (*(pb + j))->title) > 0) // ASCII 码升序,交换地址 
                {
                    temp = *(pb + i);
                    *(pb + i) = *(pb + j);
                    *(pb + j) = temp;
                }
            }
            else
                if ((*(pb + i))->value > (*(pb + j))->value) //价格升序,交换地址 
                {
                    temp = *(pb + i);
                    *(pb + i) = *(pb + j);
                    *(pb + j) = temp;
                }        
}

题目4,方法:根据要求打印结构信息。示例代码14_4_a.c:

#include <stdio.h>
#include <string.h>
#define N 5
#define LEN 30

typedef struct {
    char fname[LEN];
    char mname[LEN];
    char lname[LEN];
} NAME;

typedef struct {
    char insnum[LEN];
    NAME name;
} ID; 

void show_id(ID *, int);

int main(void)
{
    ID id[5] = {
        { "3021248", { "Jony", "Gds", "Fdi" } },
        { "3032427", { "Marry", "Fd", "Sdf" } },
        { "3023132", { "Caffd", "", "Dferw" } },
        { "3032432", { "David", "Daf", "Caff" } },
        { "3043254", { "Sally", "", "Jdafd" } } 
    };

    show_id(id, N);
    
    return 0; 
}

void show_id(ID * pd, int n)
{
    int i;
    
    printf("The ID information:\n");
    for (i = 0; i < n; i++)
        if (*(pd + i)->name.mname != '\0')
            printf("%s, %s %c. -- %s\n", (pd + i)->name.fname, (pd + i)->name.lname, *(pd + i)->name.mname, (pd + i)->insnum);
        else
            printf("%s, %s -- %s\n", (pd + i)->name.fname, (pd + i)->name.lname, (pd + i)->insnum);
}

输出结果:

14_4_b.c:

#include <stdio.h>
#include <string.h>
#define N 5
#define LEN 30

typedef struct {
    char fname[LEN];
    char mname[LEN];
    char lname[LEN];
} NAME;

typedef struct {
    char insnum[LEN];
    NAME name;
} ID; 

void show_id(ID);

int main(void)
{
    int i;
    ID id[5] = {
        { "3021248", { "Jony", "Gds", "Fdi" } },
        { "3032427", { "Marry", "Fd", "Sdf" } },
        { "3023132", { "Caffd", "", "Dferw" } },
        { "3032432", { "David", "Daf", "Caff" } },
        { "3043254", { "Sally", "", "Jdafd" } } 
    };
    printf("The ID information:\n");
    for (i = 0; i < N; i++)
        show_id(id[i]);
    
    return 0; 
}

void show_id(ID pd)
{
    if (*pd.name.mname != '\0')
        printf("%s, %s %c. -- %s\n", pd.name.fname, pd.name.lname, *pd.name.mname, pd.insnum);
    else
        printf("%s, %s -- %s\n", pd.name.fname, pd.name.lname, pd.insnum);
}

输出结果:

题目5,方法:按要求处理结构数据。示例代码14_5.c:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#define CSIZE 4
#define LEN 30
#define N 3

typedef struct {
    char fname[LEN];
    char lname[LEN];
} NAME;

typedef struct {
    NAME name;
    float grade[N];
    float average;
} STUDENT;

void get_score(STUDENT *, int);
void ave(STUDENT *, int);
void show_info(STUDENT *, int);
void show_class(STUDENT *, int);
void eatline(void);

int main(void)
{
    STUDENT student[CSIZE] = {
        { { "Marry", "Kaily" }, { 0.0 , 0.0, 0.0 }, 0.0 },
        { { "Jony", "Farry" }, { 0.0 , 0.0, 0.0 }, 0.0 },
        { { "Sailly", "Lay" }, { 0.0 , 0.0, 0.0 }, 0.0 },
        { { "Pony", "Yummy" }, { 0.0 , 0.0, 0.0 }, 0.0 }
    };
    get_score(student, CSIZE);
    ave(student, CSIZE);
    show_info(student, CSIZE);
    show_class(student, CSIZE);
    
    return 0;
}

void get_score(STUDENT * ps, int n)
{
    char f_name[LEN], l_name[LEN];
    int i;
    bool is_con = true, is_found = false;
    char choice;
    
    while (is_con)
    {
        puts("Please enter the name:");
        scanf("%s%s", f_name, l_name);
        eatline();
        for (i = 0; i < n; i++)
            if (strcmp(f_name, (ps + i)->name.fname) == 0 && strcmp(l_name, (ps + i)->name.lname) == 0)
            {
                puts("Please enter three scores:");
                while (scanf("%f%f%f", &(ps + i)->grade[0], &(ps + i)->grade[1], &(ps + i)->grade[2]) != 3)
                {
                    printf("Illigal input, try again: ");
                    eatline();    
                }
                is_found = true;
                eatline();
                printf("Entered.\n");
                break;
            }
        if (!is_found)
            puts("No found!");
        printf("Continue to enter(y/n)?");
        if ((choice = getchar()) == 'n')
            is_con = false;
        if (choice != '\n')
            eatline();
        is_found = false;
    }
}

void ave(STUDENT * ps, int n)
{
    int i, j;
    float fnum = 0.0;
    
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < N; j++)
            fnum += ps[i].grade[j];
        (ps + i)->average = fnum / N;
        fnum = 0.0;
    }
}

void show_info(STUDENT * ps, int n)
{
    int i, j;
    
    for (i = 0; i < n; i++)
    {
        printf("\nName: %s %s\n", (ps + i)->name.fname, (ps + i)->name.lname);
        for (j = 0; j < N; j++)
            printf("Score %d: %.2f\n", j + 1, (ps + i)->grade[j]);
        printf("Average: %.2f\n", (ps + i)->average);
    }
}

void show_class(STUDENT * ps, int n)
{
    int i;
    float class_ave = 0.0;
    
    for (i = 0; i < n; i++)
        class_ave += (ps + i)->average;
    printf("\nClass Average: %.2f\n", class_ave / CSIZE);
}

void eatline(void)
{
    while (getchar() != '\n')
        continue;
}

输出结果:

题目6,方法:按要求计算和存储结构信息。示例代码14_6.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 20

typedef struct {
    int id;
    char fname[LEN];
    char lname[LEN];
    int stage;
    int hit;
    int base;
    int rbi;
    float hit_rate;
} TEAM;

void record_info(TEAM *, FILE *, int);

int main(void)
{
    static TEAM team[LEN]; //静态变量自动初始化为 0 
    FILE * fp;
    
    if ((fp = fopen("team.txt","r")) == NULL)
    {
        fprintf(stderr, "Can not open %s.\n", "team.txt");
        exit(EXIT_FAILURE);
    }
    record_info(team, fp, LEN);
    if (fclose(fp) != 0)
    {
        fprintf(stderr, "Can not close %s.\n", "team.txt");
        exit(EXIT_FAILURE);
    }
    
    return 0;
}

void record_info(TEAM * pt, FILE * pf, int n)
{
    int count = 0; //不同球员计数
    int ids; //存储读入的id
    char fn[LEN], ln[LEN];
    int stage_n, hit_n, base_n, rbi_n;
    int i;
    
    while (fscanf(pf, "%d%20s%20s%d%d%d%d", &ids, fn, ln, &stage_n, &hit_n, &base_n, &rbi_n) == 7 && count < n)
    {
        if((pt + ids)->stage == 0) //录入一个新的球员身份信息并更新数据 
        {
            count++;
            (pt + ids)->id = ids;
            strcpy((pt + ids)->fname, fn);
            strcpy((pt + ids)->lname, ln);
        } 
        (pt + ids)->stage += stage_n;
        (pt + ids)->hit += hit_n;
        (pt + ids)->base += base_n;
        (pt + ids)->rbi += rbi_n;
    } 
    if (count > 0)
        for (i = 0; i < n; i++)
        {
            if ((pt + i)->stage != 0)
            {
                (pt + i)->hit_rate = (float) (pt + i)->hit / (pt + i)->stage;
                printf("Id: %d Name: %s %s ",(pt + i)->id, (pt + i)->fname, (pt + i)->lname);
                printf("Stage: %d Hit: %d Base: %d Rbi: %d ", (pt + i)->stage, (pt + i)->hit, (pt + i)->base, (pt + i)->rbi);
                printf("Hit_rate: %.2f\n", (pt + i)->hit_rate);
            }        
        }
    else
        puts("No data!");
}

team.txt:

0 Jessie Joybat 5 2 1 1
1 Mary Json 6 3 7 9
2 Filp Shell 5 3 6 1
9 Francy Card 9 6 1 2
4 Wan cary 8 5 2 1
11 Keassy Coffee 3 3 6 7
0 Jessie Joybat 7 9 8 2
11 Keassy Coffee 4 7 5 8

输出结果:

题目7,方法:按要求改写程序清单14.14。该项目包含两个头文件和三个源文件。

check.h:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#define WRONG 100

void wait(void);//暂停打印提示信息 
void consumer(char *, int *);//清空缓冲区并保存清空的字符 
bool character_check(char *, int *); //检测是否有非空字符并清空第一个非空字符及之前的缓冲区 
char choose_check(int, char *, void (*)(void)); //将输入限制在合法区间并返回输入值
void show_menu1(void); //打印一级菜单 
void show_menu2(void); //打印二级菜单
void dummy(void); 

check.c:

#include "check.h"

void show_menu1(void)
{
    printf("****************************************\n");
    printf("Please choose the operation:\n");
    printf("s.  Showinfo                   a. Add\n");
    printf("m.  Modify                     d. Delete\n");
    printf("q.  Quit\n\n");
}

void show_menu2(void)
{
    printf("****************************************\n");
    printf("Please choose the modify section:\n");
    printf("t.  Title                    a. Author\n");
    printf("v.  Value                    q. Quit\n\n");
}

void dummy(void)
{
    
}

void wait(void)
{
    char ch;
    
    printf("Enter to continue...");
    while ((ch = getchar()) != '\n')
        continue;    
    //system("cls");
}

void consumer(char * wrong, int * n)
{
    char cha;
    
    while ((cha = getchar()) != '\n')
        *(wrong + (*n)++) = cha;
}

bool character_check(char * wrong, int * n)
{
    char ch2;
    
    while ((ch2 = getchar()) != '\n') //第一个非空字符为回车,则读走回车 
    {
        *(wrong + (*n)++) = ch2;
        if (ch2 != '\t' && ch2 != ' ') //若第一个非空字符非回车,回车不被读走 
            return true;
    }
    
    return false;
}

char choose_check(int n, char * str, void (*pfun) (void))
{
    char ch1;
    char notice[n];
    int num = 1;
    int * count = &num;
    
    pfun();
    printf("Enter a character to choose: ");
    //防止第一个非空合法字符后出现第二个非空字符,例如assss 
    while (strchr(str, (ch1 = tolower(getchar()))) == NULL || character_check(notice, count) == true)
    {
        if (ch1 == ' ' || ch1 == '\n' || ch1 == '\t') // 使至少第一个非空字符被ch1获得 
            continue;
        else if (character_check(notice, count) == true) //防止出现 assss 这样的输入,即之前非法,之后合法,以及清空非空白字符缓冲区 
            consumer(notice, count); //输入a2时判断返回false,不执行此步(此时所有字符包括回车均已被读走) 
        *notice = ch1;
        printf("%s is illegal, try again: ", notice); 
        memset(notice, 0 ,sizeof(notice)); //初始化字符串数组 
        num = 1; //重置计数 
    }
    
    return ch1;
}

book.h:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define LEN 10
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 10

typedef struct {
    int booknum; //书本编号 
    char title[MAXTITL]; //书名 
    char author[MAXAUTL]; //作者 
    float value; //价格 
    bool deleted; //是否被删除 
} BOOK;

int show_book(char *, int); //显示当前书本信息 
void add_book(char *, int); //添加书本
void modify_book(char *, int); //修改书本信息 
void dele_book(char *, int); //删除书本信息 
char * s_gets(char * st, int n);

book.c:

#include "book.h"
#include "check.h"

int show_book(char * fname, int n)
{
    FILE * fp;
    BOOK books[n];
    int size = sizeof(BOOK);
    int count = 0;
    
    if ((fp = fopen(fname, "r")) == NULL)
    {
        fprintf(stderr, "Can not open %s.\n", fname);
        exit(EXIT_FAILURE);
    }
    while (count < n && fread(&books[count], size, 1, fp) == 1) //从文件中读入一块数据
    {
        if (count == 0)
            printf("Current contens of %s:\n", fname);
        if (books[count].deleted == true) 
            printf("BookNum : %d %s by %s: $%.2f\n", books[count].booknum, books[count].title, books[count].author, books[count].value);
        count++;
    } 
    if (fclose(fp) != 0)
    {
        fputs("Can not close file.\n", stderr);
        exit(EXIT_FAILURE);
    }
    
    return count;
}

void add_book(char * fname, int n)
{
    FILE * fp;
    static BOOK books[MAXBKS]; //静态变量自动初始化 
    int size = sizeof(BOOK);
    int count = 0; 
    int num;
    int total = 0; // 统计当前文件多少本书 
    int i; 
    
    show_book(fname, n);
    if ((fp = fopen(fname, "r+b")) == NULL)
    {
        fputs("Can't  open book.dat file\n", stderr);
        exit(EXIT_FAILURE);
    }
    rewind(fp); //回到文件开始便于计数
    while (count < n && fread(&books[count], size, 1, fp) == 1) // 从文件读入到数组中 
        count++;
    for (i = 0; i < n; i++) // 统计当前书本数 
        if (books[i].deleted == true)
            total++;    
    if (total == n) // 如果已经满了 
    {
        fputs("The book.dat file is full.", stderr);
        exit(2);
    }
    for (i = 0; i < n; i++)
        if (books[i].deleted == false) // 找到第一个可用位置
        {
            num = i;
            break;
        } 
    puts("Please add new book title.");
    puts("Press [enter] at the start of a line to stop.");
    while (s_gets(books[num].title, MAXTITL) != NULL && books[num].title[0] != '\0')
    {
        books[num].booknum = num;
        puts("Now enter the author.");
        s_gets(books[num].author, MAXAUTL);
        puts("Now enter the value.");
        scanf("%f", &books[num].value);
        books[num].deleted = true;
        total++;
        while (getchar() != '\n')
            continue;
        if (total < n)
            puts("Enter the next title.");
        else
            break;
        for (i = 0; i < n; i++)
            if (books[i].deleted == false) // 找到第一个可用位置
            {
                num = i;
                break;
            }
    }
    rewind(fp);
    fwrite(books, size, MAXBKS, fp);
    if (fclose(fp) != 0)
        {
            fputs("Can not close file.\n", stderr);
            exit(EXIT_FAILURE);
        } 
    puts("Saved!");
}

void modify_book(char * fname, int n)
{
    char choose;
    int num, count = 0;
    FILE * fp;
    static BOOK books[MAXBKS];
    int size = sizeof(BOOK); 
    
    system("cls");
    show_book(fname, n); // range = 可用于限制输入编号范围 
    if ((fp = fopen(fname, "r+b")) == NULL)
    {
        fprintf(stderr, "Can not open %s.\n", fname);
        exit(EXIT_FAILURE);
    }
    while (count < n && fread(&books[count], size, 1, fp) == 1)
        count++;
    while ((choose = choose_check(WRONG, "tavq", show_menu2)) != 'q')
    {
        printf("Please input the num: ");
        scanf("%d", &num);
        while (getchar() != '\n')
            continue;
        switch (choose)
        {
            case 't':
                printf("Please enter the new title: ");
                s_gets(books[num].title, MAXTITL);
                break;
            case 'a':
                printf("Please enter the new author: ");
                s_gets(books[num].author, MAXTITL);
                break;
            case 'v':
                printf("Please enter the new value: ");
                scanf("%f", &books[num].value);
                break;
            case 'q':
                break;    
        }
        rewind(fp);
        fseek(fp, num * size, SEEK_SET);
        fwrite(&books[num], size, 1, fp);
        if (fclose(fp) != 0)
        {
            fputs("Can not close file.\n", stderr);
            exit(EXIT_FAILURE);
        } 
        system("cls");
        show_book(fname, n);
        printf("Saved!\n");
        if ((fp = fopen(fname, "r+b")) == NULL)
        {
            fprintf(stderr, "Can not open %s.\n", fname);
            exit(EXIT_FAILURE);
        }
    }
    if (fclose(fp) != 0)
    {
        fputs("Can not close file.\n", stderr);
        exit(EXIT_FAILURE);
    } 
}

void dele_book(char * fname, int n)
{
    int num, count = 0;
    FILE * fp;
    static BOOK books[MAXBKS];
    int size = sizeof(BOOK); 
    
    system("cls");
    show_book(fname, n); // range = 可用于限制输入编号范围 
    if ((fp = fopen(fname, "r+b")) == NULL)
    {
        fprintf(stderr, "Can not open %s.\n", fname);
        exit(EXIT_FAILURE);
    }
    while (count < n && fread(&books[count], size, 1, fp) == 1)
        count++;
    printf("Please input the num(q to quit): ");
    while (scanf("%d", &num) == 1)
    {
        while (getchar() != '\n')
            continue;
        books[num].deleted = false;
        rewind(fp);
        fseek(fp, num * size, SEEK_SET);
        fwrite(&books[num], size, 1, fp);
        if (fclose(fp) != 0)
        {
            fputs("Can not close file.\n", stderr);
            exit(EXIT_FAILURE);
        } 
        system("cls");
        show_book(fname, n);
        printf("Saved!\n");
        if ((fp = fopen(fname, "r+b")) == NULL)
        {
            fprintf(stderr, "Can not open %s.\n", fname);
            exit(EXIT_FAILURE);
        }
        printf("Please input the num(q to quit): ");
    }
    while (getchar() != '\n')
            continue;
    if (fclose(fp) != 0)
    {
        fputs("Can not close file.\n", stderr);
        exit(EXIT_FAILURE);
    } 
} 

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n'); //查找换行符 
        if (find)                //如果地址不为NULL 
            *find = '\0';        // 在此处放置一个空字符 
        else
            while (getchar() != '\n') // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

main.c:

#include <stdio.h>
#include "book.h"
#include "check.h"

int main(void)
{
    char data_file[LEN] = "book.dat"; // 保存书本文件 
    char choose; // 保存一级菜单选项 
    
    while ((choose = choose_check(WRONG, "sdamq", show_menu1)) != 'q')
    {
        switch (choose)
        {
            case 's':
                show_book(data_file, MAXBKS);
                wait();
                break;
            case 'a':
                add_book(data_file, MAXBKS);
                wait();
                break;
            case 'm':
                modify_book(data_file, MAXBKS);
                break;
            case 'd':
                dele_book(data_file, MAXBKS);
                break;
            case 'q':
                break;
        }
        system("cls");
    }
    
    return 0;
} 

输出结果:

题目8,方法:按照要求将数据从文件读入结构体。

check.h:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#define WRONG 100

void wait(void); // 暂停打印提示信息 
void consumer(char *, int *); // 清空缓冲区并保存清空的字符 
bool character_check(char *, int *); // 检测是否有非空字符并清空第一个非空字符及之前的缓冲区 
char choose_check(int, char *, void (*)(void)); // 将输入限制在合法区间并返回输入值
void show_menu(void); // 打印一级菜单 
void dummy(void); // 无操作 

check.c:

#include "check.h"

void show_menu(void)
{
    puts("****************************************");
    puts("To choose a function, enter lts letter lable:");
    puts("a) Show number of empty seats");
    puts("b) Show list of empty seats");
    puts("c) Show alphabetical list of seats");
    puts("d) Assign a customer to a seats");
    puts("e) Delete a seat assignment");
    puts("f) Quit");
}

void dummy(void)
{
    
}

void wait(void)
{
    char ch;
    
    printf("Enter to continue...");
    while ((ch = getchar()) != '\n')
        continue;    
}

void consumer(char * wrong, int * n)
{
    char cha;
    
    while ((cha = getchar()) != '\n')
        *(wrong + (*n)++) = cha;
}

bool character_check(char * wrong, int * n)
{
    char ch2;
    
    while ((ch2 = getchar()) != '\n')   // 第一个非空字符为回车,则读走回车 
    {
        *(wrong + (*n)++) = ch2;
        if (ch2 != '\t' && ch2 != ' ') // 若第一个非空字符非回车,回车不被读走 
            return true;
    }
    
    return false;
}

char choose_check(int n, char * str, void (*pfun) (void))
{
    char ch1;
    char notice[n];
    int num = 1;
    int * count = &num;
    
    pfun();
    printf("Enter a character to choose: ");
    // 防止第一个非空合法字符后出现第二个非空字符,例如assss 
    while (strchr(str, (ch1 = tolower(getchar()))) == NULL || character_check(notice, count) == true)
    {
        if (ch1 == ' ' || ch1 == '\n' || ch1 == '\t') // 使至少第一个非空字符被ch1获得 
            continue;
        else if (character_check(notice, count) == true) // 防止出现 assss 这样的输入,即之前非法,之后合法,以及清空非空白字符缓冲区 
            consumer(notice, count); // 输入a2时判断返回false,不执行此步(此时所有字符包括回车均已被读走) 
        *notice = ch1;
        printf("%s is illegal, try again: ", notice); 
        memset(notice, 0 ,sizeof(notice)); // 初始化字符串数组 
        num = 1; // 重置计数 
    }
    
    return ch1;
}

airplan.h:

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#define LEN 20
#define N 12

typedef struct {
    char seat_id[LEN]; // 座位编号 
    bool marked;       // 是否预定 
    char fname[LEN];   // 名 
    char lname[LEN];   // 姓 
} SEAT;

void initiate(SEAT *, char *);         // 初始化数据 
int show_emnum(SEAT *, int);           // 显示空座位的数量
void show_emlist(SEAT *, int);         // 显示空座位列表 
void show_alplist(SEAT *, int);        // aplphabet 顺序输出座位列表 
void assign_seat(SEAT *, char *, int); // 为一位客户分配座位 
void delete_seat(SEAT *, char *, int); // 为一位客户取消座位 
char * s_gets(char * st, int n);
void eatline(void);

airplan.c:

#include "airplan.h"

void initiate(SEAT * ps, char * data_file)
{
    int i = 0;
    int size = sizeof(SEAT);
    FILE * fp;
    
    if ((fp = fopen(data_file, "r+b")) == NULL) // 如果文件不存在,则初始化 
    {
        if ((fp = fopen(data_file, "w+b")) == NULL)
        {
            fprintf(stderr, "Can not creat file %s.\n", data_file);
            exit(EXIT_FAILURE);
        }
        SEAT seat[N] = {
            { "C01", false, "", "" },
            { "C02", false, "", "" },
            { "C03", false, "", "" },
            { "B01", false, "", "" },
            { "B02", false, "", "" },
            { "B03", false, "", "" },
            { "A01", false, "", "" },
            { "A02", false, "", "" },
            { "A03", false, "", "" },
            { "D01", false, "", "" },
            { "D02", false, "", "" },
            { "D03", false, "", "" },
        };
        fwrite(seat, size, N, fp);
        if (fclose(fp) != 0)
        {
            fputs("Can not close file.\n", stderr);
            exit(EXIT_FAILURE);
        }
        if ((fp = fopen(data_file, "r+b")) == NULL)
        {
            fputs("Can not open file.\n", stderr);
            exit(EXIT_FAILURE);
        } 
    }
    while (i < N && fread(ps + i, size, 1, fp) == 1) // 将数据从文件中读入结构数组 
        i++;
    if (fclose(fp) != 0)
    {
        fputs("Can not close file.\n", stderr);
        exit(EXIT_FAILURE);
    }
} 

int show_emnum(SEAT * ps, int n)
{
    int i, num = 0; // 空座位的数量 
    
    for (i = 0; i < n; i++)
        if ((ps + i)->marked == false)
            num++;
    
    return num;
} 

void show_emlist(SEAT * ps, int n)
{
    int i, num = 0;
    
    putchar('\n');
    for (i = 0; i < n; i++)
        if ((ps + i)->marked == false)
        {
            printf("%s ", (ps + i)->seat_id);
            num++;
        }
    putchar('\n');
    if (!num)
        printf("No empty seat!\n");        
}

void show_alplist(SEAT * ps, int n)
{
    SEAT * alpha[n];
    SEAT * temp; 
    int i, j;
    
    for (i = 0; i < n; i++) //获取结构地址便于操作 
        alpha[i] = (ps + i);
    for (i = 0; i < n - 1; i++)
        for (j = i+ 1; j < n; j++)
            if (strcmp(alpha[i]->seat_id, alpha[j]->seat_id) > 0)
            {
                temp = alpha[i];
                alpha[i] = alpha[j];
                alpha[j] = temp;    
            }
    putchar('\n');
    for (i = 0; i < n; i++)
        printf("%s ", (*(alpha + i))->seat_id); // -> 的优先级高于 *,因此加括号 
    putchar('\n');
}

void assign_seat(SEAT * ps, char * fname, int n)
{
    char seat[LEN];
    int id = 0, em_num;
    bool find = false;
    int size = sizeof(SEAT);
    FILE * fp;
    
    em_num = show_emnum(ps, n);
    if (em_num)
    {
        printf("\nEmpty seats:\n");
        show_emlist(ps, n);
        printf("Input the ID(empty to quit): ");
        s_gets(seat, n);
        *seat = toupper(*seat);
        while (id < n)
        {
            if (strcmp(seat, (ps + id)->seat_id) == 0)
            {
                find = true;
                break;
            }
            id++;
        }
        if (find && (ps + id)->marked == false) //防止输入已分配座位 
        {
            printf("Please input first name: ");
            s_gets((ps + id)->fname, n);
            printf("Please input last name: ");
            s_gets((ps + id)->lname, n);
            (ps + id)->marked = true;
            if ((fp = fopen(fname, "r+b")) == NULL)
            {
                fprintf(stderr, "Can not open %s.\n", fname);
                exit(EXIT_FAILURE);
            }
            fseek(fp, id * size, SEEK_SET);
            fwrite((ps + id), size, 1, fp);
            if (fclose(fp) != 0)
            {
                fprintf(stderr, "Can not close file %s.\n", fname);
                exit(EXIT_FAILURE);
            }
            printf("Saved!\n");
        }
        else
        {
            if (*seat != '\0') 
                printf("Not found!\n");
            else
                printf("Opraton canceled!\n");
        }
    }
    else
        printf("No empty seat!\n");    
} 

void delete_seat(SEAT * ps, char * fname, int n)
{
    int i, count = 0, id = 0; 
    char seat[LEN];
    bool find = false;
    int size = sizeof(SEAT);
    FILE * fp;
    
    for (i = 0; i < n; i++)
        if ((ps + i)->marked == true)
        {
            if (i == 0)
                printf("\nAssigned seats: \n");
            printf("Name: %s %s\n", (ps + i)->fname, (ps + i)->lname);
            printf("ID: %s\n", (ps + i)->seat_id);
            count++;
        }
    if (count)
    {
        printf("Input the ID to delete(empty to quit): ");
        s_gets(seat, n);
        *seat = toupper(*seat);
        while (id < n)
        {
            if (strcmp(seat, (ps + id)->seat_id) == 0)
            {
                find = true;
                break;
            }
            id++;
        }
        if (find && (ps + id)->marked == true) //防止输入未分配座位 
        {
            (ps + id)->marked = false;
            if ((fp = fopen(fname, "r+b")) == NULL)
            {
                fprintf(stderr, "Can not open %s.\n", fname);
                exit(EXIT_FAILURE);
            }
            fseek(fp, id * size, SEEK_SET);
            fwrite((ps + id), size, 1, fp);
            if (fclose(fp) != 0)
            {
                fprintf(stderr, "Can not close file %s.\n", fname);
                exit(EXIT_FAILURE);
            }
            printf("Saved!\n");
        }
        else
        {
            if (*seat != '\0') 
                printf("Not found!\n");
            else
                printf("Opraton canceled!\n");
        }
    }
    else
        puts("No assigned seat!\n");
} 

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n'); //查找换行符 
        if (find)                //如果地址不为NULL 
            *find = '\0';        // 在此处放置一个空字符 
        else
            while (getchar() != '\n') // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

void eatline(void)
{
    while (getchar() != '\n')
        continue;
}

输出结果:

题目9,方法:按照要求操作文件和结构体。与题目8类似,不过多了几个文件。该项目包括2个头文件及3个源文件。

check.h:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#define WRONG 100

void wait(void);//暂停打印提示信息 
void consumer(char *, int *);//清空缓冲区并保存清空的字符 
bool character_check(char *, int *); //检测是否有非空字符并清空第一个非空字符及之前的缓冲区 
char choose_check(int, int, char *, void (*)(int)); //将输入限制在合法区间并返回输入值
void show_menu1(int); //打印一级菜单 
void show_menu2(int); //打印二级菜单 

check.c:

#include "check.h"

void show_menu1(int m)
{
    puts("****************************************");
    if (m)
        puts("TOP MENU\n");
    puts("To choose a airplan:");
    puts("a) Flight 102");
    puts("b) Flight 311");
    puts("c) Flight 444");
    puts("d) Flight 519");
    puts("q) Quit");
}

void show_menu2(int num)
{
    puts("****************************************");
    printf("FLIGHT %d\n", num);
    puts("To choose a function, enter lts letter lable:");
    puts("a) Show number of empty seats");
    puts("b) Show list of empty seats");
    puts("c) Show alphabetical list of seats");
    puts("d) Assign a customer to a seats");
    puts("e) Delete a seat assignment");
    puts("f) Show state of the flight");
    puts("g) Quit");
}

void wait(void)
{
    char ch;
    
    printf("Enter to continue...");
    while ((ch = getchar()) != '\n')
        continue;    
}

void consumer(char * wrong, int * n)
{
    char cha;
    
    while ((cha = getchar()) != '\n')
        *(wrong + (*n)++) = cha;
}

bool character_check(char * wrong, int * n)
{
    char ch2;
    
    while ((ch2 = getchar()) != '\n') //第一个非空字符为回车,则读走回车 
    {
        *(wrong + (*n)++) = ch2;
        if (ch2 != '\t' && ch2 != ' ') //若第一个非空字符非回车,回车不被读走 
            return true;
    }
    
    return false;
}

char choose_check(int m, int n, char * str, void (*pfun) (int))
{
    char ch1; // 转换小写后的第一个非空字符 
    char o_ch1; //保存原始第一个非空字符 
    char notice[n];
    int num = 1;
    int * count = &num;
    
    pfun(m);
    printf("Enter a character to choose: ");
    // 防止第一个非空合法字符后出现第二个非空字符,例如assss 
    while (strchr(str, (ch1 = tolower(o_ch1 = getchar()))) == NULL || character_check(notice, count) == true)
    {
        if (ch1 == ' ' || ch1 == '\n' || ch1 == '\t') // 使至少第一个非空字符被ch1获得 
            continue;
        else if (character_check(notice, count) == true) // 防止出现 assss 这样的输入,即之前非法,之后合法,以及清空非空白字符缓冲区 
            consumer(notice, count); // 输入a2时判断返回false,不执行此步(此时所有字符包括回车均已被读走) 
        *notice = o_ch1;
        printf("%s is illegal, try again: ", notice); 
        memset(notice, 0 ,sizeof(notice)); // 初始化字符串数组 
        num = 1; // 重置计数 
    }
    
    return ch1;
}

airplan.h:

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#define LEN 20
#define N 12

typedef struct {
    char seat_id[LEN]; // 座位编号 
    bool marked;       // 是否预定 
    char fname[LEN];   // 名 
    char lname[LEN];   // 姓 
} SEAT;

void initiate(SEAT *, char *, int);     // 初始化数据 
int show_emnum(SEAT *, int);            // 显示空座位的数量
void show_emlist(SEAT *, int);          // 显示空座位列表 
void show_state(SEAT *, int);           // 显示座位情况 
void show_alplist(SEAT *, int);         // aplphabet 顺序输出座位列表 
void assign_seat(SEAT *, char *, int);  // 为一位客户分配座位 
void delete_seat(SEAT *, char *, int);  // 为一位客户取消座位 
char * s_gets(char * st, int n);
void eatline(void);
void second_menu(int, SEAT *, char *, int);

airplan.c:

#include "airplan.h"
#include "check.h"

void initiate(SEAT * ps, char * data_file, int n)
{
    int i = 0;
    int size = sizeof(SEAT);
    FILE * fp;
    
    if ((fp = fopen(data_file, "r+b")) == NULL) //如果文件不存在,则初始化 
    {
        if ((fp = fopen(data_file, "w+b")) == NULL)
        {
            fprintf(stderr, "Can not creat file %s.\n", data_file);
            exit(EXIT_FAILURE);
        }
        SEAT seat[N] = {
            { "C01", false, "", "" },
            { "C02", false, "", "" },
            { "C03", false, "", "" },
            { "B01", false, "", "" },
            { "B02", false, "", "" },
            { "B03", false, "", "" },
            { "A01", false, "", "" },
            { "A02", false, "", "" },
            { "A03", false, "", "" },
            { "D01", false, "", "" },
            { "D02", false, "", "" },
            { "D03", false, "", "" },
        };
        fwrite(seat, size, n, fp);
        if (fclose(fp) != 0)
        {
            fputs("Can not close file.\n", stderr);
            exit(EXIT_FAILURE);
        }
        if ((fp = fopen(data_file, "r+b")) == NULL)
        {
            fputs("Can not open file.\n", stderr);
            exit(EXIT_FAILURE);
        } 
    }
    while (i < N && fread(ps + i, size, 1, fp) == 1) // 将数据从文件中读入结构数组 
        i++;
    if (fclose(fp) != 0)
    {
        fputs("Can not close file.\n", stderr);
        exit(EXIT_FAILURE);
    }
} 

int show_emnum(SEAT * ps, int n)
{
    int i, num = 0; // 空座位的数量 
    
    for (i = 0; i < n; i++)
        if ((ps + i)->marked == false)
            num++;
    
    return num;
} 

void show_state(SEAT * ps, int n)
{
    int i, num_empty = 0, num_full = 0;
    
    putchar('\n');
    for (i = 0; i < n; i++)
        if ((ps + i)->marked == false)
        {
            if (num_empty == 0)
                printf("\nEmpty seats: \n");
            printf("%s ", (ps + i)->seat_id);
            num_empty++;
        }
    putchar('\n');
    if(!num_empty)
        printf("No empty seat!\n");
    else
        printf("Totally %d empty seats.", num_empty);
    putchar('\n');
    for (i = 0; i < n; i++)
        if ((ps + i)->marked == true)
        {
            if (num_full == 0)
                printf("\nAssigned seats: \n");
            printf("Name: %s %s\n", (ps + i)->fname, (ps + i)->lname);
            printf("ID: %s\n", (ps + i)->seat_id);
            num_full++;
        }
    if(!num_full)
        printf("No assigned seat!\n");
    else
        printf("Totally %d full seats.", num_full);
    putchar('\n');
    
} 

void show_emlist(SEAT * ps, int n)
{
    int i, num = 0;
    
    putchar('\n');
    for (i = 0; i < n; i++)
        if ((ps + i)->marked == false)
        {
            printf("%s ", (ps + i)->seat_id);
            num++;
        }
    putchar('\n');
    if (!num)
        printf("No empty seat!\n");        
}

void show_alplist(SEAT * ps, int n)
{
    SEAT * alpha[n];
    SEAT * temp; 
    int i, j;
    
    for (i = 0; i < n; i++) //获取结构地址便于操作 
        alpha[i] = (ps + i);
    for (i = 0; i < n - 1; i++)
        for (j = i+ 1; j < n; j++)
            if (strcmp(alpha[i]->seat_id, alpha[j]->seat_id) > 0)
            {
                temp = alpha[i];
                alpha[i] = alpha[j];
                alpha[j] = temp;    
            }
    putchar('\n');
    for (i = 0; i < n; i++)
        printf("%s ", (*(alpha + i))->seat_id); // -> 的优先级高于 *,因此加括号 
    putchar('\n');
}

void assign_seat(SEAT * ps, char * fname, int n)
{
    char seat[LEN];
    int id = 0, em_num;
    bool find = false;
    int size = sizeof(SEAT);
    FILE * fp;
    
    em_num = show_emnum(ps, n);
    if (em_num)
    {
        printf("\nEmpty seats:\n");
        show_emlist(ps, n);
        printf("Input the ID(empty to quit): ");
        s_gets(seat, n);
        *seat = toupper(*seat);
        while (id < n)
        {
            if (strcmp(seat, (ps + id)->seat_id) == 0)
            {
                find = true;
                break;
            }
            id++;
        }
        if (find && (ps + id)->marked == false) //防止输入已分配座位 
        {
            printf("Please input first name: ");
            s_gets((ps + id)->fname, n);
            printf("Please input last name: ");
            s_gets((ps + id)->lname, n);
            (ps + id)->marked = true;
            if ((fp = fopen(fname, "r+b")) == NULL)
            {
                fprintf(stderr, "Can not open %s.\n", fname);
                exit(EXIT_FAILURE);
            }
            fseek(fp, id * size, SEEK_SET);
            fwrite((ps + id), size, 1, fp);
            if (fclose(fp) != 0)
            {
                fprintf(stderr, "Can not close file %s.\n", fname);
                exit(EXIT_FAILURE);
            }
            printf("Saved!\n");
        }
        else
        {
            if (*seat != '\0') 
                printf("Not found!\n");
            else
                printf("Operaton canceled!\n");
        }
    }
    else
        printf("No empty seat!\n");    
} 

void delete_seat(SEAT * ps, char * fname, int n)
{
    int i, count = 0, id = 0; 
    char seat[LEN];
    bool find = false;
    int size = sizeof(SEAT);
    FILE * fp;
    
    for (i = 0; i < n; i++)
        if ((ps + i)->marked == true)
        {
            if (i == 0)
                printf("\nAssigned seats: \n");
            printf("Name: %s %s\n", (ps + i)->fname, (ps + i)->lname);
            printf("ID: %s\n", (ps + i)->seat_id);
            count++;
        }
    if (count)
    {
        printf("Input the ID to delete(empty to quit): ");
        s_gets(seat, n);
        *seat = toupper(*seat);
        while (id < n)
        {
            if (strcmp(seat, (ps + id)->seat_id) == 0)
            {
                find = true;
                break;
            }
            id++;
        }
        if (find && (ps + id)->marked == true) //防止输入未分配座位 
        {
            (ps + id)->marked = false;
            if ((fp = fopen(fname, "r+b")) == NULL)
            {
                fprintf(stderr, "Can not open %s.\n", fname);
                exit(EXIT_FAILURE);
            }
            fseek(fp, id * size, SEEK_SET);
            fwrite((ps + id), size, 1, fp);
            if (fclose(fp) != 0)
            {
                fprintf(stderr, "Can not close file %s.\n", fname);
                exit(EXIT_FAILURE);
            }
            printf("Saved!\n");
        }
        else
        {
            if (*seat != '\0') 
                printf("Not found!\n");
            else
                printf("Operaton canceled!\n");
        }
    }
    else
        puts("No assigned seat!\n");
} 

void second_menu(int num, SEAT * p, char * fname, int n)
{
    char choose2;
    
    while ((choose2 = choose_check(num, WRONG, "abcedfg", show_menu2)) != 'g')
    {
        switch (choose2)
        {
            case 'a':
                printf("\nCurrently have %d of empty seats.\n", show_emnum(p, n));
                wait();
                break;
            case 'b':
                show_emlist(p, n);
                wait();
                break;
            case 'c':
                show_alplist(p, n);
                wait();
                break;
            case 'd':
                assign_seat(p, fname, n);
                wait();
                break; 
            case 'e':
                delete_seat(p, fname, n);
                wait();
                break;
            case 'f':
                show_state(p, n);
                wait();
                break;
            case 'g':
                break;
        }
        system("cls");
    }
}

char * s_gets(char * st, int n)
{
    char * ret_val;
    char * find;
    
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n'); //查找换行符 
        if (find)                //如果地址不为NULL 
            *find = '\0';        // 在此处放置一个空字符 
        else
            while (getchar() != '\n') // 处理多余字符 
                continue;
    }
    
    return ret_val;
}

void eatline(void)
{
    while (getchar() != '\n')
        continue;
}

main.c:

#include "check.h"
#include "airplan.h"

int main(void)
{
    char choose1; // 一级菜单 
    char filename1[LEN] = "flight1.dat";
    char filename2[LEN] = "flight2.dat";
    char filename3[LEN] = "flight3.dat";
    char filename4[LEN] = "flight4.dat";
    SEAT seats1[N];
    SEAT seats2[N];
    SEAT seats3[N];
    SEAT seats4[N];
    
    initiate(seats1, filename1, LEN);
    initiate(seats2, filename2, LEN);
    initiate(seats3, filename3, LEN);
    initiate(seats4, filename4, LEN);
    while ((choose1 = choose_check(1, WRONG, "abcdq", show_menu1)) != 'q')
    {
        system("cls");
        switch (choose1)
        {
            case 'a':
                second_menu(102, seats1, filename1, N);
                break;
            case 'b':
                second_menu(311, seats2, filename2, N);
                break;
            case 'c':
                second_menu(444, seats3, filename3, N);
                break;
            case 'd':
                second_menu(519, seats4, filename4, N);
                break;
            case 'q':
                break;
        }
        system("cls");    
    }
    
    return 0;
}

输出结果:

题目10,方法:通过函数指针数组实现菜单。函数指针在前两个项目中有所应用。该项目包括1个头文件和2个源文件。

check.h:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#define WRONG 100

typedef void (* pfunc)(void);
void wait(void);                        // Pause printing prompt
void consumer(char *, int *);           // Empty the buffer and save the characters in the buffer
bool character_check(char *, int *);    // Detect whether there are non null characters and clear the first non null character and the buffer before it
char choose_check(int, char *, pfunc);  // Limit the input to the legal range and return the input value
void show_menu(void);                   // Print the first level menu

check.c:

#include "check.h"

void show_menu(void)
{
    puts("****************************************");
    puts("To choose a function:");
    puts("a) Function 1");
    puts("b) Function 2");
    puts("q) Quit");
}

void wait(void)
{
    char ch;
    
    printf("Enter to continue...");
    while ((ch = getchar()) != '\n')
        continue;    
}

void consumer(char * wrong, int * n)
{
    char cha;
    
    while ((cha = getchar()) != '\n')
        *(wrong + (*n)++) = cha;
}

bool character_check(char * wrong, int * n)
{
    char ch2;
    
    while ((ch2 = getchar()) != '\n')   // If the first non null character is a carriage return, read the carriage return
    {
        *(wrong + (*n)++) = ch2;
        if (ch2 != '\t' && ch2 != ' ')  // If the first non null character is not a carriage return character, the carriage return character will not be read away 
            return true;
    }
    
    return false;
}

char choose_check(int n, char * str, pfunc pfun)
{
    char ch1;            // Save the first non null character after converting to lowercase
    char o_ch1;          // Save the original first non null character 
    char notice[n];
    int num = 1;
    int * count = &num;
    
    pfun();
    printf("Enter a character to choose: ");
    // Prevent the second non null character after the first non null legal character, such as assss
    while (strchr(str, (ch1 = tolower(o_ch1 = getchar()))) == NULL || character_check(notice, count) == true)
    {
        if (ch1 == ' ' || ch1 == '\n' || ch1 == '\t')     // Make at least the first non null character obtained by ch1
            continue;
        else if (character_check(notice, count) == true)  // Prevent the occurrence of input such as assss, which is illegal before and legal after, and clear the non blank character buffer
            consumer(notice, count);                      // When inputting a2, it is judged to return false, and this step is not executed (at this time, all characters including the Enter key have been read away) 
        *notice = o_ch1;
        printf("%s is illegal, try again: ", notice); 
        memset(notice, 0 ,sizeof(notice));                // Initialize string array 
        num = 1;                                          // Reset Count 
    }
    
    return ch1;
}

main.c:

#include "check.h"

void func1(void);
void func2(void);
void show(pfunc);

int main(void)
{
    char choose;
    pfunc func[2] = { func1, func2 };
    
    while ((choose = choose_check(WRONG, "abq", show_menu)) != 'q')
    {
        switch (choose)
        {
            case 'a':
                show(func[0]);
                wait();
                break;
            case 'b':
                show(func[1]);
                wait();
                break;
            case 'q':
                break;    
        }
        system("cls");
    }
    
    return 0;
}

void func1(void)
{
    printf("I am Function 1\n");
}

void func2(void)
{
    printf("I am Function 2\n");
}

void show(pfunc pf)
{
    pf();
}

输出结果:

题目11,方法:使用包含函数指针作为参数的函数。示例代码14_11.c:

#include <stdio.h>
#include <math.h>
#define N 4
#define LEN 5
#define MAX 10 

typedef double (* pfun) (double);
double func1(double);
double func2(double);
void transform(const double [], double [], int, pfun);
void show_array(const double [], int); 

int main(void)
{
    pfun pf_array[N] = { cbrt, sqrt, func1, func2 };
    char func_name[N][MAX] = { "cbrt", "sqrt", "func1", "func2" };
    const double original[LEN] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
    double target[LEN] = { 0.0 };
    int i;
    
    printf("Original array:\n");
    show_array(original, LEN);
    printf("Target array:\n");
    show_array(target, LEN);
    for (i = 0; i < N; i++)
    {
        printf("After %s function, target array:\n", func_name[i]);
        transform(original, target, LEN, pf_array[i]);
        show_array(target, LEN);
    }
    
    return 0;
}

void show_array(const double arr[], int n)
{
    int i;
    
    for (i = 0; i < n; i++)
        printf("%.2f ", arr[i]);
    puts("\n");
}

void transform(const double orig[], double targ[], int n, pfun pf)
{
    int i;
    
    for (i = 0; i < n; i++)
        targ[i] = pf(orig[i]);
}

double func1(double d_num)
{
    return 2.0 * d_num;
}

double func2(double d_num)
{
    return d_num + 10.0;
}

输出结果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值