功能描述
本程序旨在利用动态内存分配与文件存储的相关知识,先定义一个结构体,用于接收字段信息,包括字段名,字段类型,字段长度,字段ID。其中ID值系统自动按照顺序分配,其余属性需要用户自定义。用户需要设置字段数m和记录条数n。
比如下面这个表格:
姓名 | 性别 | 学号 | C语言成绩 | |
---|---|---|---|---|
张三 | ||||
李四 | ||||
王五 |
对于这个表格来说m=4,n=3。
其中姓名,性别,学号,C语言成绩都属于字段,以姓名字段为例,字段名称为“姓名”,字段类型为“s”,代表这个字段用于存储字符串,并且输入字符串长度(还有一种字段类型为“n”,用于存储数字,比如C语言成绩,若类型为n,则程序自动分配4个字节的内存)
当所有字段属性定义完毕后,打印已建立记录的字段属性信息,并进入录入信息阶段。录入信息完毕则全部打印出来,并提醒用户输入要创建的文件名,再利用fwrite()函数将整个结构体录入文件。若用户选择查询已存在的文件,则使用fread()函数读出文件的信息并打印。
具体实现细节可以参考代码中的注释:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
typedef struct FIELDATRR//定义一个结构体,用于接收字段信息,包括字段名,字段类型,字段长度,字段ID
{
int fieldId;
char fieldCaption[11];
char fieldType;
int fieldLen;
}F;
struct INFORMATION
{
int jilu;
int ziduan;
int length;
}I;
int main()
{
int m,n,i,j,sum=0;
char ch,filename[20],findfilename[20];
FILE *fp,*fs;
F filde[30];
printf("请按方括号中的字母选择功能:\n");
printf("[C]reat a table,[L]ist a table exist,[Q]uit:");
ch=getchar();
if(ch=='c'||ch=='C')
{
printf("请输入记录的字段数:");
scanf("%d",&m);
I.ziduan=m;
printf("请输入记录条数:");
scanf("%d",&n);
system("cls");
for(i=0;i<m;i++)
{
filde[i].fieldId=i;//系统自动录入ID值
printf("请输入字段名称:");
scanf("%s",filde[i].fieldCaption);
printf("请输入选择字段类型(int n,string s):");
scanf(" %c",&filde[i].fieldType);
if(filde[i].fieldType=='s')
{
printf("输入字符串长度:");
scanf("%d",&filde[i].fieldLen);
filde[i].fieldLen++;
printf("一个字符属性输入完毕,按任意键继续。。。\n");
getch();
}
else if(filde[i].fieldType=='n')
{
filde[i].fieldLen=4;
printf("一个字符属性输入完毕,按任意键继续。。。\n");
getch();
}
}
printf("字段属性信息已录入完毕,按任意键查看。。。");
getch();
system("cls");
printf("已建立记录的字段属性信息:\n");
for(i=0;i<m;i++)
{
printf("字段ID:%-3d,%-11s,%-3d,%c\n",i+1,filde[i].fieldCaption,filde[i].fieldLen,filde[i].fieldType);
sum=sum+filde[i].fieldLen;
}
printf("%d\n",sum);
I.length=sum;
printf("按任意键,可以录入信息\n");
getch();
system("cls");
/*录入各字段的信息*/
char *p=(char *)calloc(sum*n,sizeof(char));//申请一片连续内存,sum相当于存储一个同学数据所需要的最大字节数,n是同学人数,可理解为一个二维数组
int flag=0;
int num,numbur=0;
for(j=0;j<n;j++)
{
num=0;
for(i=0;i<m;i++)
{
printf("%s=",filde[i].fieldCaption);
if(filde[i].fieldType=='s')
scanf("%s",p+j*sum+num);
else
scanf("%d",(int *)(p+j*sum+num));//此处需要用(int*)进行强转
num=num+filde[i].fieldLen;//num用于累加每录入一个同学数据时,一种一种字段类型所占字节数向下累加,并在每次循环开始前初始化为零
}
numbur++;
I.jilu=numbur;
printf("一条记录录入完毕!按任意键继续录入,按ESC键返回\n");
if(getch()==27)
{
flag=1;
system("cls");
break;
}
else
continue;
}
if(flag==0)
{
printf("已经录入完了最后一条记录,按任意键可浏览输入的数据");
getch();
}
system("cls");
printf("已经录入的信息:\n");
for(j=0;j<numbur;j++)//此处边际值用numbur控制而没有用n的目的是,保证中途esc退出后不会打印出剩余未录入内容但已分配内存的学生信息段
{
num=0;
for(i=0;i<m;i++)
{
if(filde[i].fieldType=='s')
printf("%s:%s\t",filde[i].fieldCaption,p+j*sum+num);//利用%s输出字符串时,给地址值即可,不需要解引用
else
printf("%s:%d\t",filde[i].fieldCaption,*(int *)(p+j*sum+num));//输出时也需要用(int*)进行强转,并且解引用
num=num+filde[i].fieldLen;
}
printf("\n");
}
printf("请输入要创建的文件名:");
scanf("%s",filename);
fp=fopen(filename,"w");
fwrite(&I,sizeof(I),1,fp);
fwrite(filde,sizeof(F),m,fp);
fwrite(p,sum*n,1,fp);
fclose(fp);
printf("文件已创建,按任意键退出。。。");
getch();
exit(0);
}
else if(ch=='l'||ch=='L')
{
int k,num;
printf("请输入要浏览的文件名:");
scanf("%s",findfilename);
fs=fopen(findfilename,"r");
if(fs==NULL)
{
printf("文件不存在,按任意键退出程序。。。");
getch();
exit(0);
}
fread(&I,sizeof(I),1,fs);
printf("以下是从文件中读出的信息:\n");
printf("记录数为:%d,字段数量:%d,每条记录的长度为:%d\n\n",I.jilu,I.ziduan,I.length);
fread(filde,sizeof(F),I.ziduan,fs);
printf("表文件中字段的数据信息:\n\n");
for(k=0;k<I.ziduan;k++)
{
printf("字段ID:%-3d,%-11s,%-3d,%c\n",k+1,filde[k].fieldCaption,filde[k].fieldLen,filde[k].fieldType);
sum=sum+filde[k].fieldLen;
}
printf("\n");
printf("表文件中的记录信息:\n\n");
char *pr=(char *)calloc(sum*I.jilu,sizeof(char));
fread(pr,sum*I.jilu,1,fs);
for(j=0;j<I.jilu;j++)
{
num=0;
for(i=0;i<I.ziduan;i++)
{
if(filde[i].fieldType=='s')
printf("%s:%s\t",filde[i].fieldCaption,pr+j*sum+num);
else
printf("%s:%d\t",filde[i].fieldCaption,*(int *)(pr+j*sum+num));
num=num+filde[i].fieldLen;
}
printf("\n");
}
printf("\n");
free(pr);
fclose(fs);
printf("程序执行完毕,按任意键退出程序。。。\n");
getch();
exit(0);
}
else
{
exit(0);
}
}