C Primer Plus 第十四章 课后答案

目录

 

复习题

1.下面的结构模板有什么问题:

structure { char itable; int num[20]; char * togs }

2.下面是程序的一部分,输出是什么

3.设计一个结构模板储存一个月份名、该月份名的3个字母缩写、该月的天数以及月份号

4.定义一个数组,内含12个结构(第3题的结构类型)并初始化为一个年份(非闰年)

5.编写一个函数,用户提供月份号,该函数就返回一年中到该月为止(包括该月)的总天数。假设在所有函数的外部声明了第3题的结构模版和一个该类型结构的数组

6.

a.假设有下面的 typedef,声明一个内含 10 个指定结构的数组。然后,单独给成员赋值(或等价字符串),使第3个元素表示一个焦距长度有500mm,孔径为f/2.0的Remarkata镜头。

扫描二维码关注公众号,回复: 3466002 查看本文章

b.重写a,在声明中使用一个待指定初始化器的初始化列表,而不是对每个成员单独赋值

7.考虑下面程序片段:

a.下面的语句分别打印什么?

printf("%d\n", deb.limbs);

printf("%s\n", pb->type);

printf("%s\n", pb->type + 2);

b.如何用结构表示法(两种方法)表示"Gwolkapwolk"?

c.编写一个函数,以bem结构的地址作为参数,并以下面的形式输出结构的内容(假定结构模板在一个名为starfolk.h的头文件中): Berbnazel Gwolkapwolk is a 6-limbed Arcturan.

8.考虑下面的声明:

a.用willie标识符标识willie结构的born成员。

b.用pt标识符标识willie结构的born成员。

c.调用scanf()读入一个用willie标识符标识的born成员的值。

d.调用scanf()读入一个用pt标识符标识的born成员的值。

e.调用scanf()读入一个用willie标识符标识的name成员中lname成员的值。

f.调用scanf()读入一个用pt标识符标识的name成员中lname成员的值。

g.构造一个标识符,标识willie结构变量所表示的姓名中名的第3个字母(英文的名在前)。

h.构造一个表达式,表示willie结构变量所表示的名和姓中的字母总数。

9.定义一个结构模板以储存这些项:汽车名、马力、EPA(美国环保局)城市交通MPG(每加仑燃料行驶的英里数)评级、轴距和出厂年份。使用car作为该模版的标记。

10.假设有如下结构:

a.设计一个函数,接受struct gas类型的参数。假设传入的结构包含distance和gals信息。该函数为mpg成员计算正确的值,并把值返回该结构。

b.设计一个函数,接受struct gas类型的参数。假设传入的结构包含distance和gals信息。该函数为mpg成员计算正确的值,并把该值赋给合适的成员。

11.声明一个标记为choices的枚举,把枚举常量no、yes和maybe分别设置为0、1、2

12.声明一个指向函数的指针,该函数返回指向char的指针,接受一个指向char的指针和一个char类型的值

13.声明4个函数,并初始化一个指向这些函数的指针数组。每个函数都接受两个double类型的参数,返回double类型的值。另外,用两种方法使用该数组调用带10.0和2.5实参的第2个函数

编程练习

1.重新编写复习题 5,用月份名的拼写代替月份号(别忘了使用 strcmp())。在一个简单的程序中测试该函数

2.编写一个函数,提示用户输入日、月和年。月份可以是月份号、月份名或月份名缩写。然后该程序应返回一年中到用户指定日子(包括这一天)的总天数

3.修改程序清单 14.2 中的图书目录程序,使其按照输入图书的顺序输出图书的信息,然后按照标题字母的声明输出图书的信息,最后按照价格的升序输出图书的信息。

4.编写一个程序,创建一个有两个成员的结构模板:

a.第1个成员是社会保险号,第2个成员是一个有3个成员的结构,第1个成员代表名,第2个成员代表中间名,第3个成员表示姓。创建并初始化一个内含5个该类型结构的数组。该程序以下面的格式打印数据:

Dribble, Flossie M.–– 302039823 如果有中间名,只打印它的第1个字母,后面加一个点(.);如果没有中间名,则不用打印点。编写一个程序进行打印,把结构数组传递给这个函数。

b.修改a部分,传递结构的值而不是结构的地址

5.编写一个程序满足下面的要求。

a.外部定义一个有两个成员的结构模板name:一个字符串储存名,一个字符串储存姓。

b.外部定义一个有3个成员的结构模板student:一个name类型的结构,一个grade数组储存3个浮点型分数,一个变量储存3个分数平均数。

c.在main()函数中声明一个内含CSIZE(CSIZE = 4)个student类型结构的数组,并初始化这些结构的名字部分。用函数执行g、e、f和g中描述的任务。

d.以交互的方式获取每个学生的成绩,提示用户输入学生的姓名和分数。把分数储存到grade数组相应的结构中。可以在main()函数或其他函数中用循环来完成。

e.计算每个结构的平均分,并把计算后的值赋给合适的成员。

f.打印每个结构的信息。

g.打印班级的平均分,即所有结构的数值成员的平均值。

6.一个文本文件中保存着一个垒球队的信息。每行数据都是这样排列:

4 Jessie Joybat 5 2 1 1

