结构体文件测试

文件读写的函数
字符读写 fgetc()/fputc()
字符串读写 fputs()/fgets()
格式化读写 fscanf()/fprintf()
二进制读写:fread()/fwrite()

其他相关函数:
检测文件结束的函数:feof()
检测文件读写时出错函数:ferror()
清楚末尾文件标志和出错标志函数:clearerr()
文件定位函数:fseek(),rewind(),ftell();

fseek函数:
用法:int fseek( FILE *stream, long offset, int origin );
函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere(偏移起始位置:文件头0(SEEK_SET),当前位置1(SEEK_CUR),文件尾2(SEEK_END))为基准,偏移offset(指针偏移量)个字节的位置。如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。

第一个参数stream为文件指针
第二个参数offset为偏移量,正数表示正向偏移,负数表示负向偏移
第三个参数origin设定从文件的哪里开始偏移,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET
SEEK_SET: 文件开头
SEEK_CUR: 当前位置
SEEK_END: 文件结尾
其中SEEK_SET,SEEK_CUR和SEEK_END依次为0,1和2.

#include<stdio.h>
#define N 5
typedef struct student{
  long sno;
  char name[10];
  float score[3];
}STU;
  
void fun(char*filename,STU n)
{
  FILE*fp;
  fp=fopen(filename,"rb+");
  fseek(fp,-1L*sizeof(STU),SEEK_END);
  fwrite(&n,sizeof(STU),1,fp);
  fclose(fp);
}
  
int main()/*修改覆盖最后一个学生数据*/
{
  STU t[N]={
    {10001,"MaChao",91,92,77},
    {10002,"CaoKai",75,60,88},
    {10003,"LiSi",85,70,78},
    {10004,"FangFang",90,82,87},
    {10005,"ZhangSan",95,80,88}
  };
   
  STU n={10006,"ZhaoSi",55,70,68},ss[N];
 
  int i,j;FILE*fp;
   
  fp=fopen("student.dat","wb");
   
  fwrite(t,sizeof(STU),N,fp);
   
  fclose(fp);
   
  fp=fopen("student.dat","rb");
   
  fread(ss,sizeof(STU),N,fp);
   
  fclose(fp);
   
  printf("\nThe original data:\n\n");
   
  for(j=0;j<N;j++)
  {
    printf("\nNo:%ldName:%-8sScores:",ss[j].sno,ss[j].name);
    for(i=0;i<3;i++)
        printf("%6.2f",ss[j].score[i]);
    printf("\n");
  }
  fun("student.dat",n);
  printf("\nThe data after modifing:\n\n");
 
  fp=fopen("student.dat","rb");
  fread(ss,sizeof(STU),N,fp);
  fclose(fp);
 
  for(j=0;j<N;j++)
  {
    printf("\nNo:%ldName:%-8sScores:",ss[j].sno,ss[j].name);
    for(i=0;i<3;i++)
        printf("%6.2f",ss[j].score[i]);
    printf("\n");
  }
  return 0;
}

rewind()函数
将文件内部的指针重新指向一个流的开头
函数作用等同于 (void)fseek(stream, 0L, SEEK_SET);
用 法: void rewind(FILE *stream);
EOF:
通常在文本的最后存在此字符表示资料结束;
和feof的返回值不是一个概念

ftell()函数
用于得到文件位置(文件的第一个字节所在位置是零)指针当前位置相对于文件首的偏移字节数
用法:long ftell(FILE *stream);

结构体的输入和输出:

结构体的定义:

结构体的初始化:

结构体内容的修改:

/*输入n(3<n<=10)个职工的编号、姓名、基本工资、职务工资,输出其中“基本工资+职务工资”最少和最多的职工姓名。

输入输出示例:

n=5

1,林宏,1800,600

2,李涛,1700,550

3,王钢,2100,750

4,周航,1500,450

5,金明,2300,850

基本工资+职务工资最少的是:周航

基本工资+职务工资最多的是:金明
*/
#include<stdio.h>

struct Worker//变量类型的定义,即定义一个结构体类型,结构体本质就是一个新的变量类型,可以用于存放多组不同变量类型的数据

{   int num;//可以包含整型

