14.1
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define LEN 12
struct month
{
char name[10];
char abbrev[4];
int days;
int monnmb;
};
//创建了一个结构体数组
const struct 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 *name, int *temp);
int main(void)
{
int tp;
int daytotal;
char input[LEN];
printf("请输入一个月份名(按q退出本程序):");
while((scanf("%11s", input) == 1) && (input[0] != 'q'))
{
daytotal = days(input, &tp);
//tp对其取地址,是为了在下面方便赋值
if(daytotal > 0)
{
printf("一年中到%d月(包括%d月)总共有%d天.\n", tp, tp, daytotal);
}
else
{
printf("%s不是一个月份名!\n", input);
}
printf("您可以再次输入一个月份名(或按q退出):");
while(getchar() != '\n')
continue;
}
printf("本程序完成!\n");
return 0;
}
int days(char *m, int *temp)
{
int i = 1;
int num = 0;
int total = 0;
m[0] = toupper(m[0]);
//第一个字符转换成大写
while(m[i])
{
m[i] = tolower(m[i]);
i++;
//数组中剩余字符转换成小写
}
for(i = 0; i < LEN; i++)
{
puts("111");
if(0 == strcmp(m, months[i].name))
{
num = months[i].monnmb;
//输入和结构体数组里的月份字符相同,把当前月分日期赋值过去
*temp = i + 1;
//二者相同,循环停止,
//把i值赋值过去(意思:包括%d月)
break;
}
}
if(num == 0)
{
total = -1;
}
else
{
//将月份当作循环条件,统计所有天数
for(i = 0; i < num; i++)
{
total += months[i].days;
//统计一下num个月(包括%d月)的所有天数
}
}
return total;
}
.
.
14.2
输入30 5 1 【日、月、年】:先进入for
循环,打印44,在对if
中的条件进行比较,在下标i = 0、1、2、3
的情况下都不满足,走else
对1、2、3、4
月份的天数进行直接统计;在下标为4(5月份)
满足if
条件,进入if
,对当前月份数进行计算(*tp
),且加上当前月份的天数。
.
天数统计函数==》days_result(month, day, &n)
:要对月份、天数进行判断,且返回天数统计的总和、以及当前月份(所以形参采用指针的方式接收实参传递的地址,来达到对实参值修改的目的)。
.
结构体数组创建,每个数组的元素下标,对应一个结构体类型
.
.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#define LEN 12
struct month
{
char name[10];
char abbrev[4];
int days;
int monumb;
};
struct 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_result(char *month, int days, int *tp);
int main(void)
{
//int i = 0;
int n, val;
int day, year;
char month[LEN];
printf("请您输入日,月和年(按q退出本程序):\n");
while (scanf("%d %11s %d", &day, month, &year) == 3)
{
if((year % 4 ==0 && year % 100 != 0) || (year % 400 == 0))
{
months[1].days = 29;//判断是否是闰年;
}
val = days_result(month, day, &n);
if (val < 0)
{
printf("您输入的数据有误!\n");
}
else
{
printf("从%d年初到%d月%d日总共有%d天.\n", year, n, day, val);
}
months[1].days = 28;//2月份天数还原为非闰年时的天数;
printf("您可以继续输入日,月和年(或按q退出):\n");
}
printf("本程序完成!\n");
return 0;
}
int days_result(char *month, int days, int *tp)
{
int i;
int total = 0;
int temp = atoi(month);//输入全是字符串未进行有效转化,最后int值为0
//月份可以是月份号的情况下,字符‘5’-->整数5(字符串转换成数字的函数)
month[0] = toupper(month[0]);//转换成大写
if(days < 1 || days > 31)
{
return -1; //输入的天数有误则终止本函数;
}
for(i = 0; i < LEN; i++)
{
puts("44");
if ((temp == months[i].monumb) ||(strcmp(month, months[i].name) == 0) ||(strcmp(month, months[i].abbrev) == 0))
{
puts("33");
//⬆三种情况下满足一个即可
if(days > months[i].days)
{
return -1;//输入的天数不符合月份的规则;
}
else
{
puts("11");
*tp = i + 1;//循环判断上述条件,满足i停止,即为本月月数(数组下标从0开始)
return total + days;//累加到此月后再加上--本月天数;我们输入的天数
}
}
else
{
puts("22");
total += months[i].days;//i在循环,加上每次i变化时对应的天数
}
}
return -1; //输入月份有误后的终止条件;
}
.
.
14.3
count++;
//服务于结构体中的所有属性,不能仅仅在一个属性中采取count++的做法
- struct book *book[MAXBKS];一般会通过创建一个新的指针,来满足间接操作的目的
#include <stdio.h>
#include <string.h>
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 100
struct book
{
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
char *s_gets(char *st, int n);
void sort_title(struct book *pb[], int n);
void sort_value(struct book *pb[], int n);
int main(void)
{
struct book library[MAXBKS];
struct 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) && 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);
book[count] = &library[count];
//将library数组中各个元素下标的地址信息,赋值给指针数组book中的对应指针元素
//他们都是指向struct book类型的指针
count++;
//服务于结构体中的所有属性,不能仅仅在一个属性中采取count++的做法
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);
}
putchar('\n');
sort_title(book, count);//按照标题排序
printf("\nHere is the list of your books sorted by title letters:\n");
for(index = 0; index < count; index++)
{
printf("%s by %s: $%.2f\n", book[index]->title,
book[index]->author, book[index]->value);
}
putchar('\n');
sort_value(book, count);
printf("\nHere is the list of your books sorted by value(from low to high):\n");
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;
}
void sort_title(struct book *pb[], int n)
{
int i, j;
struct book *temp;
for(i = 0; i < n - 1; i++)
{
for(j = i + 1; j < n; j++)
{
if(strcmp(pb[j]->title, pb[i]->title) < 0)
{
temp = pb[j];
pb[j] = pb[i];
pb[i] = temp;
}
}
}
return;
}
void sort_value(struct book *pb[], int n)
{
int i, j;
struct book *temp;
for(i = 0; i < n - 1; i++)
{
for(j = i + 1; j < n; j++)
{
if(pb[j]->value < pb[i]->value)
{
temp = pb[j];
pb[j] = pb[i];
pb[i] = temp;
}
}
}
return;
}
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)
{
*find = '\0';
}
else
{
while (getchar() != '\n')
continue;
}
}
return ret_val;
}
.
.
14.4a
1. 结构体的嵌套;
2. show(m, count);
中的m是结构体数组的首地址,所以形参采取pt[ ]
的形式接收实参的地址信息,从而去指向实参中的成员属性(等价于 *pt )
#include <stdio.h>
#include <string.h>
#define N 15
#define LEN 30
struct names
{
char fname[N];
char mname[N];
char lname[N];
};
struct messages
{
char ins_num[LEN];
struct names name;
};
char *s_gets(char *st, int n);
void show(const struct messages pt[], int n);
int main(void)
{
int count = 0;
struct messages m[5];
printf("Please enter the insurance number:\n");
printf("Press [enter] at the start of a line to stop.\n");
while(count < 5 && s_gets(m[count].ins_num, LEN) && m[count].ins_num[0] != '\0'
&& m[count].name.fname[0] != '\0')
{
printf("Now enter the former name.\n");
s_gets(m[count].name.fname, N);
printf("Now enter the middle name(Without,[enter] to the next).\n");
s_gets(m[count].name.mname, N);
printf("Now enter the last name.\n");
s_gets(m[count].name.lname, N);
if(count++ < 5)
{
printf("Enter the next insurance number:\n");
}
}
if(count > 0)
{
show(m, count);
}
else
{
printf("No data!\n");
}
return 0;
}
void show(const struct messages pt[], int n)
{
int i = 0;
printf("All numbers messages:\n");
for(; i < n; i++)
{
if(pt[i].name.mname[0] == '\0')
{
printf("%s, %s", pt[i].name.fname, pt[i].name.lname);
printf(" -- %s\n", pt[i].ins_num);
}
else
{
printf("%s, %s %c.", pt[i].name.fname, pt[i].name.lname, pt[i].name.mname[0]);
printf(" -- %s\n", pt[i].ins_num);
}
}
return;
}
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.4b
.
- 值传递,接收主函数中的实参变量的所有信息且不会改变实参的数据,在功能函数中运行过后便会清零,栈的思想
- void show_messages(const struct messages pt); 注意函数的形参
.
#include <stdio.h>
#include <string.h>
#define N 15
#define LEN 30
struct names
{
char fname[N];
char mname[N];
char lname[N];
};
struct messages
{
char ins_num[LEN];
struct names name;
};
char *s_gets(char *st, int n);
void show_messages(const struct messages pt);
int main(void)
{
int i;
int count = 0;
struct messages m[5];
printf("Please enter the insurance number:\n");
printf("Press [enter] at the start of a line to stop.\n");
while(count < 5 && s_gets(m[count].ins_num, LEN) && m[count].ins_num[0] != '\0'
/*&& m[count].name.fname[0] != '\0'*/)
{
printf("Now enter the former name:\n");
s_gets(m[count].name.fname, N);
printf("Now enter the middle name(Without,[enter] to the next):\n");
s_gets(m[count].name.mname, N);
printf("Now enter the last name:\n");
s_gets(m[count].name.lname, N);
if(count++ < 5)
{
printf("Enter the next insurance number:\n");
}
}
if(count > 0)
{
printf("All numbers messages:\n");
for(i = 0; i < count; i++)
{
show_messages(m[i]);
}
}
else
{
printf("No data!\n");
}
return 0;
}
void show_messages(const struct messages pt)//直接传递结构体的变量
{
//int i = 0;
//printf("All numbers messages:\n");
//for(; i < count; i++)
//{
if(pt/*[i]*/.name.mname[0] == '\0')
{
printf("%s, %s", pt/*[i]*/.name.fname, pt/*[i]*/.name.lname);
printf(" -- %s\n", pt/*[i]*/.ins_num);
}
else
{
printf("%s, %s %c.", pt/*[i]*/.name.fname, pt/*[i]*/.name.lname, pt/*[i]*/.name.mname[0]);
printf(" -- %s\n", pt/*[i]*/.ins_num);
}
//}
return;
}
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.5
- 注意需要结构体的嵌套,学生的结构体中包含名字的结构体
- 分步走
- 2021.2.05复看于此
- grade[j]是一个float值,因此需要‘&’,来获取地址信息
#include <stdio.h>
#include <string.h>
#define LEN 15
#define CSIZE 4//声明一个内含CSIZE(CSIZE = 4)个student类型结构的数组
#define SCORES 3
struct name
{
char fname[LEN];
char lname[LEN];
};
struct student
{
struct name mes;
float grade[SCORES];//储存3个浮点型分数
float aver;//储存3个分数平均数
};
void set_students(struct student ar[], int n);
void find_averages(struct student ar[], int n);
void show_messages(const struct student ar[], int n);
void show_averages(const struct student ar[], int n);
int main(void)
{
struct student classes[CSIZE] =
{
{"Flip", "Snide"},
{"Clare", "Voyans"},
{"Bingo", "Higgs"},
{"Fawn", "Hunter"}
};
set_students(classes,CSIZE);//为结构体数组中的学生设置成绩
find_averages(classes,CSIZE);
show_messages(classes,CSIZE);
show_averages(classes,CSIZE);
return 0;
}
void set_students(struct student ar[], int n)
{
int i, j;
for(i = 0; i < n; i++)
{
puts("@");
printf("请为%s %s输入3个成绩 ;\n", ar[i].mes.fname, ar[i].mes.lname);
for(j = 0; j < SCORES; j++)
{
//grade是一个数组,j相当于元素下标
//grade[j]是一个float值,因此需要‘&’,来获取地址信息
while(scanf("%f", &ar[i].grade[j]) != 1)
{
while(getchar() != '\n')
{
continue;
}
puts("数据无效!请重新输入:");
}
}
}
return;
}
void find_averages(struct student ar[], int n)
{
int i, j;
float sum;
for(i = 0; i< n; i++)
{
for(j = 0, sum = 0.0f; j < SCORES; j++)
{
sum += ar[i].grade[j];
}
//i表示第几个学生,aver是struct student结构体中的成员属性
ar[i].aver = sum / SCORES;
}
return;
}
void show_messages(const struct student ar[], int n)
{
int i, j;
for(i = 0; i < n; i++)
{
printf("\n%s %s的3科成绩是:\n", ar[i].mes.fname, ar[i].mes.lname);
for (j = 0; j < SCORES; j++)
{
printf("每门成绩 :%g.\n", ar[i].grade[j]);
}
printf("最后平均成绩 :%g.\n", ar[i].aver);
}
return;
}
void show_averages(const struct student ar[], int n)
{
int i;
float total;
for(i = 0, total = 0.0f; i < n; i++)
{
total += ar[i].aver;
}
printf("\n班级平均分是:%g\n", total / n);
return;
}
.
14.6.1
- 全局静态变量已经清零了;
- 在从文件中读取数据的函数中,第一个fscanf已经读取过一次信息,若不
rewind(fp)
返回到文件开始处,结果将会少一个球员的数据; count_hit_rate()、show_messages()、read_datas()函数
中传递的实参都是结构体数组首地址以及数组大小;- read_datas()函数中,对结构体数组中的成员赋值数据要注意,是给对应id(这里是m)的球员进行赋值的,就是
fscanf
中写入到m
中的id
号;例如:players[m].id = m
; - 普通for循环顺序排序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 19
typedef struct
{
int id; //球员的编号
char fname[LEN]; //球员的名;
char lname[LEN]; //球员的姓;
int stage_num; //球员的上场次数;
int hit_num; //球员的击中数;
int base_num; //球员的走垒数;
int rbi; //球员的打点;
float hit_rate; //球员的安打率;
}TEAM;
//void clear_datas(TEAM players[], int n);
int read_datas(TEAM players[], int n, FILE *fp);
void count_hit_rate(TEAM players[], int n);
void show_messages(TEAM players[], int n);
static TEAM players[LEN]; //全局静态变量中数据已清0;
int main(void)
{
FILE *fp;
int len;
//TEAM players[LEN];/*全局静态变量中数据已清0;*/
/*这里就不需要专门去清理结构体数组中的成员信息清理了*/
//球员等信息在文件中
if((fp = fopen("datas.txt", "r")) == NULL)
{
fprintf(stderr,"Can't open file datas.txt.\n");
exit(EXIT_FAILURE);
}
//clear_datas(players, LEN);
len = read_datas(players, LEN, fp);//统计文件中不同球员的数量;
printf("读取到的球员个数 :len = %d\n", len);
count_hit_rate(players, LEN);
show_messages(players, LEN);
if(fclose(fp) != 0)
{
fprintf(stderr, "Can't close file datas.txt.\n");
exit(EXIT_FAILURE);
}
return 0;
}
//原数组内容全部清零
/*void clear_datas(TEAM players[], int n)
{
int i;
for(i = 0; i < n; i++)
{
players[i].id = 0;
players[i].hit_num = 0;
players[i].hit_rate = 0;
players[i].base_num = 0;
players[i].rbi = 0;
players[i].stage_num = 0;
memset(players[i].fname, '\0', sizeof(players[i].fname));
memset(players[i].lname, '\0', sizeof(players[i].lname));
}
}*/
int read_datas(TEAM players[], int n, FILE *fp)
{
int ch = 0;
int count = 0;
float hit_rate;//球员的安打率;
char fname[LEN], lname[LEN];
int m , stage_num, hit_num, base_num, rbi;
count = fscanf(fp, "%d %18s %18s %d %d %d %d",
&m, fname, lname, &stage_num, &hit_num,
&base_num, &rbi);//返回我们输入成功的次数
printf("统计我们输入成功的次数(每个球员有7条信息) :count = %d\n", count);
//while循环外的fscanf已经将文件的内容读入到对应变量的地址中一次
//所以要新定位到文件的开始,否则会从文本的第二行开始读取
rewind(fp);
while((count == 7) && !feof(fp) && (ch < n))
{
if(players[m].stage_num == 0)
{
ch++;//上场次数为0,就去统计下一个球员信息;
}
//这里从文件中的第一行向变量中输入信息,去赋值到结构体数组对应的成员中去
//
count = fscanf(fp, "%d %18s %18s %d %d %d %d",
&m, fname, lname, &stage_num, &hit_num,
&base_num, &rbi);//返回我们输入成功的次数
//对应变量的地址中的数据,赋值给结构体中的成员
strcpy(players[m].fname, fname);
strcpy(players[m].lname, lname);
players[m].id = m;
players[m].stage_num += stage_num;//同一个球员就累加
players[m].hit_num += hit_num;
players[m].base_num += base_num;
players[m].rbi += rbi;
}
return ch;
}
//计算安打率;
void count_hit_rate(TEAM players[], int n)
{
int i;
if(n > 0)
{
for(i = 0; i < n; i++)
{
players[i].hit_rate = (float)players[i].hit_num / (float)players[i].stage_num;
//计算每个运动员的安打率;i
//球员的累计击中数除以上场累计次数
}
}
return;
}
void show_messages(TEAM players[], int n)
{
int i;
if(n == 0)
{
printf("No datas!\n");
}
else
{
//for循环会按序排列
printf("Datas for all players:\n");
printf("Id First_name Last_name Stage Hit_rate Base_num RBI Hit_rate\n");
for(i = 0; i < n; i++)
{
puts("===");
printf("%-4d %-12s %-10s %5d %7d %11d %8d %8.2f\n",
players[i].id, players[i].fname, players[i].lname,
players[i].stage_num, players[i].hit_num, players[i].base_num,
players[i].rbi, players[i].hit_rate);
}
}
return;
}
.
.
标题 14.6.2—采用快速排序,进行球员id的顺序排列
- 增加了快速排序函数
- 快速排序结束后,增加了累加的函数
- 注意快速排序中的,基准值的设定,我们要排序什么类型的值,基准值的值类型就要与排序值的类型一致(
这里是对结构体数组中的id进行排序,因此基准值类型要是结构体
)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 19
typedef struct
{
int id; //球员的编号
char fname[LEN]; //球员的名;
char lname[LEN]; //球员的姓;
int stage_num; //球员的上场次数;
int hit_num; //球员的击中数;
int base_num; //球员的走垒数;
int rbi; //球员的打点;
float hit_rate; //球员的安打率;
}TEAM;
int read_datas(TEAM players[], int n, FILE *fp);
void count_hit_rate(TEAM players[], int n);
void show_messages(TEAM players[], int n);
//信息累加
void add_messages(TEAM players[],int n);
//快速排序
//int partition(TEAM players[],int begin,int end);
void quickSort(TEAM players[],int begin,int end);
void my_shos_messages(TEAM players[], int n);
static TEAM players[LEN]; //全局静态变量中数据已清0;
int main(void)
{
FILE *fp;
int len;
//球员等信息在文件中
if((fp = fopen("datas.txt", "r")) == NULL)
{
fprintf(stderr,"Can't open file datas.txt.\n");
exit(EXIT_FAILURE);
}
len = read_datas(players, LEN, fp);//统计文件中不同球员的数量;
count_hit_rate(players, len);
show_messages(players, len);
//数据累加处理
add_messages(players, len);
my_shos_messages(players, len);
if(fclose(fp) != 0)
{
fprintf(stderr, "Can't close file datas.txt.\n");
exit(EXIT_FAILURE);
}
return 0;
}
int read_datas(TEAM players[], int n, FILE *fp)
{
int ch = 0;
int count = 0;
float hit_rate;//球员的安打率;
char fname[LEN], lname[LEN];
int m , stage_num, hit_num, base_num, rbi;
count = fscanf(fp, "%d %18s %18s %d %d %d %d",
&m, fname, lname, &stage_num, &hit_num,
&base_num, &rbi);//返回我们输入成功的次数
printf("count = %d\n",count);
while((count == 7) && (ch <= n+1))
{
puts("##");
ch++;//ch从0开始++,这里的ch == 1;而ch - 1 : 相当于rewind(fp)
//首先会拷贝我们的第一列信息
strcpy(players[ch-1].fname, fname);
strcpy(players[ch-1].lname, lname);
players[ch-1].id = m;
players[ch-1].stage_num += stage_num;//同一个球员就累加
players[ch-1].hit_num += hit_num;
players[ch-1].base_num += base_num;
players[ch-1].rbi += rbi;
printf("ch -1 = %d m = %d\n",ch-1,m);
//这里再次从文件中向变量中输入信息,去赋值到结构体数组中去
count = fscanf(fp, "%d %18s %18s %d %d %d %d",
&m, fname, lname, &stage_num, &hit_num,
&base_num, &rbi);//返回我们输入成功的次数
}
return ch;
}
//计算安打率;
void count_hit_rate(TEAM players[], int n)
{
int i;
if(n > 0)
{
for(i = 0; i < n; i++)
{
players[i].hit_rate = (float)players[i].hit_num / (float)players[i].stage_num;
//计算每个运动员的安打率;i
//球员的累计击中数除以上场累计次数
}
}
return;
}
//快排
void quickSort(TEAM players[],int begin,int end)
{
if(begin < end)
{
int i = begin;//左地址、起始地址
int j = end;//右地址、终止地址
//*注意此处,基准值的类型!***给定一个基准值,用来比较***
TEAM key_id = players[i];
while(i < j)
{
while (i < j && players[j].id >= key_id.id)
{
j--;
}
//将右边小于等于基准元素的数填入右边相应位置
players[i] = players[j];
while (i < j && players[i].id <= key_id.id)
{
i++;
}
//将左边大于基准元素的数填入左边相应位置
players[j] = players[i];
}
//将基准元素填入相应位置
players[i] = key_id;
quickSort( players, begin, i-1);//左区间继续比较
quickSort( players, i+1, end);//右区间比较
}
}
void show_messages(TEAM players[], int n)
{
puts("排序后的数组:");
int i;
//int i2;
//TEAM temp;
if(n == 0)
{
printf("No datas!\n");
}
else
{
//for循环会按序排列
printf("Datas for all players:\n");
printf("Id First_name Last_name Stage Hit_rate Base_num RBI Hit_rate\n");
//方法① :按照id号进行排序
quickSort(players, 0, n-1);
/*
//方法② :冒泡排序
for(i = 0; i < n-1; i++)
{
for (i2 = 0; i2 < n-i-1; i2++)
{
if (players[i2].id > players[i2+1].id)
{
temp = players[i2];
players[i2] = players[i2+1];
players[i2+1] = temp;
}
}
}*/
for(i=0;i<n;i++)
{
puts("===");
printf("%-4d %-12s %-10s %5d %7d %11d %8d %8.2f\n",
players[i].id, players[i].fname, players[i].lname,
players[i].stage_num, players[i].hit_num, players[i].base_num,
players[i].rbi, players[i].hit_rate);
}
}
return;
}
//相同编号信息累加
void add_messages(TEAM players[],int n)
{
int i,i2;
if(n == 0)
{
printf("No datas!\n");
}
//前后编号交互比较(冒泡法)
//①与②比了,②还会与①比,用memset来防止这样的操作,只让其顺向进行比较
for (i = 0; i < n; i++)
{
for (i2 = 0; i2 < n; i2++)
{
if (i == i2)
{
continue;
}
if (strcmp(players[i].fname,players[i2].fname) == 0 && strcmp(players[i].lname,players[i2].lname) == 0)
{
players[i].base_num +=players[i2].base_num;
players[i].hit_num +=players[i2].hit_num;
players[i].hit_rate +=players[i2].hit_rate;
players[i].rbi +=players[i2].rbi;
players[i].stage_num +=players[i2].stage_num;
players[i2].id = -1;//如果相近两个编号都是同一个人,该处可以防止累加完之后,第二个编号还存在
printf("go to add -----\n");
memset(players[i2].fname,i,sizeof(players[i2].fname)); //打乱数据防止再进入....
memset(players[i2].fname,i2,sizeof(players[i2].fname)); //
}
}
}
printf("ADD ---------------------------------OVER\n");
putchar('\n');
return ;
}
void my_shos_messages(TEAM players[], int n)
{
puts("累加后的结构体数组:");
int i;
for(i=0;i<n;i++)
{
if(players[i].id != -1)
{
puts("===");
printf("%-4d %-12s %-10s %5d %7d %11d %8d %8.2f\n",
players[i].id, players[i].fname, players[i].lname,
players[i].stage_num, players[i].hit_num, players[i].base_num,
players[i].rbi, players[i].hit_rate);
}
}
}
累加函数处可以这样修改 :
修改第二个for循环的条件。
//相同编号信息累加
void add_messages(TEAM players[],int n)
{
int i,i2;
if(n == 0)
{
printf("No datas!\n");
}
//冒泡比较
for (i = 0; i < n; i++)
{
for (i2 = i + 1; i2 < n; i2++)//i2 = 0 --> i2 = i + 1
{
if (i == i2)
{
continue;
}
if (strcmp(players[i].fname,players[i2].fname) == 0 && strcmp(players[i].lname,players[i2].lname) == 0)
{
players[i].base_num +=players[i2].base_num;
players[i].hit_num +=players[i2].hit_num;
players[i].hit_rate +=players[i2].hit_rate;
players[i].rbi +=players[i2].rbi;
players[i].stage_num +=players[i2].stage_num;
players[i2].id = -1;//如果相近两个编号都是同一个人,该处可以防止累加完之后,第二个编号还存在
printf("go to add -----\n");
//memset(players[i2].fname,i,sizeof(players[i2].fname)); //打乱数据防止再进入....
//memset(players[i2].fname,i2,sizeof(players[i2].fname)); //
}
}
}
printf("ADD ---------------------------------OVER\n");
putchar('\n');
return ;
}
14.7 (1)
- 首地址可以做简写操作,因为&name[0]和name的地址是相同的,而数组后面的其余元素,就需要进行取地址操作&name[index]。
- 注意结构体的嵌套,结构体数组中包含结构体变量、布尔类型值–>结构体变量中含有自身结构体的各类成员属性。
- 这里的结构体数组,每个下标对应两个成员属性(书本信息的结构体、是否删除的布尔判断);书本信息的结构体含有 :标题、作者、价格信息。
- 2-21号的代码因为会每次清空文件,所以 优先打印【不用删除的书籍数量filecount = %d】的信息,提示用户输入数据。不过输入过后,txt文件中可以看到我们的输入
- 写入文件 :要fwrite写入下午那种结构体 可以先把结构体内容用sprintf放到一个字符串char buf[]中 在把buf用fwirte写入 就不会乱码了
//2-21
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 10
#define CONTINUE 0
#define DONE 1
struct book
{
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
struct pack
{
struct book books;
bool canceled;
};
struct pack lib;
char *s_gets(char *st, int n);
int get_first(const char *str);
int get_books(struct pack *pb);
void update(struct pack *item);
void eatline(void);
int main(void)
{
struct pack library[MAXBKS];
//这里的结构体数组,每个下标对应两个成员属性(书本信息的结构体、是否删除的布尔判断)
//书本信息的结构体含有 :标题、作者、价格信息
int count = 0;
int deleted = 0;
int index, filecount, open;
FILE *pbooks;
int size = sizeof(struct book);
if ((pbooks = fopen("book.txt", "rb")) != NULL)
{
while (count < MAXBKS && fread(&library[count], size, 1, pbooks) == 1)
{
if (count == 0)
{
puts("book.dat的当前第一行的内容是:");
}
printf("%s by %s: $%.2f\n", library[count].books.title,
library[count].books.author, library[count].books.value);
putchar('\n');
printf("Do you want to change or delete this entry(y/n)?\n");
printf("Please you enter to choose: ");
if(get_first("yn") == 'y')
{
puts("=$$$");
printf("Enter c to change, d to delete entry: ");
if(get_first("cd") == 'd')
{
library[count].canceled = true;//作为删除标记
deleted ++;//删除数量加加
printf("deleted = %d\n",deleted);
puts("标记为删除的标记(下一本书的空格)。");
}
else
{
puts("修改原书籍内容");
update(&library[count]);//修改原书籍内容,传递结构体数组的地址
}
}
count ++;//统计数量加加
putchar('\n');
}
if(fclose(pbooks) != 0)
{
fprintf(stderr, "Error in closing file.\n");
}
printf("书籍数量 :count = %d\n", count);
}
//==============
filecount = count - deleted; //不用删除的书籍数量;
printf("不用删除的书籍数量filecount = %d\n",filecount);
if(count == MAXBKS)
{
puts("=!!");
fputs("The book.dat file is full.", stderr);
exit(EXIT_FAILURE);
}
//==============
putchar('\n');
if(deleted > 0)
{
printf("If you delete some books, 您应该输入书籍来替换 .\n");
}
puts("Please add new book titles.");
puts("Press [enter] at the start of a line to stop.");
open = 0;
while(filecount < MAXBKS)
{
puts("不用删除的书籍数量比总数10少,那么:");
if(filecount < count) //删除书可以循环的次数,无法直接删除,只能用新书替换
{
putchar('\n');
puts("删除书可以循环的次数,无法直接删除,只能用新书替换");
while(library[open].canceled == false)
{
puts("跳转到要删除的书的位置处");
open++;
//该结构体数组元素位置上的数据删除失败,跳转到要删除的书的位置处(下一个元素处);
}
if(get_books(&library[open]) == DONE)
{
puts("=*=*=*");
break;//若未输入新书覆盖原有书籍则循环终止
}
}
else if(get_books(&library[filecount]) == DONE)
{
puts("添加了新的书籍");
break;//添加新的书籍;
}
filecount++;//未删除书籍数量加加
putchar('\n');
printf("当前书籍数量filecount2= %d\n",filecount);
if(filecount < MAXBKS)
{
puts("Enter the next book title.");
}
}
//==============
putchar('\n');
puts("Here is the list of your books:");
for(index = 0; index < filecount; index++)
{
if(library[index].canceled == false)
{
puts("书本信息:");
printf("%s by %s : $%.2f\n", library[index].books.title,
library[index].books.author, library[index].books.value);
}
}
//把修改的内容写到文件中去
putchar('\n');
if((pbooks = fopen("book.txt", "wb")) == NULL)
{
fputs("Can't open book.dat file for output.\n", stderr);
exit(EXIT_FAILURE);
}
for(index = 0; index < filecount; index++)
{
int s_number = 0;
int w_number = 0;
char buf[200] = {0};
puts("修改内容写入到文件:");
if(library[index].canceled == false)
{
s_number = sprintf(buf,"%s %s %f \n",library[index].books.title,
library[index].books.author,library[index].books.value);
w_number = fwrite(buf, s_number, 1, pbooks);
if( w_number != 1)
{
printf("write error\n");
}
}
}
if (fclose(pbooks) != 0)
{
fprintf(stderr, "Error in closing file.\n");
}
puts("Bye.\n");
return 0;
}
//判断我们的输入getchar(输入的是字符),在传递过来的字符串中吗
int get_first(const char *str)
{
int ch;
ch = tolower(getchar());
while(strchr(str, ch) == NULL)
{
putchar('\n');
printf("Invalid data! Please enter again:\n");
eatline();
//如果不在,清理一下输入行,再次输入
ch = tolower(getchar());
}
eatline();
return ch;
}
//保存用户输入的书籍的数据(该类信息都在结构体中)
int get_books(struct pack *pb)
{
int status = CONTINUE;
//辅助判断
printf("Now enter the title /or/ Press Enter to exit: \n");
if(s_gets(pb->books.title, MAXTITL) == NULL || pb->books.title[0] == '\0')
{
status = DONE;
//若是输入EOF或换行符则改变status的值并将其返回(无新内容输入)
}
else
{
putchar('\n');
printf("Now enter the author: \n");
s_gets(pb->books.author, MAXAUTL);
printf("Now enter the value: ");
while(scanf("%f", &pb->books.value) != 1)
{
eatline();
puts("Please enter a valid value: ");
}
eatline();
pb->canceled = false;
}
printf("成功、失败的标志(0成功,1失败)status = %d\n",status);
return status;
//返回成功、失败的标志
}
//对书籍内容的修改,需要对结构体中的成员变量进行操作
void update(struct pack *item)
{
int ch;
struct book copy;
copy = item->books;//保存原书的内容以便修改(对临时变量进行操作)
putchar('\n');
puts("============================================");
puts("t) modify title a) modify author");
puts("v) modify value s) quit and save changes");
puts("q) quit and ignore changes");
puts("============================================");
printf("Please you enter to choose: ");
//可以先选择对结构体临时变量中的成员属性进行赋值操作
while((ch = get_first("tavsq")) != 's' && ch != 'q')
{
switch(ch)
{
case 't':
{
printf("Please enter new title: ");
s_gets(copy.title, MAXTITL);
break;
}
case 'a':
{
printf("Please enter new author: ");
s_gets(copy.author, MAXAUTL);
break;
}
case 'v':
{
printf("Please enter new value: ");
while(scanf("%f", ©.value) != 1)
{
eatline();
puts("Please enter a valid value: ");
}
eatline();
break;
}
}
putchar('\n');
puts("============================================");
puts("t) modify title a) modify author");
puts("v) modify value s) quit, saving changes");
puts("q) quit, ignore changes");
puts("============================================");
printf("You can choose again: ");
//在输入成功后不想修改书籍内容,输入q退出程序且不改变原书的内容;
}
if(ch == 's')
{
item->books = copy;//修改了原书的内容
}
return;
}
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)
{
*find = '\0';
}
else
{
while (getchar() != '\n')
continue;
}
}
return ret_val;
}
void eatline(void)
{
while (getchar() != '\n')
continue;
return;
}
2-21修改的代码,每次运行程序,都会把txt文件中的数据清零
.
.
14.7(2)这次虽然不会情况文档,但是会是txt中打开会显示乱码
- 将向写入文件的操作,改成了直接fwrite的操作,不再经过数组了
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 10
#define CONTINUE 0
#define DONE 1
struct book
{
char title[MAXTITL];
char author[MAXAUTL];
float value;
};
struct pack
{
struct book books;
bool canceled;
};
char *s_gets(char *st, int n);
int get_first(const char *str);
int get_books(struct pack *pb);
void update(struct pack *item);
void eatline(void);
int main(void)
{
struct pack library[MAXBKS];
//这里的结构体数组,每个下标对应两个成员属性(书本信息的结构体、是否删除的布尔判断)
//书本信息的结构体含有 :标题、作者、价格信息
int count = 0;
int deleted = 0;
int index, filecount, open;//书籍结构体数组下标
FILE *pbooks;
FILE *pbooks1;
int size = sizeof(struct book);
if ((pbooks = fopen("book.txt", "rb")) != NULL)
{
while (count < MAXBKS && fread(&library[count], size, 1, pbooks) == 1)
{
if (count == 0)
{
puts("book.dat的当前第一行的内容是:");
}
//for(count = 0; count < MAXBKS; count ++)
//{
printf("%s by %s: $%.2f\n", library[count].books.title,
library[count].books.author, library[count].books.value);
//}
putchar('\n');
printf("Do you want to change or delete this entry(y/n)?\n");
printf("Please you enter to choose: ");
if(get_first("yn") == 'y')
{
puts("=$$$");
printf("Enter c to change, d to delete entry: ");
if(get_first("cd") == 'd')
{
library[count].canceled = true;//作为删除标记
deleted ++;//删除数量加加
printf("deleted = %d\n",deleted);
puts("标记为删除的标记(下一本书的空格)");
}
else
{
puts("修改原书籍内容");
update(&library[count]);//修改原书籍内容,传递结构体数组的地址
}
}
count ++;//统计数量加加
}
putchar('\n');
printf("循环次数count = %d\n", count);
if(fclose(pbooks) != 0)
{
fprintf(stderr, "Error in closing file.\n");
}
}
//==============
filecount = count - deleted; //不用删除的书籍数量(若内容为0,会优先打印该行)
printf("不用删除的书籍数量filecount = %d\n",filecount);
if(count == MAXBKS)
{
puts("=!!");
fputs("The book.dat file is full.", stderr);
exit(EXIT_FAILURE);
}
//==============
putchar('\n');
if(deleted > 0)
{
printf("If you delete some books, 您应该输入书籍来替换 .\n");
}
puts("Please add new book titles.");
puts("Press [enter] at the start of a line to stop.");
open = 0;
while(filecount < MAXBKS)
{
puts("不用删除的书籍数量比总数10少,那么:");
if(filecount < count) //删除书可以循环的次数,无法直接删除,只能用新书替换
{
putchar('\n');
puts("删除书可以循环的次数,无法直接删除,只能用新书替换");
while(library[open].canceled == false)
{
puts("跳转到要删除的书的位置处==>");
open++;
//该结构体数组元素位置上的数据删除失败,跳转到要删除的书的位置处(下一个元素处);
}
if(get_books(&library[open]) == DONE)
{
puts("若未输入新书覆盖原有书籍则循环终止==>");
break;//若未输入新书覆盖原有书籍则循环终止
}
}
else if(get_books(&library[filecount]) == DONE)
{
puts("添加了新的书籍==>");
break;//添加新的书籍;
}
filecount++;//未删除书籍数量加加
printf("filecount2= %d\n",filecount);
if(filecount < MAXBKS)
{
puts("Enter the next book title.");
}
}
//==============
putchar('\n');
puts("Here is the list of your books:");
for(index = 0; index < filecount; index++)
{
if(library[index].canceled == false)
{
puts("书本信息:");
printf("%s by %s : $%.2f\n", library[index].books.title,
library[index].books.author, library[index].books.value);
}
}
//把修改的内容写到文件中去
putchar('\n');
if((pbooks1 = fopen("book.txt", "wb")) == NULL)
{
fputs("Can't open book.dat file for output.\n", stderr);
exit(EXIT_FAILURE);
}
for(index = 0; index < filecount; index++)
{
puts("修改内容写入到文件:");
char buf[200] = {0};
int s_number = 0;
int w_number = 0;
if(library[index].canceled == false)//非删除项
{
//s_number = sprintf(buf, "%s %s %f", library[index].books.title, library[index].books.author,
//library[index].books.value);
fwrite(&(library[index].books), size, 1, pbooks1);
}
//w_number = fwrite(buf, s_number, 1, pbooks1);
//直接修改原文本内容;
/* 要fwrite写入下午那种结构体
*可以先把结构体内容用sprintf放到一个字符串char buf[]中
*在把buf用fwirte写入 就不会乱码了*/
//if(w_number != 1)
//{
// puts("fwrite error!");
//}
}
if (fclose(pbooks) != 0)
{
fprintf(stderr, "Error in closing file.\n");
}
puts("Bye.\n");
return 0;
}
//判断我们的输入getchar(输入的是字符),在传递过来的字符串中吗
int get_first(const char *str)
{
int ch;
ch = tolower(getchar());
while(strchr(str, ch) == NULL)
{
putchar('\n');
printf("Invalid data! Please enter again:\n");
eatline();
//如果不在,清理一下输入行,再次输入
ch = tolower(getchar());
}
eatline();
return ch;
}
//保存用户输入的书籍的数据(该类信息都在结构体中)
int get_books(struct pack *pb)
{
int status = CONTINUE;
//辅助判断
printf("Now enter the title: \n");
if(s_gets(pb->books.title, MAXTITL) == NULL || pb->books.title[0] == '\0')
{
status = DONE;
//若是输入EOF或换行符则改变status的值并将其返回(无新内容输入)
}
else
{
putchar('\n');
printf("Now enter the author: \n");
s_gets(pb->books.author, MAXAUTL);
printf("Now enter the value: ");
while(scanf("%f", &pb->books.value) != 1)
{
eatline();
puts("Please enter a valid value: ");
}
eatline();
pb->canceled = false;
}
return status;
//返回成功、失败的标志
}
//对书籍内容的修改,需要对结构体中的成员变量进行操作
void update(struct pack *item)
{
int ch;
struct book copy;
copy = item->books;//保存原书的内容以便修改(对临时变量进行操作)
putchar('\n');
puts("============================================");
puts("t) modify title a) modify author");
puts("v) modify value s) quit and save changes");
puts("q) quit and ignore changes");
puts("============================================");
printf("Please you enter to choose: ");
//可以先选择对结构体临时变量中的成员属性进行赋值操作
while((ch = get_first("tavsq")) != 's' && ch != 'q')
{
switch(ch)
{
case 't':
{
printf("Please enter new title: ");
s_gets(copy.title, MAXTITL);
break;
}
case 'a':
{
printf("Please enter new author: ");
s_gets(copy.author, MAXAUTL);
break;
}
case 'v':
{
printf("Please enter new value: ");
while(scanf("%f", ©.value) != 1)
{
eatline();
puts("Please enter a valid value: ");
}
eatline();
break;
}
}
putchar('\n');
puts("============================================");
puts("t) modify title a) modify author");
puts("v) modify value s) quit, saving changes");
puts("q) quit, ignore changes");
puts("============================================");
printf("You can choose again: ");
//在输入成功后不想修改书籍内容,输入q退出程序且不改变原书的内容;
}
if(ch == 's')
{
item->books = copy;//修改了原书的内容,并保存
}
return;
}
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)
{
*find = '\0';
}
else
{
while (getchar() != '\n')
continue;
}
}
return ret_val;
}
void eatline(void)
{
while (getchar() != '\n')
continue;
return;
}
14.7 (3)-开辟堆区内存
感觉这样的方法会更好一点,所有地方都分块去完成,且使用了函数指针的方法,更简洁;采用了在堆区开辟空间的方式去存储我们的书籍信息,相当于一个安全的临时变量(结构体指针变量-指向堆区的地址),不会影响到文本本来的内容。
//由于no7.c代码结构混乱,语句冗长,可读性,与维护性较低,所以最终决定重构no7.c
//以下程序思路,基于内存操作,使用了函数指针等简洁,可读性,维护性较高的技巧
//执行原理,程序启动将读取指定文件内所有内容,将内容整个放在内存中,关闭文件.
//接下来的增删查改等操作都对内存操作,当程序结束时,将内存中的所有数据重新写入
//文件内.
//缺点是对内存开销较大...但是目前我还未想到更好的办法
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
//# include <windows.h>
# define MAXTITL 20 //最大书名长度
# define MAXAUTL 20 //最大作者名长度
# define FILENAME "book.dat" //宏定义文件名
# define FLDWIDTH 15 //字段宽度(表格)
// 声明书籍结构体
typedef struct
{
char title[MAXTITL] ;
char author[MAXAUTL] ;
float value ;
}book;
//定义全局结构体
static struct
{
long COUNT ;
book * BOOKS ;
}LIBRARY;
long load_file(char * file);//从文件读数据
long refresh_file(char * file);//写入文件
void print_hline(const char ch , int count);
void print_squared(const char * st , int fwidth);
char * s_gets(char * st , int n);
void out_menu(void);
int menu_choice(void);
void menu_end(void);
void lib_out(void); //查
void lib_modify(void); //改
void lib_add(void); //增
void lib_del(void); //删
int abort_operation(); //放弃操作
int main(void)
{
char ch[20] ;
load_file(FILENAME) ;
system("cls");
while (menu_choice()) //对数字的输入,让其在while循环中,不断提示用户哪些功能可选择
{
system("pause");
system("cls");
}
refresh_file(FILENAME);
free(LIBRARY.BOOKS);
return 0 ;
}
long load_file(char * file)
{
FILE * fp ;
long size = 0;
long item = 0 ;
if (!(fp = fopen(file , "rb"))) //打开文件失败
{
if (!(fp = fopen(file , "wb"))) //创建新的文件
{
fputs("创建文件失败" , stderr);
exit(1);
}
fclose(fp);
if (!(fp = fopen(file , "rb"))) //关闭文件并以读方式重新打开
{
fputs("打开文件失败" , stderr);
exit(1);
}
}
fseek(fp , 0L , SEEK_END); //定位到文件的结尾
size = ftell(fp); //统计文件中字节的大小
LIBRARY.COUNT = size / sizeof(book) ;
LIBRARY.BOOKS = (book *) calloc(LIBRARY.COUNT , sizeof(book)) ; //分配内存
rewind(fp); //文件指针重新定位到文件首
item = fread(LIBRARY.BOOKS , sizeof(book) , LIBRARY.COUNT , fp);//读取文件
fclose(fp);
return item ;
}
long refresh_file(char * file)
{
FILE * fp ;
long item = 0 ;
if (!(fp = fopen(file , "wb")))
{
fputs("更新文件失败" , stderr);
exit(2);
}
item = fwrite(LIBRARY.BOOKS , sizeof(book) , LIBRARY.COUNT , fp);
fclose(fp);
return item ;
}
void print_squared(const char * st , int fwidth) //实参传递过来的是字符串的地址信息 以及 字段宽度
{
printf("%-*c%s%*c" , (fwidth - strlen(st)) / 2 , '|' , st ,
(fwidth - strlen(st)) / 2 , '|');
printf("%s\n",(fwidth - strlen(st)) / 2);
}
void print_hline(const char ch , int count)
{
putchar(' ');
while (--count)
{
putchar(ch);
}
putchar('\n');
}
int menu_choice(void)
{
//meun包含函数指针的数组(每个都指向无形参,且无返回值类型的函数)
static const void (* menu[])(void) = {menu_end ,
lib_out , lib_modify , lib_add , lib_del};
int cmd = 0 ;
out_menu();
while (!scanf(" %d" , &cmd) || cmd < 0 || cmd > 4) //开始输入我们的选择
{
if ((cmd < 0) || (cmd > 4))
{
fputs("无效选择,请输入正确的序号:\n" , stderr);
}
else
{
fputs("非法输入\n" , stderr);
}
while (getchar() != '\n') ;
}
while (getchar() != '\n') ;
menu[cmd](); //函数指针,根据我们输入的数字,接收相对应的函数的地址,来实现功能
return cmd ; //返回成功输入的个数
}
void out_menu(void)
{
static char * menu[] =
{
"#################################",
"请选择您需要的操作:" ,
"1) 查看 2) 修改",
"3) 添加 4) 删除",
"0) 退出" ,
"#################################"
};
int i;
for( i = 0 ; i < sizeof(menu) / sizeof(menu[0]) ; i++)
{
puts(menu[i]);
//这是个指针数组,i对应字符串所在行号(6个字符串)
}
}
void menu_end(void)
{
puts("再见,祝您生活愉快!");
}
void lib_out(void)
{
static const char * label[] =
{
"书名" ,
"作者" ,
"价格"
} ; //指针数组
char tmp[100] ;
int i;
// 打印表头
print_hline('=' , (sizeof(label) / sizeof(label[0])) * FLDWIDTH - 4);
for ( i = 0 ; i < sizeof(label) / sizeof(label[0]) ; i++)
{
print_squared(label[i] , FLDWIDTH); //输出指针数组中的字符串
}
putchar('\n');
print_hline('=' , (sizeof(label) / sizeof(label[0])) * FLDWIDTH - 4);
// 打印数据
for (i = 0 ; i < LIBRARY.COUNT; i++)
{
print_squared(LIBRARY.BOOKS[i].title , FLDWIDTH);
print_squared(LIBRARY.BOOKS[i].author , FLDWIDTH);
sprintf(tmp ,"%.1f" ,LIBRARY.BOOKS[i].value) ;
print_squared(tmp , FLDWIDTH);
putchar('\n');
print_hline('-' , (sizeof(label) / sizeof(label[0])) * FLDWIDTH - 4);
}
}
void lib_modify(void)
{
book tbook ;
char tstr[100] ;
char answer ;
int i ;
float tfloat = 0 ;
if (!LIBRARY.COUNT)
{
puts("书籍为空,不能修改");
return ;
}
lib_out();
puts("请输入您要修改的书名(输入空行退出):");
while (s_gets(tstr , 100) && tstr[0])
{
for (i = 0 ; i < LIBRARY.COUNT ; i++)
{
if (strcmp(LIBRARY.BOOKS[i].title , tstr) == 0)
{
break;
}
}
if (i > LIBRARY.COUNT - 1)
{ //未找到书名给出提示
puts("您输入的书名不存在!");
}
else
{
tbook = LIBRARY.BOOKS[i] ;
printf("书名: %s\n无需修改请按[Enter]输入空行\n" , tbook.title);
if (s_gets(tstr , 100) && tstr[0])
strncpy(tbook.title , tstr , MAXTITL) ;
printf("作者: %s\n无需修改请按[Enter]输入空行\n" , tbook.author);
if (s_gets(tstr , 100) && tstr[0])
strncpy(tbook.author , tstr , MAXAUTL);
printf("价格: %.1f\n无需修改请按[Enter]输入空行\n" , tbook.value);
while (!s_gets(tstr , 100) || !tstr[0] || (tfloat = atof(tstr)) <= 0)
{
if (!tstr[0])
{
tfloat = tbook.value ;
break ;
}
else
puts("输入价格无效,请重新输入");
}
tbook.value = tfloat ;
puts("=============================================");
printf("书名: %s\n作者: %s\n价格: %.1f\n" , tbook.title , tbook.author , tbook.value);
puts("您确定要修改?(y/n)");
if (scanf(" %c" , &answer) && 'y' == tolower(answer))
{
LIBRARY.BOOKS[i] = tbook ;
puts("修改成功!");
}
while (getchar() != '\n') ;
}
puts("请输入您要修改的下一本书名(空行退出)");
}
}
void lib_add(void)
{
book tbook = { 0} ;
char ch ;
char tmp[100] ;
float tfloat = 0 ;
puts("请输入您要添加的书名(输入空行退出)");
while (s_gets(tbook.title , MAXTITL) && !tbook.title[0])
{
if (abort_operation()) //放弃时都会进行提示
return ;
else
puts("请输入您要添加的书名(输入空行退出)");
}
puts("请输入该书的作者,或者出版社(输入空行退出)");
while (s_gets(tbook.author , MAXAUTL) && !tbook.author[0])
{
if (abort_operation())
return ;
else
puts("请输入该书的作者,或者出版社(输入空行退出)");
}
puts("请输入该书的价格(输入空行退出)");
while (!s_gets(tmp , 100) || !tmp[0] || (tfloat = atof(tmp)) <= 0)
{
if (!tmp[0])
{
if (abort_operation())
return ;
else
puts("请输入该书的价格(输入空行退出)");
}
else
puts("输入价格无效,请重新输入(输入空行退出)");
}
tbook.value = tfloat ;
puts("================================");
puts("以下是您要添加的书籍信息:");
printf("书名: %s\n" , tbook.title);
printf("作者: %s\n" , tbook.author);
printf("价格: %.1f\n" , tbook.value);
puts("确认添加吗?(y/n)");
if(scanf(" %c" , &ch) && 'y' == tolower(ch))
{
puts("添加成功");
LIBRARY.BOOKS = (book *)realloc(LIBRARY.BOOKS ,++LIBRARY.COUNT * sizeof(book)) ;
//为新添加的书籍分配地址空间
LIBRARY.BOOKS[LIBRARY.COUNT - 1] = tbook ;
//LIBRARY.BOOKS[LIBRARY.COUNT - 1] :相当于指针数组,其中的每个元素都指向book结构体中的各类成员信息
//将为book结构体中新添加的成员信息,赋值给对应的数组元素中
}
}
void lib_del(void)
{
char tmp_title[MAXTITL] ;
int i ;
int j;
if (!LIBRARY.COUNT)
{
puts("书籍为空,不能删除");
return ;
}
lib_out();
puts("请输入您要删除的书名(空行退出)");
while (s_gets(tmp_title ,MAXTITL) && tmp_title[0])
{
//寻找相同的书名
for (i = 0 ; i < LIBRARY.COUNT ; i++)
{
if (strcmp(LIBRARY.BOOKS[i].title , tmp_title) == 0)
break;
}
if (i > LIBRARY.COUNT - 1)
{ //未找到书名给出提示
puts("您输入的书名不存在!");
}
else
{
for ( j = i ; j < LIBRARY.COUNT ; j++) //在后一本覆盖掉上一本的同时,就删除掉一个book结构体指针所指的堆区空间
LIBRARY.BOOKS[j] = LIBRARY.BOOKS[j + 1] ;
LIBRARY.BOOKS = (book *)realloc(LIBRARY.BOOKS , --LIBRARY.COUNT * sizeof(book));
//去掉一个堆区的内存空间
puts("删除成功!");
}
puts("请输入您要删除的书名(空行退出)");
}
}
int abort_operation()
{
int answer = 0 ;
char ch ;
puts("你确定要放弃本次操作,并返回菜单页面?(y/n)");
if (scanf(" %c" , &ch) && 'y' == tolower(ch))
{
answer = 1 ;
}
else
{
answer = 0 ;
}
while (getchar() != '\n');
return answer ;
}
char * s_gets(char * st , int n)
{
char * find ;
if (fgets(st , n , stdin))
{
if (find = strchr(st , '\n'))
*find = '\0' ;
else
while (getchar() != '\n') ;
}
return st ;
}
14.8(1)-有BUG想找问题的可以到这里
//巨人航空公司的机群由12个座位的飞机组成.它每天飞行一个航班.根据下面的要求,编写一个座位预定程序
//a. 该程序使用一个内含12个结构的数组.每个结构中包括:一个成员表示座位编号.一个成员表示座位是否
// 已经被预定,一个成员表示预定人名,一个成员表示预定人的姓.
//b. 该程序显示下面的菜单:
// To choose a function enter its letter label:
// a) Show number of empty seats
// b) Show list of emppty 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 <ctype.h>
#include <string.h>
#include <stdlib.h> //该头文件别忘加,否则使用malloc会报错
#define NAME_LEN 50
#define SEAT_COUNT 12
typedef struct
{
int number;
int selected;
char name[NAME_LEN];
char s_name[NAME_LEN];
}seat;
static seat plane_seat[SEAT_COUNT]; //全局静态变量中数据已清0;
int initialize_seat(seat * pstr , int n);
void print_menu(void);
char choice_menu(void);
int switch_menu(char choice, seat *pstr);
int empty_seat_count(int n, const seat * pstr);
int show_seat_list(int n, const seat * pstr);
int sort_seat_list(int n, seat * pstr );
int choice_seat(int n, seat * pstr );
int delte_seat(int n, seat * pstr );
char * s_gets(char * st , int n);
int main(void)
{
seat plane_seat[SEAT_COUNT];
initialize_seat(plane_seat, SEAT_COUNT); //初始化结构体成员
while(switch_menu(choice_menu(), plane_seat));
return 0;
}
void eatline(void)
{
while (getchar() != '\n')//处理掉不需要的字符
continue;
}
int initialize_seat(seat *ps, int n)
{
int i;
for(i = 0; i < n; i++)
{
ps[i].number = i + 1;
ps[i].selected = 0;
memset(ps[i].name, '\0', sizeof(ps[i].name));
memset(ps[i].s_name, '\0', sizeof(ps[i].s_name));
}
return (i == n ? i : 0);
}
void print_menu(void)
{
static char *menu[] =
{
"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",
};
int i;
for(i = 0; i < sizeof(menu)/sizeof(menu[0]); i++)
{
puts(menu[i]);
}
}
char gets_input(void)
{
int ch;
//char p[20];
//p = (char)malloc(20 * sizeof(p));
//ch = tolower(scanf("%c", &ch));
ch = getchar();
ch = tolower(ch);
eatline(); // 清理输入行
return ch;
}
char choice_menu(void)
{
char ch;
print_menu();
while(gets_input())
{
if(strchr("abcde", ch) == NULL)
{
fputs("无效选择,请输入abcde.\n" , stderr);
}
else
{
fputs("输入正确~\n" , stderr);
}
}
eatline();
return ch;
puts(ch);
}
int switch_menu(char choice, seat *pstr)
{
switch (choice)
{
case 'a' :
//显示未预定的座位数量
empty_seat_count(pstr , SEAT_COUNT);
system("pause");
return 1;
case 'b' :
//显示空的座位列表
show_seat_list(pstr , SEAT_COUNT);
system("pause");
return 1 ;
case 'c' :
//按字母顺序显示座位列表
sort_seat_list(pstr , SEAT_COUNT) ;
system("pause");
return 1 ;
case 'd' :
//为客户分配座位
choice_seat(pstr , SEAT_COUNT);
show_seat_list(pstr , SEAT_COUNT);
system("pause");
return 1 ;
case 'e' :
//删除座位分配
delte_seat(pstr , SEAT_COUNT);
show_seat_list(pstr , SEAT_COUNT);
system("pause");
return 1 ;
case 'f' :
//退出
return 0 ;
default :
//错误选择
puts("无效选择,请重新选择");
system("pause");
return 1 ;
}
}
int empty_seat_count(int n, const seat *ps)
{
puts("显示未预定的座位数量");
int count = 0;
int i;
for(i = 0; i < n; i++)
{
if(ps[i].selected == 0)
{
count ++;
}
}
printf("现在空座为还剩%d个\n" , count);
return count;
}
int show_seat_list(int n, const seat *ps)
{
int i;
puts("显示空的座位列表");
puts("当前座位信息:");
for(i = 0; i < n; i++)
{
printf("座位号 :%-5d %-5d 名 :%-20s 姓:%-20s\n",ps[i].number,
ps[i].selected ? "已预定" : "未预定",
ps[i].name,
ps[i].s_name);
}
return i;
}
int sort_seat_list(int n , seat *ps)
{
puts("按字母顺序显示座位列表");
seat **ps_arr;
seat *tmp;
int min;
int i, j;
ps_arr = (seat **)calloc(n, sizeof(seat *));
for(i = 0; i < n; i++)
{
ps_arr[i] = &ps[i];
}
for(i = 0; i < n - 1; i++)
{
min = i;
for(j = i+1; j < n; j++)
{
if(strcmp(ps_arr[min]->name, ps_arr[j]->name) > 0)
{
min = j;
}
}
if(min != i)
{
tmp = ps_arr[i];
ps_arr[i] = ps_arr[min];
ps_arr[min] = tmp;
}
}
for(i = 0; i < n; i++)
{
printf("座位号 :%-5d %-5d 名 :%-20s 姓:%-20s\n",ps[i].number,
ps[i].selected ? "已预定" : "未预定",
ps[i].name,
ps[i].s_name);
}
free(ps_arr);
}
int choice_seat(int n, seat *ps)
{
puts("为客户分配座位");
seat t;
char ch;
int flag = 0;
puts("请输入您要挑选的座位号:");
while(!scanf(" %d", &t.number) || t.number < 1 || t.number > n \
|| (flag = ps[t.number -1].selected))
{
eatline();
if(flag)
{
puts("此座位已被预定,请重新选择座位:");
flag = 0 ;
}
else
{
puts("非法输入,请重新输入座位号:");
}
}
eatline();
puts("锁定此座位后,请输入姓名:");
t.selected = 1; //锁定此座位
puts("请输入您的名:");
while(!s_gets(t.name, NAME_LEN));
{
puts("非法输入,请重新输入您的名:");
}
puts("请输入您的姓:");
while (!s_gets(t.s_name , NAME_LEN))
{
puts("非法输入,请重新输入您的姓:");
}
puts("======================================");
printf("座位号: %d\n名:%s\n姓:%s\n" ,t.number, t.name, t.s_name);
puts("确认预约此座吗?(y/n):");
while(!(scanf(" %d"), &ch) || !isalpha(ch = tolower(ch)))
{
puts("非法输入,请重新输入");
}
if(ch == 'y')
{
ps[t.number -1] = t;
return 1;
}
else
return 0;
}
int delte_seat(int n, seat *pstr)
{
int num;
int flag = 0;
//int i;
char ch;
puts("请输入您要删除的座位号:");
while(!scanf(" %d", &num) || num < 1 || num > n \
|| (flag = !pstr[num -1].selected))
{
eatline();
if (flag)
{
puts("取消预约失败,此座位并未被预约");
flag = 0 ;
}
else
{
puts("非法输入,请重新输入要取消预约的座位号:");
}
}
eatline();
puts("======================================");
printf("座位号: %d\n名:%s\n姓:%s\n" , pstr[num - 1].number , pstr[num - 1].name , pstr[num - 1].s_name);
puts("确认此座取消预约吗?(y/n):");
while(!scanf(" %c", &ch) || !isalpha(ch = tolower(ch)))
{
;
}
if(ch == 'y')
{
pstr[num - 1].selected = 0;
pstr[num - 1].name[0] = '\0';
pstr[num - 1].s_name[0] = '\0' ;
return 1 ;
}
else
return 0;
}
char * s_gets(char * st , int n)
{
char * ret_value = NULL ;
char * find ;
if (ret_value = fgets(st , n , stdin))
{
if (find = (strchr(st , '\n')))
*find = '\0' ;
else
while (getchar() != '\n') ;
}
return ret_value ;
}
14.8(2)已经解决问题版本
flag = pstr[tmp.number - 1].selected :其中
1、tmp.number - 1
表示 :我们输入的number ,按照数组下标理解–>数组下标从0开始排列,因此此处需要-1
2、selected 是标记该位置有没有被选取的标志,1已经选取,0未选取
3、flag判断位置有无预订
.
.
删除函数中flag = !pstr[num - 1].selected
1、当selected = 0时,该位置未被预订,对其取反使得flag = 1,进入下面的"取消预约失败,此座位并未被预约"的判断语句中
2、此处flag依旧是判断用
.
.
sort_seat_list(seat *ps, int n)函数中
1、 ps_arr = (seat **)calloc(n, sizeof(seat *)); //为ps_arr在堆区分配n个sizeof(seat *)
大小的空间让其去指向
2、ps_arr[i] 就相当于指针数组,保存我们所定义的结构体指针ps_arr[i] = &ps[i]
//巨人航空公司的机群由12个座位的飞机组成.它每天飞行一个航班.根据下面的要求,编写一个座位预定程序
//a. 该程序使用一个内含12个结构的数组.每个结构中包括:一个成员表示座位编号.一个成员表示座位是否
// 已经被预定,一个成员表示预定人名,一个成员表示预定人的姓.
//b. 该程序显示下面的菜单:
// To choose a function enter its letter label:
// a) Show number of empty seats
// b) Show list of emppty 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 <ctype.h>
#include <string.h>
#include <stdlib.h> //该头文件别忘加,否则使用malloc会报错
#define NAME_LEN 50
#define SEAT_COUNT 12
typedef struct
{
int number;
int selected;
char name[NAME_LEN];
char s_name[NAME_LEN];
}seat;
//static seat plane_seat[SEAT_COUNT]; //全局静态变量中数据已清0;
int initialize_seat(seat * pstr , int n);
void print_menu(void);
char choice_menu(void);
int switch_menu(int choice, seat *pstr);
int empty_seat_count(const seat * ps,int n);
int show_seat_list(const seat * ps,int n);
int sort_seat_list(seat * ps,int n);
int choice_seat(seat * ps,int n);
int delte_seat(seat * pstr,int n );
char * s_gets(char * st , int n);
//char gets_input(void);
int main(void)
{
seat plane_seat[SEAT_COUNT] ;
initialize_seat(plane_seat , SEAT_COUNT); //初始化座位
while (switch_menu(choice_menu() , plane_seat)) ;
puts("Bye. See you next!");
return 0 ;
}
void eatline(void)
{
while (getchar() != '\n')//处理掉不需要的字符
continue;
}
int initialize_seat(seat *ps, int n)
{
int i;
for(i = 0; i < n; i++)
{
ps[i].number = i + 1;
ps[i].selected = 0;
memset(ps[i].name, '\0', sizeof(ps[i].name));
memset(ps[i].s_name, '\0', sizeof(ps[i].s_name));
}
return (i == n ? i : 0);
}
void print_menu(void)
{
static char *menu[] =
{
"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"
};
int i;
for(i = 0; i < sizeof(menu)/sizeof(menu[0]); i++)
{
puts(menu[i]);
}
}
char choice_menu(void)
{
char ch ;
print_menu();
while (!scanf(" %c" , &ch) || !isalpha(ch = tolower(ch)))
{
while (getchar() != '\n') ;
puts("输入非法,请重新输入");
}
while (getchar() != '\n') ;
return ch ;
}
int switch_menu(int choice , seat * pstr)
{
switch (choice)
{
case 'a' :
//显示未预定的座位数量
empty_seat_count(pstr , SEAT_COUNT);
system("pause");
return 1;
case 'b' :
//显示空的座位列表
show_seat_list(pstr , SEAT_COUNT);
system("pause");
return 1 ;
case 'c' :
//按字母顺序显示座位列表
sort_seat_list(pstr , SEAT_COUNT) ;
system("pause");
return 1 ;
case 'd' :
//为客户分配座位
choice_seat(pstr , SEAT_COUNT);
show_seat_list(pstr , SEAT_COUNT);
system("pause");
return 1 ;
case 'e' :
//删除座位分配
delte_seat(pstr , SEAT_COUNT);
show_seat_list(pstr , SEAT_COUNT);
system("pause");
return 1 ;
case 'f' :
//退出
return 0 ;
default :
//错误选择
puts("无效选择,请重新选择");
system("pause");
return 1 ;
}
}
int empty_seat_count(const seat *ps, int n)
{
puts("显示未预定的座位数量");
int count = 0;
int i;
for(i = 0; i < n; i++)
{
if(ps[i].selected == 0)
{
count ++;
}
}
printf("现在空座为还剩%d个\n" , count);
return count;
}
int show_seat_list( const seat *ps, int n)
{
int i;
puts("显示空的座位列表");
puts("当前座位信息:");
for(i = 0; i < n; i++)
{
printf("座位号 :%-5d %-5d 名 :%-20s 姓:%-20s\n",ps[i].number,
ps[i].selected ? "已预定" : "未预定",
ps[i].name,
ps[i].s_name);
}
return i;
}
int sort_seat_list(seat *ps, int n)
{
puts("按字母顺序显示座位列表");
seat **ps_arr;
seat *tmp;
int min;
int i, j;
ps_arr = (seat **)calloc(n, sizeof(seat *)); //为ps_arr在堆区分配n个sizeof(seat *)大小的空间让其去指向
for(i = 0; i < n; i++)
{
ps_arr[i] = &ps[i]; //ps_arr相当于指针数组,保存有0-11个结构体指针
}
for(i = 0; i < n - 1; i++)
{
min = i;
for(j = i+1; j < n; j++)
{
if(strcmp(ps_arr[min]->name, ps_arr[j]->name) > 0)
{
min = j;
}
}
if(min != i)
{
tmp = ps_arr[i];
ps_arr[i] = ps_arr[min];
ps_arr[min] = tmp;
}
}
for(i = 0; i < n; i++)
{
printf("座位号 :%-5d %-5s 名 :%-20s 姓:%-20s\n",ps_arr[i]->number,
ps_arr[i]->selected ? "已预定" : "未预定",
ps_arr[i]->name,
ps_arr[i]->s_name);
}
free(ps_arr);
}
int choice_seat(seat *ps, int n)
{
puts("为客户分配座位");
seat t;
char ch;
int flag = 0;
puts("请输入您要挑选的座位号:");
while(!scanf(" %d", &t.number) || t.number < 1 || t.number > n \
|| (flag = ps[t.number -1].selected))
{
eatline();
if(flag) //selected==1 说明被预订
{
puts("此座位已被预定,请重新选择座位:");
flag = 0 ;
}
else
{
puts("非法输入,请重新输入座位号:");
}
}
eatline();
puts("锁定此座位后,请输入姓名:");
t.selected = 1; //锁定此座位
puts("请输入您的名:");
while(!s_gets(t.name, NAME_LEN));
{
puts("非法输入,请重新输入您的名:");
}
puts("请输入您的姓:");
while (!s_gets(t.s_name , NAME_LEN))
{
puts("非法输入,请重新输入您的姓:");
}
puts("================输入完毕的结构体成员属性======================");
printf("座位号: %d\n名:%s\n姓:%s\n" ,t.number, t.name, t.s_name);
puts("确认预约此座吗?(y/n):");
while(!scanf(" %c", &ch) || !isalpha(ch = tolower(ch)))
{
puts("非法输入,请重新输入");
}
if(ch == 'y')
{
ps[t.number -1] = t; //在为结构体中成员属性赋值完毕后,将其赋给结构体数组对应元素中
return 1;
}
else
return 0;
}
int delte_seat(seat *pstr, int n)
{
int num;
int flag = 0;
//int i;
char ch;
puts("请输入您要删除的座位号:");
while(!scanf(" %d", &num) || num < 1 || num > n \
|| (flag = !pstr[num -1].selected))
{
eatline();
if (flag)
{
puts("取消预约失败,此座位并未被预约");
flag = 0 ;
}
else
{
puts("非法输入,请重新输入要取消预约的座位号:");
}
}
eatline();
puts("================删除结构体对应下标所属成员======================");
printf("座位号: %d\n名:%s\n姓:%s\n" , pstr[num - 1].number , pstr[num - 1].name , pstr[num - 1].s_name);
puts("确认此座取消预约吗?(y/n):");
while(!scanf(" %c", &ch) || !isalpha(ch = tolower(ch)))
{
;
}
if(ch == 'y') //输入数字作为下标索引,找到对应结构体数组,将该元素下标对应的成员全部清零
{
pstr[num - 1].selected = 0;
pstr[num - 1].name[0] = '\0';
pstr[num - 1].s_name[0] = '\0' ;
return 1 ;
}
else
return 0;
}
char * s_gets(char * st , int n)
{
char * ret_value = NULL ;
char * find ;
if (ret_value = fgets(st , n , stdin))
{
if (find = (strchr(st , '\n')))
*find = '\0' ;
else
while (getchar() != '\n') ;
}
return ret_value ;
}
bug
`choice_menu’函数的实现没有,只有声明在,添加上功能实现代码即可
14.9
一些小地方的理解
对清空函数initialize_airline()
中,多维数组的理解
这里的多维数组,其实已经可以按照一个一维数组进行理解 :因为我们这里的“清零”,是针对座位而言,并不附加对航班的解释,所以单独对座位进行“清零”,只需要知道有多少个座位即可,一切按照一维数组首地址+数字
去理解
(首地址+数字 :顺序指向其在数组中的位置)
//巨人航空公司的机群由12个座位的飞机组成.它每天飞行一个航班.根据下面的要求,编写一个座位预定程序
//a. 该程序使用一个内含12个结构的数组.每个结构中包括:一个成员表示座位编号.一个成员表示座位是否
// 已经被预定,一个成员表示预定人名,一个成员表示预定人的姓.
//b. 该程序显示下面的菜单:
// To choose a function enter its letter label:
// a) Show number of empty seats
// b) Show list of emppty 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 <ctype.h>
#include <string.h>
#include <stdlib.h> //该头文件别忘加,否则使用malloc会报错
#define NAME_LEN 50
# define FLIGHT_COUNT 4
#define SEAT_COUNT 12
typedef struct
{
int number;
int selected;
char name[NAME_LEN];
char s_name[NAME_LEN];
}seat;
//static seat plane_seat[SEAT_COUNT]; //全局静态变量中数据已清0;
int initialize_airline(seat * pstr, int r, int c);
void print_menu(int n);
char choice_menu(int n);
int switch_menu(int choice, seat * pstr);
int empty_seat_count(const seat * pstr, int n);
int show_seat_list(const seat * pstr, int n);
int sort_seat_list(seat * pstr, int n);
int choice_seat(seat * pstr, int n);
int delte_seat(seat * pstr, int n);
char * s_gets(char * st, int n);
//void print_flight(void);
char choice_fight(void);
int flight_switch(char ch);
void eatline(void);
int main(void)
{
seat airline[FLIGHT_COUNT][SEAT_COUNT];
int num;
initialize_airline(*airline, FLIGHT_COUNT, SEAT_COUNT);
//多维数组清空函数
while (num = flight_switch(choice_fight()))
{
if (num > 0)
while (switch_menu(choice_menu(num - 1), airline[num - 1]));
}
puts("Bye. See you next!");
return 0;
}
void eatline(void)
{
while (getchar() != '\n')//处理掉不需要的字符
continue;
}
//清空多维数组中成员属性
int initialize_airline(seat *pstr, int r, int c)
{
int i;
int j;
for (i = 0; i < r; i++)
{
for (j = 0; j < c; j++)
{
(pstr + (i * c + j))->number = j + 1;
//j + 1 值:从第一号到第48号
(pstr + (i * c + j))->selected = 0;
(pstr + (i * c + j))->name[0] = '\0';
(pstr + (i * c + j))->s_name[0] = '\0';
}
}
return ((i * j) == (r * c) ? (i * j) : 0);
//(i * j) :表示全部座位数
}
void eatline(void)
{
while (getchar() != '\n')
continue;
}
//飞机航班编号选定
char choice_fight(void)
{
puts("飞机航班编号选定:");
int ch;
while (!scanf("%c", &ch) || !isalpha(ch))
{
eatline();
puts("非法输入,请重新选择");
}
return tolower(ch);
}
//航班选择
int flight_switch(char ch)
{
puts("开始飞机航班编号选择:");
switch (ch)
{
case 'a':
//厦航102
return 1; //num - 1 == 对应数组索引
break;
case 'b':
//国航311
return 2;
break;
case 'c':
//马航444
return 3;
break;
case 'd':
//南航519
return 4;
break;
case 'e':
//退出
return 0;
break;
default:
//错误
puts("无效输入,请重新输入一个字母:");
system("pause");
return -1;
break;
}
}
//航班已经选定,对可操作进行选择
char choice_menu(int n)
{
int ch;
print_menu(n);
puts("航班已经选定,请选择相应的需求");
while (!scanf("%c", &ch) || !isalpha(ch) || strchr("abcdef", ch) == NULL)
{
eatline();
puts("输入非法,请重新输入");
}
puts("输入非法,请重新输入");
return tolower(ch);
}
void print_menu(int n)
{
static const char *menu[] = {
"请选择所要执行的操作:",
"a) 显示剩余未预定的座位数",
"b) 显示座位列表",
"c) 按首字母排序显示座位列表",
"d) 预定座位",
"e) 取消预定座位",
"f) 返回上一级菜单"
};
static const char * flight[] = {
"厦航102" , //0
"国航311" ,
"马航444" , //2
"南航519" ,
};
int i;
printf("您选择的是[%s]航班\n", flight[n]);
//此处选择了航班,在对-对应航班的座位进行操作,因此switch_menu中的功能函数中
//只需要接受一维数组地址以及12整形值
puts("-------------------------------------------------");
for (i = 0; i < sizeof(menu) / sizeof(menu[0]); i++)
{
puts(menu[i]);
}
}
int switch_menu(int choice, seat * pstr)
{
switch (choice)
{
case 'a':
//显示未预定的座位数量
empty_seat_count(pstr, SEAT_COUNT);
system("pause");
return 1;
case 'b':
//显示空的座位列表
show_seat_list(pstr, SEAT_COUNT);
system("pause");
return 1;
case 'c':
//按字母顺序显示座位列表
sort_seat_list(pstr, SEAT_COUNT);
system("pause");
return 1;
case 'd':
//为客户分配座位
choice_seat(pstr, SEAT_COUNT);
show_seat_list(pstr, SEAT_COUNT);
system("pause");
return 1;
case 'e':
//删除座位分配
delte_seat(pstr, SEAT_COUNT);
show_seat_list(pstr, SEAT_COUNT);
system("pause");
return 1;
case 'f':
//退出
return 0;
default:
//错误选择
puts("无效选择,请重新选择");
system("pause");
return 1;
}
}
int empty_seat_count(const seat *pstr, int n)
{
puts("显示未预定的座位数量");
int count = 0;
int i;
for (i = 0; i < n; i++)
{
if (pstr[i].selected == 0)
{
count++;
}
}
printf("现在空座为还剩%d个\n", count);
return count;
}
int show_seat_list(const seat *pstr, int n)
{
int i;
puts("显示空的座位列表");
puts("当前座位信息:");
for (i = 0; i < n; i++)
{
printf("座位号 :%-5d %-5d 名 :%-20s 姓:%-20s\n", pstr[i].number,
pstr[i].selected ? "已预定" : "未预定",
pstr[i].name,
pstr[i].s_name);
}
return i;
}
int sort_seat_list(seat *ps, int n)
{
puts("按字母顺序显示座位列表");
seat **ps_arr;
seat *tmp;
int min;
int i, j;
ps_arr = (seat **)calloc(n, sizeof(seat *));
//为ps_arr在堆区分配【n】个sizeof(seat *)大小的空间让其去指向
//每个sizeof(seat *)就相当于结构体大小(所有成员在内)
for (i = 0; i < n; i++)
{
ps_arr[i] = &ps[i];
//ps_arr相当于指针数组,保存有0-11个结构体指针(每个指针又都指向一个结构体)
}
for (i = 0; i < n - 1; i++)//冒泡法
{
min = i;
for (j = i + 1; j < n; j++)
{
if (strcmp(ps_arr[min]->name, ps_arr[j]->name) > 0)
{
min = j;
}
}
if (min != i)
{
//上诉的min = i是我们假定i是最小的,当i不是的时候,就把二者互换一下,使得min永远是最小
tmp = ps_arr[i];
ps_arr[i] = ps_arr[min];
ps_arr[min] = tmp;
}
}
for (i = 0; i < n; i++)
{
printf("座位号 :%-5d %-5s 名 :%-20s 姓:%-20s\n",
ps_arr[i]->number,
ps_arr[i]->selected ? "已预定" : "未预定",
ps_arr[i]->name,
ps_arr[i]->s_name);
}
free(ps_arr);
}
int choice_seat(seat *ps, int n)
{
puts("为客户分配座位");
seat t;
char ch;
int flag = 0;
puts("请输入您要挑选的座位号:");
while (!scanf(" %d", &t.number) || t.number < 1 || t.number > n
|| (flag = ps[t.number - 1].selected))
{
eatline();
if (flag) //selected==1 说明被预订
{
puts("此座位已被预定,请重新选择座位:");
flag = 0;
}
else
{
puts("非法输入,请重新输入座位号:");
}
}
eatline();
puts("锁定此座位后,请输入姓名:");
t.selected = 1; //锁定此座位
puts("请输入您的名:");
while (!s_gets(t.name, NAME_LEN));
{
puts("非法输入,请重新输入您的名:");
}
puts("请输入您的姓:");
while (!s_gets(t.s_name, NAME_LEN))
{
puts("非法输入,请重新输入您的姓:");
}
puts("================输入完毕的结构体成员属性======================");
printf("座位号: %d\n名:%s\n姓:%s\n", t.number, t.name, t.s_name);
puts("确认预约此座吗?(y/n):");
while (!scanf(" %c", &ch) || !isalpha(ch = tolower(ch)))
{
puts("非法输入,请重新输入");
}
if (ch == 'y')
{
ps[t.number - 1] = t; //在为临时结构体中成员属性赋值完毕后,将其赋给结构体数组对应元素中
return 1;
}
else
return 0;
}
int delte_seat(seat *pstr, int n)
{
int num;
int flag = 0;
//int i;
char ch;
puts("请输入您要删除的座位号:");
while (!scanf(" %d", &num) || num < 1 || num > n
|| (flag = !pstr[num - 1].selected))
{
eatline();
if (flag)
{
puts("取消预约失败,此座位并未被预约");
flag = 0;
}
else
{
puts("非法输入,请重新输入要取消预约的座位号:");
}
}
eatline();
puts("================删除结构体对应下标所属成员======================");
printf("座位号: %d\n名:%s\n姓:%s\n", pstr[num - 1].number, pstr[num - 1].name, pstr[num - 1].s_name);
puts("确认此座取消预约吗?(y/n):");
while (!scanf(" %c", &ch) || !isalpha(ch = tolower(ch)))
{
;
}
if (ch == 'y') //输入数字作为下标索引,找到对应结构体数组,将该元素下标对应的成员全部清零
{
pstr[num - 1].selected = 0;
pstr[num - 1].name[0] = '\0';
pstr[num - 1].s_name[0] = '\0';
return 1;
}
else
return 0;
}
char * s_gets(char * st, int n)
{
char * ret_value = NULL;
char * find;
if (ret_value = fgets(st, n, stdin))
{
if (find = (strchr(st, '\n')))
*find = '\0';
else
while (getchar() != '\n');
}
return ret_value;
}
.
.
14.10
稍微要注意的是 :函数指针
的形参、返回值,要和其所指向的函数对应上
# include <stdio.h>
# include <math.h>
# include <windows.h>
void print_menu(void);
int choice_meun(void);
void calculation(int cmd);
double fun_add(double x, double y);
double fun_sub(double x, double y);
double fun_mul(double x, double y);
double fun_div(double x, double y);
double get_number(void);
int main(void)
{
int n;
while ((n = choice_meun())) //在条件中直接显示我们选择的数字
{
calculation(n - 1); //而后把数字作为形参,值传递给可以实现函数指针的功能函数实现中
}
return 0;
}
int choice_meun(void)
{
int num;
int i;
print_menu();
for (i = 0; !scanf("%d", &num) || num < 1 || num > 5; i++) //中间的表达式应该是作为判断使用,也就是可循环次数
{
while (getchar() != '\n');
if((i+1) % 10 == 0)
print_menu();
puts("无效输入,请输入整数");
}
while (getchar() != '\n');
return (num == 5 ? 0 : num); //5就推出,不是就返回我们选择的数字对应的功能
}
void print_menu(void)
{
static const char* menu[] =
{
"======================================" ,
"请选择您需要的功能:" ,
"1 加 2 减" ,
"3 乘 4 除" ,
"5 退出" ,
"======================================"
};
system("cls");
int i;
printf("menu = %d", sizeof(menu) / sizeof(menu[0]));
for (i = 0; i < sizeof(menu)/sizeof(menu[0]); i++)
{
puts(menu[i]);
}
}
void calculation(int cmd) //cmd接受的(n - 1)数字
{
double n1, n2;
double(*f[4])(double x, double y) =
{ fun_add, fun_sub , fun_mul , fun_div };
puts("请输入您要计算的第一个数:");
n1 = get_number();
puts("请输入您要计算的第二个数:");
n2 = get_number();
printf("计算结果为: %.2lf\n", f[cmd](n1, n2));
system("pause");
}
double fun_add(double x, double y)
{
double sum = 0;
sum = x + y;
return sum;
}
double fun_sub(double x, double y)
{
double results = 0;
results = x - y;
return results;
}
double fun_mul(double x, double y)
{
double results = 0;
results = x * y;
return results;
}
double fun_div(double x, double y)
{
double results = 0;
if (y == 0)
{
fputs("参数错误 :除数不能是0\n", stderr);
}
else
results = x / y;
return results;
}
double get_number(void)
{
double x;
while (!scanf(" %lf", &x))
{
while (getchar() != '\n');
puts("无效输入,请输入正确的数字");
}
while (getchar() != '\n');
return x;
}
.
.
.
14.11
# include <stdio.h>
# include <windows.h>
# include <math.h>
int transform(double *source, double *traget, int n, double(*pfun)(double x));
void print_results(const double*source, int n);
int main(void)
{
double source[4] = { 1, 2, 3, 4 };
double traget[4] = { 0 };
transform(source, traget, 4, sin);
puts("source :");
print_results(source, 4);
puts("traget :");
print_results(traget, 4);
return 0;
}
int transform(double *source, double *traget, int n, double(*pfun)(double x))
{
int i = 0;
for (i; i < n; i++)
{
traget[i] = pfun(source[i]);
}
return i;
}
void print_results(const double *source, int n)
{
int i = 0;
for (i; i < n; i++)
{
printf(" %lf", source[i]);
}
putchar('\n');
}