第1项是球员号,为方便起见,其范围是0~18。第2项是球员的名。第3项是球员的姓。名和姓都是一个单词。第4项是官方统计的球员上场次数。接着3项分别是击中数、走垒数和打点(RBI)。文件可能包含多场比赛的数据,所以同一位球员可能有多行数据,而且同一位球员的多行数据之间可能有其他球员的数据。编写一个程序,把数据储存到一个结构数组中。该结构中的成员要分别表示球员的名、姓、上场次数、击中数、走垒数、打点和安打率(稍后计算)。可以使用球员号作为数组的索引。该程序要读到文件结尾,并统计每位球员的各项累计总和。

世界棒球统计与之相关。例如,一次走垒和触垒中的失误不计入上场次数,但是可能产生一个RBI。但是该程序要做的是像下面描述的一样读取和处理数据文件,不会关心数据的实际含义。

要实现这些功能,最简单的方法是把结构的内容都初始化为零,把文件中的数据读入临时变量中,然后将其加入相应的结构中。程序读完文件后,应计算每位球员的安打率,并把计算结果储存到结构的相应成员中。计算安打率是用球员的累计击中数除以上场累计次数。这是一个浮点数计算。最后,程序结合整个球队的统计数据,一行显示一位球员的累计数据。

7.修改程序清单 14.14,从文件中读取每条记录并显示出来,允许用户删除记录或修改记录的内容。如果删除记录,把空出来的空间留给下一个要读入的记录。要修改现有的文件内容,必须用"r+b"模式,而不是"a+b"模式。而且,必须更加注意定位文件指针,防止新加入的记录覆盖现有记录。最简单的方法是改动储存在内存中的所有数据,然后再把最后的信息写入文件。跟踪的一个方法是在book结构中添加一个成员表示是否该项被删除

8.巨人航空公司的机群由 12 个座位的飞机组成。它每天飞行一个航班。根据下面的要求,编写一个座位预订程序。

a.该程序使用一个内含 12 个结构的数组。每个结构中包括:一个成员表示座位编号、一个成员表示座位是否已被预订、一个成员表示预订人的名、一个成员表示预订人的姓。

b.该程序显示下面的菜单:

c.该程序能成功执行上面给出的菜单。选择d)和e)要提示用户进行额外输入,每个选项都能让用户中止输入。

d.执行特定程序后,该程序再次显示菜单,除非用户选择f)。

9.巨人航空公司(编程练习 8)需要另一架飞机(容量相同),每天飞 4 班(航班 102、311、444 和519)。把程序扩展为可以处理4个航班。用一个顶层菜单提供航班选择和退出。选择一个特定航班,就会出现和编程练习8类似的菜单。但是该菜单要添加一个新选项:确认座位分配。而且,菜单中的退出是返回顶层菜单。每次显示都要指明当前正在处理的航班号。另外,座位分配显示要指明确认状态

10.编写一个程序,通过一个函数指针数组实现菜单。例如,选择菜单中的 a,将激活由该数组第 1个元素指向的函数

11.编写一个名为transform()的函数,接受4个参数:内含double类型数据的源数组名、内含double类型数据的目标数组名、一个表示数组元素个数的int类型参数、函数名(或等价的函数指针)。transform()函数应把指定函数应用于源数组中的每个元素,并把返回值储存在目标数组中。例如:

transform(source, target, 100, sin);

该声明会把target[0]设置为sin(source[0]),等等,共有100个元素。在一个程序中调用transform()4次,以测试该函数。分别使用math.h函数库中的两个函数以及自定义的两个函数作为参数


复习题

1.下面的结构模板有什么问题:

structure { char itable; int num[20]; char * togs }

  1. 关键词是struct
  2. 花括号后面缺少分号

2.下面是程序的一部分,输出是什么

#include <stdio.h> 

struct house 
{ 
    float sqft; 
    int rooms; 
    int stories; 
    char address[40]; 
}; 

int main(void) 
{ 
    struct house fruzt = {1560.0, 6, 1, "22 Spiffo Road"}; 
    struct house *sign; 
    sign = &fruzt; 
    printf("%d %d\n", fruzt.rooms, sign->stories); 
    printf("%s \n", fruzt.address); 
    printf("%c %c\n", sign->address[3], fruzt.address[4]); 
    return 0; 
}

6 1

22 Spiffo Road

S p

3.设计一个结构模板储存一个月份名、该月份名的3个字母缩写、该月的天数以及月份号

struct month
{
    char name[15];
    char ab[4];//留一个位置给\0
    int days;
    int num;
};

4.定义一个数组,内含12个结构(第3题的结构类型)并初始化为一个年份(非闰年)

struct month list[12] =
            {
                    {
                        "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
                    }
            };

5.编写一个函数,用户提供月份号,该函数就返回一年中到该月为止(包括该月)的总天数。假设在所有函数的外部声明了第3题的结构模版和一个该类型结构的数组

int DAYS(int n)
{
    int sum = 0;
    for (int i = 0; i < n; ++i) {
        sum += list[i].days;
    }
    return sum;
}

6.

a.假设有下面的 typedef,声明一个内含 10 个指定结构的数组。然后,单独给成员赋值(或等价字符串),使第3个元素表示一个焦距长度有500mm,孔径为f/2.0的Remarkata镜头。

