c语言基础六

C语言基础六

结构体

结构体:不同类型的数据组合成一个有机的整体,结构体是一种构造数据类型。

描述一组具有相同类型数据的有序集合,用于处理大量相同类型的数据运算–数组,数组也是构造函数。

结构体类型的概念:结构体是一种构造类型的数据结构,是一种或多种基本类型或构造类型的数据的集合

结构体类型定义

先定义结构体类型,再去定义结构体变量

struct 结构体类型名{
成员列表
};

struct stu{
int num;
char name[20];
char sex;
};
//有了结构体类型后,就可以用类型定义变量了
struct stu caicai,shu//定义了两个struct stu 类型的变量每个结构体都有三个成员,分别是num name sex

在定义结构体类型的时候顺便定义结构体变量,以后还可以定义结构体变量

struct 结构体类型名{
成员列表;
}结构体变量1,变量2;
struct 结构体类型名变量3,变量4;

struct stu{
int num;
char name[20];
char sex;
}caicai,shu; //定义了caicai,shu
struct stu zhou,zhao;//又定义了zhou,zhao

在定义结构体类型的时候,没有结构体类型名,顺便定义结构体变量,因为没有类型名,所以以后不能再定义相关类型的数据了

struct {
成员列表;
}变量1,变量2;

struct stu{
int num;
char name[20];
char sex;
}caicai,shu;//以后没法再定义这个结构体类型的数据了,因为没有类型名,只有caicai,shu

最常用的方法

利用typedef将一个结构体类型重新起个类型名,用新的类型名替代原先的类型

struct stu{
int num;
char name[20];
char sex;
};
struct stu zhou,zhao;
//利用typedef重新起个名,
typedef struct stu{
int num;
char name[20];
char sex;
}STU;
STU zhou,zhao;

结构体变量的定义初始化及使用

结构体变量,是个变量,这个变量是若干个相同或不同数据构成的集合

在定义结构体变量之前首先得有结构体类型,然后再定义变量

在定义结构体变量的时候,可以顺便给结构体变量赋初值,被称为结构体的初始化

结构体变量初始化的时候,各个成员顺序初始化

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
typedef struct stu {
	int num;
	char name[20];
	char sex;
}STU;
int main()
{
	STU caicai = {
	102,
	"caicai",         //成员按顺序初始化,后面的成员可以不初始化
	};
	STU shu = {
		100,
		"shu",
		'm'
	};


	return 0;
}

结构体变量成员的引用方法:结构体变量.成员名

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
typedef struct stu {
	int num;
	char name[20];
	char sex;
}STU;
int main()
{
	
	STU shu;
	shu.num = 100;
	strcpy(shu.name, "shu");
	//shu.name = "shu";shu.name是地址是个常量
	shu.sex = 'm';
	printf("name:%s",shu.name);

	return 0;
}

结构体成员多级引用

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
struct date {
	int year;
	int month;
	int day;
};
typedef struct stu {
	int num;
	char name[20];
	char sex;
	struct date bri;
}STU;
int main()
{
	STU shu;
	shu.num = 100;
	strcpy(shu.name, "shu");
	shu.sex = 'm';
	shu.bri.year = 2000;
	printf("name:%s\n",shu.name);
	printf("name:%d\n", shu.bri.year);
	return 0;
}

相同类型的结构体变量可以相互赋值

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
struct date {
	int year;
	int month;
	int day;
};
typedef struct stu {
	int num;
	char name[20];
	char sex;
	struct date bri;
}STU;
int main()
{
	STU shu;
	shu.num = 100;
	strcpy(shu.name, "shu");
	shu.sex = 'm';
	shu.bri.year = 2000;
	printf("name:%s\n",shu.name);
	printf("name:%d\n", shu.bri.year);
	STU caicai;
	caicai = shu;
	printf("name:%s\n", caicai.name);
	printf("name:%d\n", caicai.bri.year);
	return 0;
}

结构体数组

