结构体 structre
看完简介,觉得与PHP中关联数组尤其是object是一样的。
定义
struct Student{
int num;
char name[20];
char sex;
int age;
float score;
};
值得注意的是Student 是一个类型名,是一种类型(自定义的),并不是这个数据的名称
定义结构体变量
struct Student a={10101,"xiaoming",'M',15,88.8};
使用结构体变量
a.name
&a代表a的首地址
结构体数组
一个包含统一结构体类型的数组 就是结构体数组
struct Student a[2]={{10101,"xiaoming",'M',15,88.8},{10102,"xiaohong",'W',14,99}};
结构体指针
struct Student * p:
(*p).num 一般使用更直观的 p->num 这样的写法
指向结构数组的时候 (p++)->num 是先指向后自增的 括号也不会让他先加
结构体作为函数参数
结构体变量作为参数并不是传递地址,而至把自己整个传到形参那。
所以一般用指针传(省内存)。
指针处理链表
链表:
头:头指针指向第一个元素
身:每个元素包含1内容 2指向下个元素的地址
尾:1内容 2 null
链表在内存中可以是不连续的,链表的意义解决了数组无法准确定义未知大小数据时必须保证大于数据的同时会造成空间浪费的缺陷。
静态链表
struct S{
int id;
float score;
struct S * next;
};
struct S a,b,c,* p;
a.id=01;a.score=66;
b.id=02;b.score=77;
c.id=03;c.score=88;
p=&a;
a.next=&b;
b.next=&c;
c.next=null;
以上为静态链表,所有结点是在程序中定义的,不是临时也不能用完释放。
动态链表
#define LEN sizeof(struct S);
struct S{
int id;
float score;
struct S * next;
}
struct S * creat(void){
struct S * head;
struct S * p1,p2;
n=0;
p1=p2=malloc(LEN);
scanf("%d,%f",&p1->id,&p1->score);
head=null;
while(p1->id!=0){
n++;
if(n==1)head=p1;
else p2->next=p1;
p2=p1;
p1=malloc(LEN);
scanf("%d,%f",&p1->id,&p1->score);
}
p2->next=null;
return(head);
}
以上为动态链表创建函数,看的时候很绕,最后在纸上画出来才弄明白。在脑海中模拟运行很烧脑
链表输出
共用体类型 union
union Data{
int id;
char sex;
float score;
};
union Data a,b,c;
共用体与结构体有点像
区别是 struct是每个元素分别占用自己的内存,比如上述结构一个struct应占用4+1+4=9个字节
但union只占用元素中占用最长的的字节,上述最长的是4,所以这个union仅占用4个字节。
特点
同时存在与union中的只能有一个元素 (突然有种弱类型语言的感觉 - -)
union Data a={97};
printf(“%c”,a.sex);//输出 a 97对应a
枚举类型 enumeration
只有几个可能的值的变量
enum Weekday{sun,mon,tue,wed,thu,fri,sat};//声明枚举类型
enum Weekday workday;//声明枚举变量
类似html select标签,事先指定选项,只能设定指定的值之一
也可以不声明类型名直接定义变量
enum{sun,mon,tue,wed,thu,fri,sat} workday,weekend;
每个枚举元素代表一个整数,默认为0,1,2,3…如上述sun的值为0
workday=mon;
相当于workday=1;//是不是感觉很曹丹
也可以在定义类型时赋元素的数值
在后面的例子中,是用了switch去判断然后输出的对应的值的,要是能直接输出(现在直接输出是整形数字)就好了
用typedef声明新类型名
简单的声明
typedef int Integer;//相当于给int类型取了个别名
Integer i,j;//这样声明变量类型其实与int一样
复杂类型的声明
typedef struct {
int id;
float score;
}Info;
在用这个新类型的时候
Info student;//不用再写struct了
数组类型、指针类型、指向函数的指针类型等均可。
使用方法归纳
按定义变量的方式,把变量名换为新类型名,在最前面加上 typedef,就声明了新类型名代表原来的类型
用typedef只是对现在的类型制定一个新名称,并没有创造新的类型,仅此而已,只是为了使用更加方便。方便你妹
实用例子
有的计算机int是4字节有的是2字节,若直接用int,移植不同的系统需要对int进行更改(改为long)
如果type int Integer;并且只用Integer
则只改为 type long Integer;就行了
估计这个时代是用不到了
文件的输入输出
文件的意思
存储在外部介质上的数据的集合
操作系统一般把各种设备也统一作为文件来处理linux是这样,win就不知道了
输入输出像流水一样,被成为流 stream 数据流,表示信息的流动
C把文件看作是一个字符(或字节)的序列
文件名
1、文件路径 2、文件名、 3、后缀名(扩展名)
分类
根据数组的组织形式,分为ASCⅡ文件(文本文件)和二进制文件(映像文件)
ASCⅡ:一个字符占一个字节
二进制:占用空间少,并且读入内存无需转换
文件缓冲区
C处理数据文件时,会对文件开辟一个文件缓冲区,读入输出都会先把数据放到缓冲区,满了之后才送到程序数据区/磁盘。
文件类型指针
C编译环境提供的stdio.h中 声明了FILE类型 为struct类型 放在一个单独的文件信息区
一般设一个指针变量指向这个FILE数据
FLIE * fp;
打开与关闭
打开:建立文件信息区、文件缓冲区,指定指针
关闭:撤销以上。
fopen(文件名,使用文件方式);
返回一个文件指针 失败返回 null
fclose(文件指针)//成功返回0,失败返回-1
读写
单个字符的读写
fgetc(fp);
fputc(c,fp);
feof(fp);检查文件读写位置是否移动到文件的末尾。是 真 否 假
字符串的读写
fgets(str,n,fp)//取长度为n的字符串放到str里
fputs(str,fp)//把str放到文件里
格式化方式读写文件
类似于printf和scanf
fprintf(文件指针,格式字符串,输出表列);
fscanf(文件指针,格式字符串,输入表列);
如fprintf(fp,”%d,%f”,i,f);
二进制方式读写
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
buffer使用的数据起始地址
size要读写的字节数
count读写的数据数量(每个长度为size)
fp FILE指针
执行成功返回count个数
随机读写数据文件
为了解决顺序读写,用到第N个数据(比如第100W个)必须读完前面所有数据的问题,使用随机读写,可以对任意位置数据进行访问。
文件位置标记
在顺序读写中 默认标记在第1个字符,每读取一个就向后移动一个位置
根据需要对标记进行移动然后再读写,就是随机读写。
rewind(fp);//使标记指向文件头
fseek(fp,移动距离,起始点)
移动距离为字节数,应是long型数据,在末尾加一个L,正数表示向后移动,负数表示向前移动
0表示开始,1当前,2末尾
ftell(fp);//返回标记相对开头的距离。若失败(fp指向的文件不存在)返回-1L
读写出错检测
ferror(fp);//未出错返回0,出错返回非零值。仅针对最近一次输入输出有效。
clearerr(fp)://使文件 错误标志和文件结束标志为0 感觉没什么用
第11章为常见的错误
总结
看完了但还是一脸懵逼