LENS list[10];
list[2].foclen = 500;
list[2].fstop = 2.0;
strcpy(list[2].brand, "Remarkata");

b.重写a,在声明中使用一个待指定初始化器的初始化列表,而不是对每个成员单独赋值

LENS list[10] = {[3] = {500, 2.0, "Remarkata"}};

7.考虑下面程序片段:

struct name {
    char first[20];
    char last[20];
};
struct bem {
    int limbs;
    struct name title;
    char type[30];
};

struct bem * pb;
struct bem deb = { 6, { "Berbnazel", "Gwolkapwolk" }, "Arcturan" };
pb = &deb;

a.下面的语句分别打印什么?

printf("%d\n", deb.limbs);

printf("%s\n", pb->type);

printf("%s\n", pb->type + 2);

6

Arcturan

cturan

b.如何用结构表示法(两种方法)表示"Gwolkapwolk"?

deb.title.last

pb->title.last

c.编写一个函数,以bem结构的地址作为参数,并以下面的形式输出结构的内容(假定结构模板在一个名为starfolk.h的头文件中): Berbnazel Gwolkapwolk is a 6-limbed Arcturan.

void Print(const struct bem *a)
{
    printf("%s %s is a %d-limbed %s\n", a->title.first, a->title.last, a->limbs, a->type);
}

8.考虑下面的声明:

struct fullname 
{ 
    char fname[20]; 
    char lname[20]; 
}; 
struct bard 
{ 
    struct fullname name; 
    int born; 
    int died; 
}; 

struct bard willie; 
struct bard *pt = &willie;

a.用willie标识符标识willie结构的born成员。

willie.born

b.用pt标识符标识willie结构的born成员。

pt->born

c.调用scanf()读入一个用willie标识符标识的born成员的值。

scanf("%d", willie.born);

d.调用scanf()读入一个用pt标识符标识的born成员的值。

scanf("%d", pt->born);

e.调用scanf()读入一个用willie标识符标识的name成员中lname成员的值。

scanf("%s", willie.name.lname);

f.调用scanf()读入一个用pt标识符标识的name成员中lname成员的值。

scanf("%s", pt->name.lname);

g.构造一个标识符,标识willie结构变量所表示的姓名中名的第3个字母(英文的名在前)。

willie.name.fname[2]

h.构造一个表达式,表示willie结构变量所表示的名和姓中的字母总数。

strlen(willie.name.fname) + strlen(willie.name.lname)

9.定义一个结构模板以储存这些项:汽车名、马力、EPA(美国环保局)城市交通MPG(每加仑燃料行驶的英里数)评级、轴距和出厂年份。使用car作为该模版的标记。

struct car
{
    char name[30];
    float horsepow;
    float MPG;
    float wbase;
    int year;
};

10.假设有如下结构:

struct gas 
{ 
    float distance; 
    float gals; 
    float mpg; 
};

a.设计一个函数,接受struct gas类型的参数。假设传入的结构包含distance和gals信息。该函数为mpg成员计算正确的值,并把值返回该结构。

struct gas getmpg(struct gas a)
{
    if(a.gals > 0)
    {
        a.mpg = a.distance / a.gals;
    }
    else
    {
        a.mpg = -1.0;
    }
    return a;
}

b.设计一个函数,接受struct gas类型的参数。假设传入的结构包含distance和gals信息。该函数为mpg成员计算正确的值,并把该值赋给合适的成员。

struct gas getmpg(struct gas *a)
{
    if(a->gals > 0)
    {
        a->mpg = a->distance / a->gals;
    }
    else
    {
        a->mpg = -1.0;
    }
}

11.声明一个标记为choices的枚举,把枚举常量no、yes和maybe分别设置为0、1、2

enum choices = {no, yes, maybe};

12.声明一个指向函数的指针,该函数返回指向char的指针,接受一个指向char的指针和一个char类型的值

char* (*func)(char*, char);

13.声明4个函数,并初始化一个指向这些函数的指针数组。每个函数都接受两个double类型的参数,返回double类型的值。另外,用两种方法使用该数组调用带10.0和2.5实参的第2个函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

double f1(double, double);
double f2(double, double);
double f3(double, double);
double f4(double, double);

double (*func[4])(double, double) = {f1, f2, f3, f4};

int main(void)
{
    (*func[1])(10, 2.5);
    func[1](10, 2.5);
    return 0;
}

编程练习