typedef struct stu {
	int num;
	char name[20];
	char sex;
	struct date bri;
}STU;
STU erban[50];定义了一个STU(struct stu)类型的结构体数组,有50个元素
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
struct date {
	int year;
	int month;
	int day;
};
typedef struct stu {
	int num;
	char name[20];
	char sex;
	float score;
	struct date bri;
}STU;
int main()
{
	STU erban[50];
	strcpy(erban[0].name, "shu");
	erban[0].num = 1;
	erban[0].score = 100;
	strcpy(erban[1].name, "caicai");
	erban[1].num = 2;
	erban[1].score = 99;
	printf("第%d名的名字是%s分数是%.2f\n", erban[0].num, erban[0].name, erban[0].score);
	printf("第%d名的名字是%s分数是%.2f\n", erban[1].num, erban[1].name, erban[1].score);
	printf("平均成绩是%.2f\n",  (erban[1].score+ erban[0].score)/2);
	return 0;
}

结构体指针

结构体变量存放内存中,也有起始地址,定义一个变量来存放这个地址,那这个变量就是结构体指针变量。也是4个字节

结构体指针变量的定义方法:

struct 结构体类型名* 结构体指针变量名;
struct stu{
int num;
char name[20];
};
struct stu * p;//定义了一个struct stu *类型的指针变量
#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
typedef struct stu {
	int num;
	char name[20];
	char sex;
	float score;
}STU;
int main()
{
	STU shu = {100,"caicai",'m',};
	STU* caicai;//caicai与数必须同一个结构体类型
	caicai = &shu;   //caicai保存shu的地址,
	printf("name:%s\n",shu.name);
	printf("name:%s\n", (*caicai).name);//*caicai相当于shu
	printf("name:%s\n", caicai->name);//caicai指向name,相当于shu.name
	return 0;
}

给函数结构体变量的地址

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
typedef struct stu {
	int num;
	char name[20];
	char sex;
	float score;
}STU;
void fun(STU *p)  //定义变量类型STU*
{
	p->num = 2;              //赋值
	strcpy(p->name, "lucy"); //赋值,p->name是一个地址常量不能被赋值
	p->score = 99;            //赋值
}

int main()
{
	STU shu ;  //定义结构体类型,变量
	fun(&shu);   //给fun函数传shu的地址
	printf("name:%s\n",shu.name);
	printf("num:%d\n", shu.num);
	printf("score:%.2f\n", shu.score);
	return 0;
}

传结构体数组的地址

结构体数组,是由若干个相同类型的结构体变量构成的集合。存放在内存里,也有起始地址,其实就是第0 个结构体变量的地址。

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
typedef struct stu {
	int num;
	char name[20];
	float score;
}STU;
void fun(STU *p,int j)  //定义p接受传入的首地址类型为STU*
{
	int i;
	for ( i = 0; i < j; i++)
	{
		printf("num:%d name:%s score:%.2f\n", p[i].num, p[i].name, p[i].score);
	}
}

int main()
{
	STU erban[3] = {
		{1,"shu",99},
		{2,"caicai",98},
		{3,"kunkun",90}
	};  //定义一个结构体数组
	fun(erban,3); //给fun函数传入结构体数组首地址
	return 0;
}

结构体变量的地址编号和结构体第一个成员的地址编号相同,但指针的类型不同。

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
typedef struct stu {
	int num;
	char name[20];
	float score;
}STU;


int main()
{
	STU shu;
	printf("%p\n",&shu);//shu的类型为STU,指针类型为STU*
	printf("%p\n", &shu.num);//shu.num类型为int,指针类型为int*
	return 0;
}	

结构体数组的地址就是结构体数组中第0 个元素的地址

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
typedef struct stu {
	int num;
	char name[20];
	float score;
}STU;
int main()
{
	STU erban[3] = {
		{1,"shu",99},
		{2,"caicai",98},
		{3,"kunkun",90}
	};  //定义一个结构体数组
	printf("%p\n",erban);//erban是一个数组的地址
	printf("%p\n", &erban[0]);//数组第0个元素,erban[0]类型是STU,指针的类型是STU*
	printf("%p\n", &erban[0].num);//数组第0个元素首个成员,erban[0].num类型是int,指针的类型是int*
	return 0;
}