    char name[20];//字符型(一维二维均可以表示)

    float jbpay;//浮点型

    float zwpay;

};



int main()



{

        ______1_______;//定义一个结构体变量,用构造的结构体类型来定义一个变量,类似于int/float/char..., int x;

//答案为 :struct Worker s[10] 这边有个困惑是,为什么要加[10],其实是定义一个结构体数组,当有多组数据需要存储时,使用结构体数组来存储每一条变量数据。


    int max=0,min=0,i,n;

    printf("n=");

    scanf("%d",&n);

         getchar();

    for (i=0;i<n;i++)

   {

        scanf("%d%s%f%f",______2______);//结构体变量的输入,需要对每一项结构体成员分别输入,不同类型的成员用不同类型的格式符输入;

        if(s[max].jbpay+s[max].zwpay <s[i].jbpay+s[i].zwpay )    ______3_______;                                        

        if(s[min].jbpay+s[min].zwpay >s[i].jbpay+s[i].zwpay )______4_______; 

               getchar();                                                      

    }

    printf("基本工资+职务工资最少的是%s\n",s[min].name);//结构体成员的引用使用 结构体变量名.结构体成员,"."号表示引用,

    printf("基本工资+职务工资最多的是%s\n",s[max].name);

    return 0;

}

结构体成员运算符
->指针运算符。
1、如果结构体中的成员均为一般变量(包括结构体变量),则使用容“.”,如果成员变量为指针(不管指向什么,包括结构体),则使用“->”。
2、如果定义了结构体数组指针,则可分别使用“.”和“->”,区别在于指针带下标时,以是数组形式访问,此时用“.”,如果不带下标(或使用偏移),此时用“->”。

(->)是一个表示成员的运算符,它与前面讲过的·运算符的区别是:
(->)用来表示指向对象的指针的成员,表示数据成员。
(·)用来表示一般对象的成员,表示成员函数。

下面的两种表示是等价的:

<对象指针名>-><成员名>

(*<对象指针名>).<成员名>

这对于成员函数也适用。
另一说:
成员运算符(·)和指向结构体成员运算符(->)的区别

两者都是用来引用结构体变量的成员,但它们的应用环境是完全不一样,前者是用在一般结构体变量中,而后者是与指向结构体变量的指针连用,例如:有定义

struct student

{
long num;

float score;

};

struct student stud, *ptr=&stud;

则stud.num、stud.score、ptr->num等都是正确的引用方式,但ptr.num、stud->num就是不允许的,其实ptr->num相当于(*ptr).num,只是为了更为直观而专门提供了这->运算符。

最后指出,这两者都具有最高优先级,按自左向右的方向结合

/*
修改结构体中的数据
程序通过定义学生结构体变量,存储了学生的学号、姓名和3门课的成绩。

函数fun的功能是将形参a所指结构体变量s中的数据进行修改,并把a中地址作为函数值返回主函数,在主函数中输出修改后的数据。

例如:a所指变量s中的学号、姓名、和三门课的成绩依次是:

10001、" ZhangSan "、95、80、88,

修改后输出t中的数据应为:10002、"LiSi "、96、81、89。

注意:按照顺序填代码,不要带编号1,2,3,4。空格或回车隔开。*/

#include  <stdio.h>

#include  <string.h>

struct student {

  long  sno;

  char  name[10];

  float  score[3];

};



 ______2__________ Modif(struct student  *p)//定义一个结构体指针,返回类型为结构体指针类型,故答案为struct student *

{

   int  i;



   p->sno = 10002;//若成员为整型数据,则可以使用直接赋值的方法,指针指向结构体成员然后赋值,使用箭头运算符

   strcpy(p->name, "LiSi");//若成员为字符串型数据,则必须使用相关函数(strcpy()),不能够直接赋值!!!

   for (i=0; i<3; i++)//对于成员为数组的变量,则修改时必须使用循环,每一条数据修改方式同上两条
      ______3_______++;//p->score[i]


   return _____4________;//返回值为p指针,用于使用箭头指针运算符,修改的只有成员的数据,并未修改指针p的位置,所以返回时无需返回第一个成员变量的地址。

}



void main()