1.重新编写复习题 5,用月份名的拼写代替月份号(别忘了使用 strcmp())。在一个简单的程序中测试该函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct month
{
    char name[15];
    char ab[4];//留一个位置给\0
    int days;
    int num;
}list[12] = 
        {
                {"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 a[])
{
    int sum = 0;
    for (int i = 0; i < 12; ++i) {
        sum += list[i].days;
        if(!strcmp(list[i].name, a))
        {
            return sum;
        }
    }
    return sum;
}

int main(void)
{
    printf("%d\n", days("July"));
    printf("%d\n", days("November"));
    return 0;
}

2.编写一个函数,提示用户输入日、月和年。月份可以是月份号、月份名或月份名缩写。然后该程序应返回一年中到用户指定日子(包括这一天)的总天数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

struct month
{
    char ab[4];
    int days;
    int num;
}list[12] =
        {
                {"JAN", 31, 1},
                {"FEB", 28, 2},
                {"MAR", 31, 3},
                {"APR", 30, 4},
                {"MAY", 31, 5},
                {"JUN", 30, 6},
                {"JUL", 31, 7},
                {"AUG", 31, 8},
                {"SEP", 30, 9},
                {"OCT", 31, 10},
                {"NOV", 30, 11},
                {"DEC", 31, 12}
        };



int main(void)
{
    int year, month, day, flag = 0;
    char mon[15];
    char mid[4];
    int sum = 0;
    printf("Input the year num:");
    scanf("%d", &year);
    if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
    {
        list[1].days = 29;
    }
    printf("Inpur the month:");
    if(scanf("%d", &month) == 1) {}
    else if(scanf("%s", mon) == 1)
    {
        mid[0] = toupper(mon[0]);
        mid[1] = toupper(mon[1]);
        mid[2] = toupper(mon[2]);
        mid[3] = '\0';
        for (int i = 0; i < 12; ++i) {
            if(!strcmp(mid, list[i].ab))
            {
                month = i + 1;
            }
        }
    }
    printf("Input the day:");
    scanf("%d", &day);
    for (int j = 0; j < month - 1; ++j) {
        sum += list[j].days;
    }
    sum += day;
    printf("%d days in all\n", sum);
    return 0;
}

3.修改程序清单 14.2 中的图书目录程序,使其按照输入图书的顺序输出图书的信息,然后按照标题字母的声明输出图书的信息,最后按照价格的升序输出图书的信息。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char * s_gets(char * st, int n);
#define MAXTITL  40
#define MAXAUTL  40
#define MAXBKS 100    /* 书籍的最大数量 */
struct book           /* 简历 book 模板  */
{
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};

int (* funcp)(const void*, const void*);

int sortByAscii(const void* a, const void* b)//格式要符合qsort,函数内再转换
{
    if(strcmp(((struct book*)a)->title, ((struct book*)b)->title) > 0)
    {
        return 0;
    }
    return 1;
}

int sortByPrice(const void* a,const void* b)
{
    if(((struct book*)a)->value < ((struct book*)b)->value)
    {
        return 0;
    }
    return 1;
}

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);
        printf("Here is the list sorted by ASCII of your books:\n");
        funcp = sortByAscii;
        qsort(library, count == MAXBKS ? MAXBKS - 1 : count, sizeof(library[0]), funcp);//第二个参数应该用数组当前写入了数据长度,不然会是一堆乱码
        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 sorted by price of your books:\n");
        funcp = sortByPrice;
        qsort(library, count == MAXBKS ? MAXBKS - 1 : count, sizeof(library[0]), funcp);
        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;
}

4.编写一个程序,创建一个有两个成员的结构模板:

a.第1个成员是社会保险号,第2个成员是一个有3个成员的结构,第1个成员代表名,第2个成员代表中间名,第3个成员表示姓。创建并初始化一个内含5个该类型结构的数组。该程序以下面的格式打印数据:

Dribble, Flossie M.–– 302039823 如果有中间名,只打印它的第1个字母,后面加一个点(.);如果没有中间名,则不用打印点。编写一个程序进行打印,把结构数组传递给这个函数。

b.修改a部分,传递结构的值而不是结构的地址

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct mod
{
    char sid[30];
    struct
    {
        char fname[15];
        char mname[15];
        char lname[15];
    };
}list[5] =
        {
                {"302039823", {"Flossie", "Maa", "Dribble"}},
                {"302039823", {"Flossie", "Maa", "Dribble"}},
                {"302039823", {"Flossie", "Maa", "Dribble"}},
                {"302039823", {"Flossie", "Maa", "Dribble"}},
                {"302039823", {"Flossie", "Maa", "Dribble"}}
        };

void Print(struct mod a[])
{
    for (int i = 0; i < 5; ++i)
    {
        printf("%s,%s %c.--%s\n", a[i].lname, a[i].fname, a[i].mname[0], a[i].sid);
    }
}

void sPrint(struct mod a)
{
    printf("%s,%s %c.--%s\n", a.lname, a.fname, a.mname[0], a.sid);
}

int main(void)
{
    Print(list);
    for (int i = 0; i < 5; ++i) {
        sPrint(list[i]);
    }
    return 0;
}

5.编写一个程序满足下面的要求。

a.外部定义一个有两个成员的结构模板name:一个字符串储存名,一个字符串储存姓。

b.外部定义一个有3个成员的结构模板student:一个name类型的结构,一个grade数组储存3个浮点型分数,一个变量储存3个分数平均数。

c.在main()函数中声明一个内含CSIZE(CSIZE = 4)个student类型结构的数组,并初始化这些结构的名字部分。用函数执行g、e、f和g中描述的任务。

d.以交互的方式获取每个学生的成绩,提示用户输入学生的姓名和分数。把分数储存到grade数组相应的结构中。可以在main()函数或其他函数中用循环来完成。

e.计算每个结构的平均分,并把计算后的值赋给合适的成员。

f.打印每个结构的信息。