结构体的内存

结构体变量大小是,它所有成员的大小之和

在实际给结构体变量分配内存的时候,是有规则的

规则1:以多少个字节为单位开辟内存

给结构体变量分配内存的时候,会去结构体变量中找基本类型的成员
哪个基本类型的成员占字节数多,就以它的大小为单位开辟内存,

说明:

成员中只有char 型数据,以1 字节为单位开辟内存。

成员中出现了short int 类型数据,没有更大字节数的基本类型数据。以2 字节为单位开辟内存

出现了int float 没有更大字节的基本类型数据的时候以4 字节为单位开辟内存。

出现了double 类型的数据,无论是那种环境,double 型变量,占8 字节。但是在vc6.0 和Visual Studio 中里,以8 字节为单位开辟内存。在Linux 环境gcc 里,以4 字节为单位开辟内存。

如果在结构体中出现了数组,数组可以看成多个变量的集合。
如果出现指针的话,没有占字节数更大的类型的,以4 字节为单位开辟内存。
在内存中存储结构体成员的时候,按定义的结构体成员的顺序存储。

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
typedef struct stu {
	int num;
	char name;
	float score;
}STU;
int main()
{
	STU shu;
	printf("%p\n",&shu.num);
	printf("%p\n", &shu.name);
	printf("%p\n", &shu.score);//char类型占一个字节但是name与score却相差4个字节
	return 0;
}

规则2:字节对齐

char 1 字节对齐,即存放char 型的变量,内存单元的编号是1 的倍数即可。
short int 2 字节对齐,即存放short int 型的变量,起始内存单元的编号是2 的倍数即可。

int 4 字节对齐,即存放int 型的变量,起始内存单元的编号是4 的倍数即可
long int 在32 位平台下,4 字节对齐,即存放long int 型的变量,起始内存单元的编号是4
的倍数即可
float 4 字节对齐,即存放float 型的变量,起始内存单元的编号是4 的倍数即可
double
vc6.0 和Visual Studio 环境下8 字节对齐,即存放double 型变量的起始地址,必须是8 的倍数,double 变量占8 字节
gcc 环境下,4 字节对齐,即存放double 型变量的起始地址,必须是4 的倍数,double 变量占8 字节。

当结构体成员中出现数组的时候,可以看成多个变量。

开辟内存的时候,从上向下依次按成员在结构体中的位置顺序开辟空间

字节对齐的目的:用空间来换时间,提高cpu 读取数据的效率

使用#pragma pack改变默认对齐原则,#pragma pack (value)时的指定对齐值value。value只能是:1 2 4 8等,指定对齐值与数据类型对齐值相比取较小值

以多少个字节为单位开辟内存,结构体成员中,占字节数最大的类型长度和value比较,取较小值,为单位开辟内存,结构体成员中成员的对齐方法,各个默认的对齐字节数和value相比,取较小值

如:如果指定对齐值:
设为1:则short、int、float等均为1
设为2:则char 仍为1,short 为2,int 变为2

#pragma pack(2)
struct stu{
char a;
int b;
} ;//默认占8个字节,value设定为2,则占6个字节,设定为1,则占5个字节

位段

定义:在结构体中,以位为单位的成员,称之为位段(位域)。

struct stu{
unsigned int a:2; //定义a占2位
unsigned int b:6;//定义b占6位
unsigned int c:4;//定义c占4位
unsigned int d:4;//定义d占4位
unsigned int i;
} data;     //总sizeof占8字节,2+6+4+4=16位,两字节+(两字节)+四字节=8字节

不能对位段成员取地址,位段成员可能不够1字节

对于位段成员的引用如下:

unsigned int a:2; //定义a占2位