{

  struct student  s={10001,"ZhangSan", 95, 80, 88},  *t;//主函数中,结构体变量的初始化必须紧跟在结构体变量的定义之后,否则视为违法操作

  int  i;

  printf("\n\nThe original data :\n");

  printf("\nNo: %ld  Name: %s\nScores:  ",s.sno, s.name);

  for (i=0; i<3; i++)

     printf("%6.2f ", ___1____);//输出修改前的数据

  printf("\n");

  t = Modif(&s);//将函数的返回值赋给一个结构体指针

  printf("\nThe data after modified :\n");

  printf("\nNo: %ld  Name: %s\nScores:  ",t->sno, t->name);

  for (i=0; i<3; i++)//对于数据,使用循环输出

    printf("%6.2f ", t->score[i]);//输出修改后的数据



  return 0;

}


/*
1.下述数据,结构体如何定义? 

2.现有100部电影数据,如何存储。 

3.定义结构体指针怎么定义? 

4.修改第三条数据为 {F001,前任4,60,10:30},怎么改?   

5de3e2937fa3d.png?OSSAccessKeyId=LTAItfPkNIKJFibY&Expires=4728815763&Signature=Xr2bX%2F1MQ%2FiSKjefgQCdNcxcIj8%3D


*/


/*正确答案:

第一空:*/

typedef struct {//使用typedef 来给定义的结构体类型起一个名字,以便于接下来对于结构体变量的定义,倘若不使用typedef,定义结构体变量就得使用
// struct MyStruct+变量名

char filmNum[10];//定义电影编号,包含英文字母,故使用字符数组

char filmName[100];//名字类使用字符数组

int filePrice;//电影价

char fileTime[20];//对于时间的存储????

}FILM;

  FILM films[100];

  FILM *p = films;//定义结构体指针来移动到需要修改的位置

 p=p+2;

strcpy(p->filmNum,"F001");//注意字符的修改需要使用字符的相关函数(strcpy)

strcpy(p->filmName,"前任4");

p->filmPrice=60; 

strcpy(p->filmTime,"10:30")

/*我的答案:

第一空: 
1.*/

typedef struct

{

char num[50];

char name[30];

double price;

char datetime[70][70];

}MOVIEDATA;

MOVIEDATA data;

data = (MOVIEDATA)malloc(sizeof(MOVIEDATA)10000);

strcpy=(data[3].num,"F001");

strcpy=(data[3].name,"前任4");

data[3].price=60;

int i=0;

strcpy=(data[3].datetime[i],'10');

i++;

strcpy=(data[3].datetime[i],'30');


/*
以下程序中用户由键盘输入一个文件名,然后输入一串字符(用#结束输入)存放到此文件文件中形成文本文件,并将字符的个数写到文件尾部。文件名要加上后缀txt,如“hello.txt”

思路是,先将输入的文件名写入文件中(救赎创建一个文件),再写入文本到这个文件

*/

include <stdio.h>

include <stdlib.h>

int main(void){

FILE *fp;

char ch,fname[32];

int count=0;

printf("Input the filename :");

scanf("%s",fname);//文件可以来自键盘输入的字符串??打开的文件可以来自于键盘输入的字符串???

if (1_==NULL) {//(fp=fopen(fname,"w+"))使用写入文件的写法 将文件指针指向打开后的文件,文件使用文件打开函数打开,

printf("Can't open file:%s \n",fname);



exit(0);

}

printf("Enter data:\n");

while ((ch=getchar())!='#') {//循环条件是没有到结束标志

  _________2______________;//将字符写入到文件当中去,fputc(ch,fp)



   count++;//计算文件的长度



}

fprintf(3_________);// fp,"\n%d\n",count,将字符的个数写到文件尾部,注意,在文件中的输出和写入,使用的函数和在屏幕上的不同。

fclose(fp);

}

正确答案:

第一空:
(fp=fopen(fname,"w+"))

第二空:
fputc(ch,fp)

第三空:
fp,"\n%d\n",count

我的答案:

第一空:
fp=fopen("fname.txt","w")

第二空:
fputs(ch,fp)

第三空:
("%d",count)

posted @ 2021-01-17 22:48  calizo  阅读(166)  评论(0编辑  收藏  举报