g.打印班级的平均分,即所有结构的数值成员的平均值。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CSIZE 4

struct name
{
    char fname[30];
    char lname[30];
};

struct student
{
    struct name sname;
    float grade[3];
    float average;
};

void getGrade(struct student a[])
{
    int n = 0, flag = 1;
    char f[30], l[30];
    int i;
    while(flag)
    {
        printf("Input the name:");
        scanf("%s %s", f, l);
        for (i = 0; i < CSIZE; ++i)
        {
            if(!strcmp(a[i].sname.fname, f) && !strcmp(a[i].sname.lname, l))
            {
                if(a[i].grade[0] != 0)
                {
                    printf("This student has been registered\n");
                    break;
                }
                printf("Input 3 grade for %s%s:", f, l);
                scanf("%f %f %f", &a[i].grade[0], &a[i].grade[1], &a[i].grade[2]);
                n++;
                if(n == CSIZE)
                {
                    flag = 0;
                }
                break;
            }
        }
        if(i == CSIZE)
        {
            printf("Student %s%s is not found\n", f, l);
        }
    }
}

void getAverage(struct student a[])
{
    for (int i = 0; i < CSIZE; ++i) {
        a[i].average = (a[i].grade[0] + a[i].grade[1] + a[i].grade[2]) / 3;
    }
}

void Print(struct student a[])
{
    for (int i = 0; i < CSIZE; ++i) {
        printf("%s%s : %5.2f %5.2f %5.2f, average = %5.2f\n", a[i].sname.fname,
 a[i].sname.lname, a[i].grade[0], a[i].grade[1], a[i].grade[2], a[i].average);
    }
}

void APrint(struct student a[])
{
    float sum = 0.0;
    for (int i = 0; i < CSIZE; ++i) {
        sum += a[i].average;
    }
    printf("Class average is %.2f\n", sum / 4);
}

int main(void)
{
    struct student stu[CSIZE] = {
            {.sname = {"1", "2"}, .grade = {0.0, 0.0, 0.0}},
            {.sname = {"3", "4"}, .grade = {0.0, 0.0, 0.0}},
            {.sname = {"5", "6"}, .grade = {0.0, 0.0, 0.0}},
            {.sname = {"7", "8"}, .grade = {0.0, 0.0, 0.0}}
    };
    getGrade(stu);
    getAverage(stu);
    Print(stu);
    APrint(stu);
    return 0;
}
/*
1 2
1 2 3
3 4
4 5 6
5 6
7 8 9
7 8
10 11 12
*/

6.一个文本文件中保存着一个垒球队的信息。每行数据都是这样排列:

4 Jessie Joybat 5 2 1 1

第1项是球员号,为方便起见,其范围是0~18。第2项是球员的名。第3项是球员的姓。名和姓都是一个单词。第4项是官方统计的球员上场次数。接着3项分别是击中数、走垒数和打点(RBI)。文件可能包含多场比赛的数据,所以同一位球员可能有多行数据,而且同一位球员的多行数据之间可能有其他球员的数据。编写一个程序,把数据储存到一个结构数组中。该结构中的成员要分别表示球员的名、姓、上场次数、击中数、走垒数、打点和安打率(稍后计算)。可以使用球员号作为数组的索引。该程序要读到文件结尾,并统计每位球员的各项累计总和。

世界棒球统计与之相关。例如,一次走垒和触垒中的失误不计入上场次数,但是可能产生一个RBI。但是该程序要做的是像下面描述的一样读取和处理数据文件,不会关心数据的实际含义。

要实现这些功能,最简单的方法是把结构的内容都初始化为零,把文件中的数据读入临时变量中,然后将其加入相应的结构中。程序读完文件后,应计算每位球员的安打率,并把计算结果储存到结构的相应成员中。计算安打率是用球员的累计击中数除以上场累计次数。这是一个浮点数计算。最后,程序结合整个球队的统计数据,一行显示一位球员的累计数据。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

struct player
{
    int num;
    char fname[30];
    char lname[30];
    int scs;
    int jzs;
    int zls;
    int dd;
    float adl;
}list[19] = {
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
        {0, "", "", 0, 0, 0, 0, 0},
};

void mkfile()
{
    FILE *fp = fopen("data.txt", "w");
    if(fp == NULL)
    {
        fprintf(stderr, "Open failed\n");
        exit(EXIT_FAILURE);
    }
    int num, scs, jzs, zls, dd;
    char f[30], l[30], ch;
    srand((unsigned long)time(0));
    for (int i = 0; i < 100; ++i)
    {
        num = rand() % 19;
        scs = rand() % 8;
        jzs = rand() % 6;
        zls = rand() % (jzs + 1);//因为有jzs == 0的情况会导致程序崩溃,同时也有二者相等的可能,下同理
        dd = rand() % (zls + 1);
        ch = num + 'a';
        f[0] = f[1] = l[0] = l[1] = l[2] = ch;
        f[2] = l[3] = '\0';
        fprintf(fp, "%d %s %s %d %d %d %d\n", num, f, l, scs, jzs, zls, dd);
    }
    fclose(fp);//因为忘关了出现了莫名的错误
}