data.a =2//a的取值范围是00–11,转十进制是0–3
赋值时,不要超出位段定义的范围;如段成员a定义为2位,最大值为3,即(11)2,所以data.a =5,就会取5(101)的低两位进行赋值01

位段成员的类型必须指定为整型或字符型

一个位段必须存放在一个存储单元中,不能跨两个单元,第一个单元空间不能容纳下一个位段,则该空间不用,而从下一个单元起存放该位段

char 型位段存储单元是1 个字节
short int 型的位段存储单元是2 个字节
int 的位段,存储单元是4 字节
long int 的位段,存储单元是4 字节

struct stu{
char a:7;//第一个字节占7位,剩余1位
char b:7;//不能跨储存单元即1个字节,所以从第二个字节开始储存,占7位,剩余1位
char c:2;//不能跨储存单元,所以从第三个字节开始储存,占2位,剩余6位
}temp;//占3 字节,

位段的长度不能大于存储单元的长度

char 型位段不能大于8 位,一个字节
short int 型位段不能大于16 位,两个字节
int 的位段,位段不能大于32 位,4个字节
long int 的位段,位段不能大于32 位,4个字节

char a:9;//编译出错,位段a 不能大于其存储单元的大小
unsigned char a:1;
unsigned char b:2;
unsigned char :0;//作用是使下一个位段从,下一个存储单元开始存放
unsigned char c:3;(另一个单元)
unsigned a: 1;
unsigned : 2;//可以定义无意义位段
unsigned b: 3;

共用体

共用体和结构体类似,也是一种构造类型的数据结构。先定义出类型,然后用类型定义变量

union 共用体类型名{
成员列表
};

几个不同的变量共同占用一段内存的结构,在C语言中,被称作“共用体”类型结构,共用体所有成员占有同一段地址空间,共用体的大小是其占内存长度最大的成员的大小

同一内存段可以用来存放几种不同类型的成员,但每一瞬时只有一种起作用

共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员的值会被
覆盖

共用体变量的地址和它的各成员的地址都是同一地址

初始化共用体只能为第一个成员赋值,不能给所有成员都赋初值

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
typedef union temp {
	unsigned char a;
	unsigned short int b;
	unsigned int c;
}TEMP;
int main()
{
	TEMP t;
	printf("%p\n",&t.a);
	printf("%p\n", &t.b);
	printf("%p\n", &t.c);  //地址一样
	t.c = 0xffffffff;      //相当于全部赋值
	printf("%x\n", t.a);
	printf("%x\n", t.b);
	printf("%x\n", t.c);
	t.a = 0x11;            //所有成员都会改变
	printf("%x\n", t.a);
	printf("%x\n", t.b);
	printf("%x\n", t.c);
	return 0;
}

枚举

将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。

枚举类型也是个构造类型的,类型定义类似结构体类型的定义。使用枚举的时候,得先定义枚举类型,再定义枚举变量

enum 枚举类型名{
枚举值列表(枚举元素);
};

枚举元素是常量,默认是从0 开始编号的。枚举变量仅能取枚举值所列元素

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
enum week 
{
	mon,tue,wed,thu,fri,sat,sun   //0,1,2,3,4,5,6,7
};
int main()
{
	enum week day;
	day = wed;
	printf("%d\n",day);   //2
	//mon=2 mon是常量不能被赋值
	return 0;
}

枚举值是常量,不能在程序中用赋值语句再对它赋值

枚举元素本身由系统定义了一个表示序号的数值,默认是从0开始顺序定义为0,1,2…

可以改变枚举值的默认值

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
enum week 
{
	mon=2,tue,wed,thu,fri=1,sat,sun //2,3,4,5,1,2,3改变枚举值的默认值
};
int main()
{
	enum week day;
	day = wed;
	printf("%d\n",day);   //4
	return 0;
}

文件指针

关于文件:文件在硬盘上存储的时候,物理上都是用二进制来存储的。标准io 库函数,对文件操作的时候,不管文件的编码格式(字符编码、或二进制),而是按字节对文件进行读写,所以文件又叫流式文件,即把文件看成一个字节流。

文件指针:在程序中用来标识(代表)一个文件的,在打开文件的时候得到文件指针,文件指针就用来代表打开的文件。它是个FILE 类型结构体指针,用文件指针来标识一个文件。

形式:

FILE * 指针变量标识符;
FILE 为大写,需要包含<stdio.h>
FILE 是系统使用typedef 定义出来的有关文件信息的一种结构体类型,结构中含有文件名、文件
状态和文件当前位置等信息

实际编程中使用库函数操作文件,无需关心FILE 结构体的细节,只需要将文件指针传给io 库函数,
库函数再通过FILE 结构体里的信息对文件进行操作

typedef struct   FILE 在stdio.h 文件中的文件类型声明
{ short level; //缓冲区“满”或“空”的程度
unsigned flags; //文件状态标志
char fd; //文件描述符
unsigned charhold; //如无缓冲区不读取字符
short bsize; //缓冲区的大小
unsigned char *buffer; //数据缓冲区的位置
unsigned ar*curp; //指针,当前的指向
unsigned istemp; //临时文件,指示器
shorttoken; //用于有效性检查
}FILE;

对文件操作的步骤:
1、对文件进行读写等操作之前要打开文件得到文件指针
2、可以通过文件指针对文件进行读写等操作
3、读写等操作完毕后,要关闭文件,关闭文件后,就不能再通过此文件指针操作文件了

stdin: 标准输入默认为当前终端(键盘)
我们使用的scanf、getchar 函数默认从此终端获得数据
stdout:标准输出默认为当前终端(屏幕)
我们使用的printf、puts 函数默认输出信息到此终端
stderr:标准错误输出设备文件默认为当前终端(屏幕)
当我们程序出错使用:perror 函数时信息打印在此终端

打开文件fopen

FILE *fopen(const char *path, const char *mode);

fopen 函数的功能是打开一个已经存在的文件,并返回这个文件的文件指针(文件的标识)
或者创建一个文件,并打开此文件,然后返回文件的标识。

打开的文件的路径:绝对路径D:\\demo\\test\\aaa.txt,从根目录开始的路径名称,相对路径.\\test\\aaa.txt

文件打开的方式,即以什么样的方式(只读、只写、可读可写等等)打开文件

r 或rb 以只读方式打开一个文本文件(不创建文件)

w 或wb 以写方式打开文件(使文件长度截断为0 字节,创建一个文件)

a 或ab 以追加方式打开文件,即在末尾添加内容,当文件不存在时,创建文件用于写

r+或rb+ 以可读、可写的方式打开文件(不创建新文件)

w+或wb+ 以可读、可写的方式打开文件(使文件长度为0 字节,创建一个文件)

a+或ab+ 以追加方式打开文件,打开文件并在末尾更改文件(如果文件不存在,则创建文件)

返回值:
成功:打开的文件对应的文件指针
失败:返回NULL
调用fopen 函数的时候,一定要判断一下,打开是否成功。

关闭文件fclose

int fclose(FILE *fp);

关闭fp 所代表的文件,一个文件只能关闭一次

返回值:成功返回0,失败返回非0,可以通过返回值,来判断关闭文件是否成功。

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
int main()
{
	FILE* fp;  //文件指针
	int ret;   //接受fclose的返回值
	fp = fopen(".\\test.txt","r+");   //打开的文件路径.//与.c在同一路径,打开方式,
	if (fp == NULL)     // 判断文件是否打开
	{
		perror("fopen");    //perror可以打印出错信息, No such file or directory
		return 0;
	}
	printf("打开文件成功\n");
	ret = fclose(fp);    //接受fclose的返回值,判断文件是否打开成功
	if (ret == 0)
		printf("关闭文件成功\n");
	else
		printf("关闭文件失败");
	return 0;
}

读写字符

一次读写一个字符

int fgetc(FILE *stream);