void getData(struct player a[])
{
    FILE *fp = fopen("data.txt", "r");
    if(fp == NULL)
    {
        fprintf(stderr, "Open failed\n");
        exit(EXIT_FAILURE);
    }
    int num, scs, jzs, zls, dd;
    char f[30], l[30];
    while(~fscanf(fp, "%d %s %s %d %d %d %d", &num, f, l, &scs, &jzs, &zls, &dd))
    {
        if(a[num].num != 0)
        {
            a[num].dd += dd;
            a[num].scs += scs;
            a[num].jzs += jzs;
            a[num].zls += zls;
        }
        else
        {
            a[num].num = num;
            a[num].dd += dd;
            a[num].scs += scs;
            a[num].jzs += jzs;
            a[num].zls += zls;
            strcpy(a[num].fname, f);
            strcpy(a[num].lname, l);
        }
    }
    fclose(fp);
}

void getADL(struct player a[])
{
    for (int i = 0; i < 19; ++i) {
        a[i].adl = (float)a[i].jzs / (float)a[i].scs;
    }
}

void Print(struct player a[])
{
    for (int i = 0; i < 19; ++i) {
        printf("%d %s %s %d %d %d %d %.2f\n", a[i].num, a[i].fname, a[i].lname, a[i].scs, a[i].jzs, a[i].zls, a[i].dd, a[i].adl);
    }
}

int main(void)
{
    mkfile();
    getData(list);
    getADL(list);
    Print(list);
    return 0;
}

7.修改程序清单 14.14,从文件中读取每条记录并显示出来,允许用户删除记录或修改记录的内容。如果删除记录,把空出来的空间留给下一个要读入的记录。要修改现有的文件内容,必须用"r+b"模式,而不是"a+b"模式。而且,必须更加注意定位文件指针,防止新加入的记录覆盖现有记录。最简单的方法是改动储存在内存中的所有数据,然后再把最后的信息写入文件。跟踪的一个方法是在book结构中添加一个成员表示是否该项被删除

#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 flag;
};

void mkfile()
{
    FILE *fp = fopen("book.dat", "a");
    fclose(fp);
}

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", "r+b")) == NULL)
    {
        mkfile();
        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 contents 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 titles.");
    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);
        library[count++].flag = 1;
        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);
        int fn;
        char a[MAXTITL];
        puts("Do you wanna delete your books(1/0)?");
        while(scanf("%d", &fn) == 1 && fn)
        {
            puts("Input the book name that you wanna delete:");
            scanf("%s", a);
            int i;
            for (i = 0; i < count; ++i) {
                if(!strcmp(library[i].title, a))
                {
                    library[i].flag = 0;
                    break;
                }
            }
            if(i == count)
            {
                printf("There is no book named %s\n", a);
            }
            puts("Do you wanna delete your book again(1/0)?");
        }
        puts("Do you wanna change the info of your books(1/0)?");
        while(scanf("%d", &fn) == 1 && fn)
        {
            puts("Input the book name that you wanna change:");
            scanf("%s", a);
            int i;
            for (i = 0; i < count; ++i) {
                if(!strcmp(library[i].title, a))
                {
                    puts("Now enter the author.");
                    scanf("%s", library[i].author);
                    puts("Now enter the value.");
                    scanf("%f", &library[i].value);
                    while (getchar() != '\n')
                        continue;
                    break;
                }
            }
            if(i == count)
            {
                printf("There is no book named %s\n", a);
            }
            puts("Do you wanna delete your book again(1/0)?");
        }
        fclose(pbooks);
        FILE *fp = fopen("book.dat", "w");//因为要删除,所以重写
        for (int j = 0; j < count; ++j)
        {
            if(library[j].flag)
            {
                fwrite(&library[j], size, 1, fp);
            }
        }
        fclose(fp);
    }
    else
        puts("No books? Too bad.\n");
    puts("Bye.\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;
}

8.巨人航空公司的机群由 12 个座位的飞机组成。它每天飞行一个航班。根据下面的要求,编写一个座位预订程序。

a.该程序使用一个内含 12 个结构的数组。每个结构中包括:一个成员表示座位编号、一个成员表示座位是否已被预订、一个成员表示预订人的名、一个成员表示预订人的姓。

b.该程序显示下面的菜单:

To choose a function, enter its letter label:

a) Show number of empty seats

b) Show list of empty seats

c) Show alphabetical list of seats

d) Assign a customer to a seat assignment

e) Delete a seat assignment

f) Quit

c.该程序能成功执行上面给出的菜单。选择d)和e)要提示用户进行额外输入,每个选项都能让用户中止输入。

d.执行特定程序后,该程序再次显示菜单,除非用户选择f)。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