fgetc 从stream 所标识的文件中读取一个字节,将字节值返回

以t (文本)的方式: 读到文件结尾返回EOF
以b (二进制)的方式:读到文件结尾,使用feof(文件指针)判断结尾
feof 是C 语言标准库函数,其原型在stdio.h 中,其功能是检测流上的文件结束符,如果文件结束,
则返回非0 值,否则返回0(即,文件结束:返回非0 值;文件未结束:返回0 值)。

int fputc(int c, FILE *stream)

fputc 将c 的值写到stream 所代表的文件中。

如果输出成功,则返回输出的字节值;
如果输出失败,则返回一个EOF。

EOF 是在stdio.h 文件中定义的符号常量,值为-1

打开文件的时候,默认读写位置在文件的开始,如果以a 的方式打开读写位置在文件的末尾
向文件中读取字节或写入字节的时候,读写位置会往文件的末尾方向偏移,读写多少个字节,读写位置就往文件的末尾方向偏移多少个字节

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
int main()
{
	FILE* fp;  //文件指针
	FILE* fp2;
	int ret;   //接受fclose的返回值
	char ch;
	fp = fopen(".\\test.txt","r+");   //打开的文件路径,打开方式
	if (fp == NULL)     // 判断文件是否打开
	{
		perror("fopen");    //perror可以打印出错信息, No such file or directory
		return 0;
	}
	printf("打开test文件成功\n");
	fp2 = fopen(".\\test2.txt", "r+");   //打开的文件路径,打开方式
	if (fp == NULL)     // 判断文件是否打开
	{
		perror("fopen");    //perror可以打印出错信息, No such file or directory
		return 0;
	}
	printf("打开test2文件成功\n");

	while ((ch = fgetc(fp)) != EOF)
	{
		fputc(ch, stdout);//读取字符到屏幕上标准输出
		fputc(ch, fp2);读取字符输出到fp2
	}
	printf("\n");
	ret = fclose(fp);    //接受fclose的返回值,判断文件是否打开成功
	if (ret == 0)
		printf("关闭文件成功\n");
	else
		printf("关闭文件失败");
	fclose(fp2);
	return 0;
}

一次读写一个字符串

char *fgets(char *s, int size, FILE *stream);

从stream 所代表的文件中读取字符,在读取的时候碰到换行符或者是碰到文件的末尾停止读取,或者是读取了size-1 个字节停止读取,在读取的内容后面会加一个\0,作为字符串的结尾

返回值:成功返回目的数组的首地址,即s失败返回NULL

int fputs(const char *s, FILE *stream);

将s 指向的字符串,写到stream 所代表的文件中

返回值:成功返回写入的字节数,失败返回-1

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
int main()
{
	FILE* fp;  //文件指针
	FILE* fp2;
	char ch[100];
	fp = fopen(".\\test.txt","r+");   //打开的文件路径,打开方式
	fp2 = fopen(".\\test2.txt", "r+");   //打开的文件路径,打开方式
	fgets(ch,30,fp);//碰到换行符,文件结尾,size-1(30-1)就会停止读取
	printf("*%s*\n", ch);
	fputs(ch,stdout);  //输出到屏幕
	printf("\n");
	fputs(ch, fp2);//输出到fp2文件
	fclose(fp);    
	fclose(fp2);
	return 0;
}

读写文件

读文件fread

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

fread 函数从stream 所标识的文件中读取数据,每块是size 个字节,共nmemb 块,存放到ptr 指向的
内存里

返回值:实际读到的块数。

unsigned int num;
num=fread(str,100,3,fp);
从fp 所代表的文件中读取内容存放到str 指向的内存中,读取的字节数为,每块100 个字节,3 块。
返回值num,
如果读到300 个字节返回值num 为3
如果读到了大于等于200 个字节小于300 个字节返回值为2
读到的字节数,大于等于100 个字节小于200 个字节返回1
不到100 个字节返回0

写文件fwrite

size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);