struct seat
{
    int num;
    int flag;
    char f[30], l[30];
}list[12] = {{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {9, 1}, {10, 1}, {11, 1}};

void afunc()
{
    int sum = 0;
    for (int i = 0; i < 12; ++i) {
        if(list[i].flag)
        {
            sum++;
        }
    }
    printf("There are %d seats empty\n", sum);
}

void bfunc()
{
    puts("Empty list:");
    for (int i = 0; i < 12; ++i) {
        if(list[i].flag)
        {
            printf("%d ", list[i].num);
        }
    }
    putchar('\n');
}

int cfunccmp(const void* a, const void* b)
{
    struct seat *i = (struct seat*)a;
    struct seat *j = (struct seat*)b;
    if(i->flag && j->flag)//防止可选座位被乱序
    {
        return i->num - j->num;
    }
    if(!i->flag)//不可选座位直接前置,无法比较名字大小
    {
        return 0;
    }
    if(!j->flag)
    {
        return 1;
    }
    int x = strcmp(i->f, j->f);
    if(x > 0)
    {
        return 1;
    }
    else if(!x && strcmp(i->l, j->l) > 0)
    {
        return 1;
    }
    return 0;
}

void cfunc()
{
    qsort(list, 12, sizeof(struct seat), cfunccmp);
    puts("Alphabetical list:");
    for (int i = 0; i < 12; ++i) {
        if(!list[i].flag)
        {
            printf("%s %s\n", list[i].f, list[i].l);
        }
    }
}

void dfunc()
{
    int n;
    char a[30], b[30];
    bfunc();
    puts("Which seat you wanna assign?");
    while(scanf("%d", &n) == 1)
    {
        for (int i = 0; i < 12; ++i) {
            if(list[i].num == n)
            {
                n = i;
                break;
            }
        }
        if(list[n].flag)
        {
            printf("What's your first name:");
            scanf("%s", a);
            strcpy(list[n].f, a);
            printf("What's your last name:");
            scanf("%s", b);
            strcpy(list[n].l, b);
            list[n].flag = 0;
            puts("Done");
            break;
        } else
        {
            puts("This seat is not empty");
        }
    }
}

void efunc()
{
    int n;
    puts("Assigned list:");
    for (int i = 0; i < 12; ++i) {
        if(!list[i].flag)
        {
            printf("%d ", list[i].num);
        }
    }
    putchar('\n');
    puts("Which assign you wanna delete?");
    while(scanf("%d", &n) == 1)
    {
        if(!list[n].flag)
        {
            list[n].flag = 1;
            puts("Done");
            break;
        } else
        {
            puts("This seat is empty");
        }
    }
}


void doChoice()
{
    puts("To choose a function, enter its letter label: ");
    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 seat assignment ");
    puts("e) Delete a seat assignment");
    puts("f) Quit");
    char ch;
    while( scanf("%c", &ch) == 1&& ch != 'f')
    {
        switch (ch)
        {
            case 'a':
                afunc();
                break;
            case 'b':
                bfunc();
                break;
            case 'c':
                cfunc();
                break;
            case 'd':
                dfunc();
                break;
            case 'e':
                efunc();
                break;
            default:
                break;
        }
    }
}

int main(void)
{
    doChoice();
    return 0;
}
/*
d
8
asd
asd
d
0
dsa
das
c
b
*/

9.巨人航空公司(编程练习 8)需要另一架飞机(容量相同),每天飞 4 班(航班 102、311、444 和519)。把程序扩展为可以处理4个航班。用一个顶层菜单提供航班选择和退出。选择一个特定航班,就会出现和编程练习8类似的菜单。但是该菜单要添加一个新选项:确认座位分配。而且,菜单中的退出是返回顶层菜单。每次显示都要指明当前正在处理的航班号。另外,座位分配显示要指明确认状态

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

struct seat
{
    int num;
    int flag;
    char f[30], l[30];
}list[4][12] = {
        {{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {9, 1}, {10, 1}, {11, 1}},
        {{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {9, 1}, {10, 1}, {11, 1}},
        {{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {9, 1}, {10, 1}, {11, 1}},
        {{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}, {5, 1}, {6, 1}, {7, 1}, {8, 1}, {9, 1}, {10, 1}, {11, 1}}
};

int hb;
int de[4] = {0, 0, 0, 0};

void afunc()
{
    int sum = 0;
    for (int i = 0; i < 12; ++i) {
        if(list[hb][i].flag)
        {
            sum++;
        }
    }
    printf("There are %d seats empty\n", sum);
}

void bfunc()
{
    puts("Empty list:");
    for (int i = 0; i < 12; ++i) {
        if(list[hb][i].flag)
        {
            printf("%d ", list[hb][i].num);
        }
    }
    putchar('\n');
}

int cfunccmp(const void* a, const void* b)
{
    struct seat *i = (struct seat*)a;
    struct seat *j = (struct seat*)b;
    if(i->flag && j->flag)//防止可选座位被乱序
    {
        return i->num - j->num;
    }
    if(!i->flag)//不可选座位直接前置,无法比较名字大小
    {
        return 0;
    }
    if(!j->flag)
    {
        return 1;
    }
    int x = strcmp(i->f, j->f);
    if(x > 0)
    {
        return 1;
    }
    else if(!x && strcmp(i->l, j->l) > 0)
    {
        return 1;
    }
    return 0;
}

void cfunc()
{
    qsort(list[hb], 12, sizeof(struct seat), cfunccmp);
    puts("Alphabetical list:");
    for (int i = 0; i < 12; ++i) {
        if(!list[hb][i].flag)
        {
            printf("%s %s\n", list[hb][i].f, list[hb][i].l);
        }
    }
}

void dfunc()
{
    int n;
    char a[30], b[30];
    bfunc();
    puts("Which seat you wanna assign?");
    while(scanf("%d", &n) == 1)
    {
        for (int i = 0; i < 12; ++i) {
            if(list[hb][i].num == n)
            {
                n = i;
                break;
            }
        }
        if(list[hb][n].flag)
        {
            printf("What's your first name:");
            scanf("%s", a);
            strcpy(list[hb][n].f, a);
            printf("What's your last name:");
            scanf("%s", b);
            strcpy(list[hb][n].l, b);
            list[hb][n].flag = 0;
            puts("Done");
            break;
        } else
        {
            puts("This seat is not empty");
        }
    }
}

void efunc()
{
    int n;
    puts("Assigned list:");
    for (int i = 0; i < 12; ++i) {
        if(!list[hb][i].flag)
        {
            printf("%d ", list[hb][i].num);
        }
    }
    putchar('\n');
    puts("Which assign you wanna delete?");
    while(scanf("%d", &n) == 1)
    {
        if(!list[hb][n].flag)
        {
            list[hb][n].flag = 1;
            puts("Done");
            break;
        } else
        {
            puts("This seat is empty");
        }
    }
}


void doChoice()
{
    puts("To choose a function, enter its letter label: ");
    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 seat assignment ");
    puts("e) Delete a seat assignment");
    puts("f) Determine allocation");
    puts("g) Quit");
    char ch = 'a';
    while(ch != 'g' && scanf("%c", &ch) == 1)
    {
        switch (ch)
        {
            case 'a':
                afunc();
                break;
            case 'b':
                bfunc();
                break;
            case 'c':
                cfunc();
                break;
            case 'd':
                dfunc();
                break;
            case 'e':
                efunc();
                break;
            case 'f':
                ch = 'g';
                de[hb] = 1;
                puts("Flight determined");
                break;
            default:
                break;
        }
    }
}

void DoChoice()
{
    hb = 0;
    puts("Which flight do you want to choice");
    puts("0) Flight 102        2)FLight 311");
    puts("1) Flight 411        3)Flight 519");
    puts("4) quit");
    while(scanf("%d", &hb) == 1)
    {
        if(de[hb])
        {
            puts("This flight has been determined, please choice another one");
        }
        else
        {
            if(hb == 4)
            {
                break;
            }
            doChoice();
            puts("Which flight do you want to choice");
            puts("0) Flight 102        2)FLight 311");
            puts("1) Flight 411        3)Flight 519");
            puts("4) quit");
        }
    }
}

int main(void)
{
    DoChoice();
    return 0;
}
/*
0
d
8
asd
asd
d
0
dsa
das
c
b
f
0
4
*/

10.编写一个程序,通过一个函数指针数组实现菜单。例如,选择菜单中的 a,将激活由该数组第 1个元素指向的函数

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

void funa(int a, int b)
{
    printf("%d\n", a + b);
}

void funb(int a, int b)
{
    printf("%d\n", a - b);
}

void func(int a, int b)
{
    puts("Do nothing");
}

int main(void)
{
    void (* pfunc)(int, int) = func;
    char ch;
    int a = 100, b = 25;
    puts("Input a, b, c or q:");
    while(scanf("%c", &ch) && ch != 'q')
    {
        getchar();//连续输入字符要吃空格
        switch(ch)
        {
            case 'a':
                pfunc = funa;
                break;
            case 'b':
                pfunc = funb;
                break;
            default:
                pfunc = func;
                break;
        }
        pfunc(a, b);
        puts("Input a, b or c:");
    }
    return 0;
}

11.编写一个名为transform()的函数,接受4个参数:内含double类型数据的源数组名、内含double类型数据的目标数组名、一个表示数组元素个数的int类型参数、函数名(或等价的函数指针)。transform()函数应把指定函数应用于源数组中的每个元素,并把返回值储存在目标数组中。例如:

transform(source, target, 100, sin);

该声明会把target[0]设置为sin(source[0]),等等,共有100个元素。在一个程序中调用transform()4次,以测试该函数。分别使用math.h函数库中的两个函数以及自定义的两个函数作为参数

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h>
#include <math.h>

void transform(double a[], double b[], int n, double (*func)(double))
{
    for (int i = 0; i < n; ++i) {
        b[i] = func(a[i]);
    }
}

double test1(double a)
{
    return a / 2;
}

double test2(double a)
{
    return a * 2;
}

int main(void)
{
    double a[50], b[50];
    for (int i = 0; i < 50; ++i) {
        a[i] = i;
    }
    transform(a, b, 50, test1);
    for (int j = 0; j < 50; ++j)
    {
        printf("%.2lf ", b[j]);
    }
    puts("\n------------------------------------------------------------------------------------------------------------------------");
    transform(a, b, 50, test2);
    for (int j = 0; j < 50; ++j)
    {
        printf("%.2lf ", b[j]);
    }
    puts("\n------------------------------------------------------------------------------------------------------------------------");
    transform(a, b, 50, sin);
    for (int j = 0; j < 50; ++j)
    {
        printf("%.2lf ", b[j]);
    }
    puts("\n------------------------------------------------------------------------------------------------------------------------");
    transform(a, b, 50, cos);
    for (int j = 0; j < 50; ++j)
    {
        printf("%.2lf ", b[j]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/asdgyy/article/details/82956108