fwrite 函数将ptr 指向的内存里的数据,向stream 所标识的文件中写入数据,每块是size 个字节,共
nmemb 块。

返回值:实际写入的块数

fwrite 函数是将内存中的数据原样输出到文件中。
fread 函数是将文件中的数据原样读取到内存里。

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
struct stu
{
	char name[10];
	int num;
	int age;
}boya[2], boyb[2]; //定义两个结构体数组boya,boyb,分别有两个元素
int main()
{
	FILE* fp;    //文件指针
	int i;
	if ((fp = fopen("test.txt", "wb+")) == NULL)
	{
		printf("Cannot open file!");
		return 0;
	}//判断文件是否打开
	printf("input data\n");
	printf("name、num、age\n");
	for (i = 0; i < 2; i++)
		scanf("%s %d %d", boya[i].name, &boya[i].num, &boya[i].age);
	//输入,赋值
	fwrite(boya, sizeof(struct stu), 2, fp); //
	rewind(fp); //文件指针经过写操作已经到了最后,需要复位
	fread(boyb, sizeof(struct stu), 2, fp); //将文件中的数据读入到内存中,大小是结构体的大小
	for (i = 0; i < 2; i++)
		printf("%s %d %d\n", boyb[i].name, boyb[i].num, boyb[i].age);
	fclose(fp);
	return 0;
}

文件的随机读写

移动文件内部的位置指针到需要读写的位置,再进行读写,这种读写称为随机读写
实现随机读写的关键是要按要求移动位置指针,这称为文件的定位.

完成文件定位的函数有:rewind、fseek 函数

rewind 复位读写位置

rewind(文件指针);

把文件内部的位置指针移到文件首

fwrite(pa,sizeof(struct stu),2,fp );//读的时候位置指针会往后便宜
rewind(fp);//复位读写位置
fread( pb,sizeof(struct stu),2,fp);//又可以从头读了

ftell 测文件读写位置距文件开始有多少个字节

long ftell(文件指针);

取得文件流目前的读写位置.

返回当前读写位置(距离文件起始的字节数),出错时返回-1.

long int length;
length = ftell(fp);//取得文件流目前的读写位置

fseek 定位位置指针(读写位置)

fseek 函数(一般用于二进制文件即打开文件的方式需要带b)

int fseek(FILE *stream, long offset, int whence);

//int fseek(文件类型指针,位移量,起始点);

移动文件流的读写位置.

whence 起始位置
文件开头SEEK_SET 0
文件当前位置SEEK_CUR 1
文件末尾SEEK_END 2

以起始点为基点,向前、后移动的字节数,正数往文件末尾方向偏移,负数往文件开头方向
偏移。

fseek(fp,50,SEEK_SET);//从头向尾偏移50个字节
fseek(fp,-50,SEEK_END);//从尾向头偏移50个字节
fseek(fp,0,SEEK_END);//在尾部不偏,定位到尾
fseek(fp,20,SEEK_CUR);//从当前位置向尾偏移20

打开一个文件到屏幕上

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#pragma warning(disable:4996)

int main()
{
	FILE *fp;   
	long int len;
	char* str;
	fp = fopen(".\\test.txt","r+");   //打开文件,txt文件内容一行,编码为ANSI
	if (fp == NULL)                   //判断文件是否打开
	{
		perror("fopen");
		return 0;
	}
	fseek(fp, 0, SEEK_END);              //定位位置指针到文件尾
	len = ftell(fp);                   //取得文件字节数
	rewind(fp);                 //复位位置指针到文件头
	printf("%d\n", len);
	str = malloc(len+1);         //申请动态内存加1
	if (str == NULL)                //判断动态内存是否申请成功
	{
		perror("malloc");
		return 0;
	}
	fread(str, len, 1, fp);          //读取文件到str
	str[len] = '\0';                 //将最后一个内存赋字符串结束符
	printf("%s\n",str);
	fclose(fp);                        //关闭文件
	free(str);                         //释放申请的内存
	return 0;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值