S3--自带数据结构、文件、预处理和位运算
- 1 数组
-
- 1.1 数组
-
- 1.1.1 数组的定义和数组元素的引用
- 1.1.2 字符数组
- 1.1.3 字符串
- 1.1.4 数组应用举例
- 2 结构体和共用体
-
- 2.1 typedef
- 2.2 结构体
-
- 2.3 共用体类型的定义和引用
- 2.4 链表的建立
-
- 2.4.1 链表的组成
- 2.4.2 单向链表的建立
- 2.4.3 节点数据的输出、删除和插入
- 3 编辑预处理、位运算和文件
-
- 3.1 文件
- 3.2 文件的打开与关闭
- 3.3 文件的读与写
-
- 3.3.1 fgetc函数和fputc函数
- 3.3.2 fgets函数和fputs函数
- 3.3.3 fread函数和fwrite函数
- 3.3.4 fscanf函数和fprintf函数
- 3.5 文件的定位
-
C语言本省对大量数据提供的数据结构:数组、结构体、共用体。包括:位运算、文件和编辑预处理。
1 数组
1.1 数组
1.1.1 数组的定义和数组元素的引用
数据是将多个相同数据类型的变量组成的集合结构,方便处理;
数组两要素:数据和下标。
- 一维数组的定义、引用及初始化
一维数组是指数组中的每个元素只带有一个下标的数组。
- 一维数组的一般定义形式:
类型说明符 数组名[常量表达式];
long array[10];
- 引用:保证数组下标不越界;一个数组不能进行整体运算。
- 初始化:数据类型 数组名[长度]={常量1,常量2,常量3,…};
#include
int main(){
int i,arr[10];
for(i=0;i<10;i++){
printf("please input number%d:",i+1);
scanf("%d",&arr[i]);
}
}
- 二维数组的定义、引用及初始化
- 一般形式: 数据类型 数组名[常量表达式1][常量表达式2];
二维数组在内存空间是连续的,按照行存放。
- 二维数组引用:一般引用形式:数组名[下标表达式1][下标表达式2];
- 初始化:int array[2][2]={{1,1},{2,2}};
可以省略行下标,但不能省略列下标。
1.1.2 字符数组
字符数组:就是数组中的每个元素都是字符。
- 字符数组的一般定义式:
一维数组:char 数组名 [下标表达式] char ch[8];
二维字符数组:char 数组名[行下标表达式][列下标表达式] char ch[8][8];
说明一个字符数组时,数组名前的数据类型为char。
- 字符数组的引用:一般引用形式:
一维字符数组:数组名[下标表达式]
二维字符数组:数组名[行下标表达式][列下标表达式]
- 字符数组的初始化:对字符数组初始化时,使用对一般数组元素初始化的方法,把字符逐个赋值给数组元素。初值个数少于数组长度,系统会自动补’\0’。
- 字符数组的输入/输出:
- 用"%c"格式将字符逐个输入或输出,并且输入时需要在最后认为的加入’\0’,输出时以’\0’作为结束标志。
- 用’%s’格式字符串将整个字符串一次输入或输出。
#include
main(){
int i;
char day[4][10]={'Mornning','Afternoon','Everything','Night'};
for(i=0;i<4;i++){
printf("\n %s\t",day[i]);
}
}
1.1.3 字符串
- 用字符串完成初始化:以字符’\0’作为字符串的结束标识。
char ch[8]=“Beijing”; //最后一个’\0’系统自动加上的。
- 常用字符串处理函数
- scanf("%s",地址);
- 用gets函数输入字符串:gets(地址);
- printf("%s",字符串首地址); //一次输出多个
- puts(字符串首地址); // 自动利用’\n’取代字符串结束表示’\0’。用puts函数输出字符串时,会自动输出一个换行符,不要求另加换行符。
- 求字符串长度函数strlen(s);
- 字符串复制函数strcpy(s1,s2);
- 字符串比较函数strcmp(s1,s2);
1.1.4 数组应用举例
【例子】使用冒泡法对数组元素进行排序
#include
int main(){
int arr[10]={1,4,42,56,82,12,18,50,23,62};
int i,j,temp;
for(i=0;i<10;i++){
printf("%d",arr[i]);
}
printf('\n');
for(i=1;i<10;i++){
for(j=0;j<a10-i;j++){
if(arr[j]<arr[j+i]){
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
for(i=0;i<10;i++){
printf("%d",arr[i]);
}
}
【例子2】
#include
# include
float fun(int a[20]);
void main(){
int a[20],k,m,n,tot;
float aver=0.0;
for(m=0,k=2;m<20;m++,l=k+2){
a[m]=k;
}
printf("average is: %f",fun(a));
}
float fun(int a[20]){
int tot,m,k;
for(m=19,k=1,tot=0;m>=0;m--,k--){
printf("%4d",a[m]);
if(k%5==0){
printf("\n");
tot=tot+a[m];
}
}
printf("total is :%ld",tot);
return(tot/20.0);
}
#include
int main(){
char str[1000];
while(i<=1000){
str[i]=getchar();
if(str[i]=='\n'){
break;
i++;
}
}
while(str[i]!='\n'){
printf("%c",str[i+1]);
}
printf("\n");
}
2 结构体和共用体
在C语言中,用户自定义的数据类型:
- typedef 已有类型 起新名;
- 结构体(struct):把具有相互关系的不同类型的数据组成一个有机整体;
- 共用体(union): 又称联合体,使几种不同类型的变量公用一段存储空间。
2.1 typedef
一般形式:typedef 类型名 标识符;// 类型名一定是在此语句之前已有定义的类型标识符。typedef语句的作用仅仅是用"标识符"来代表已存在的"类型名",并未产生新的数据类型。
基本都是和struct连用
2.2 结构体
2.2.1 结构体类型的定义和引用
- 一般形式:
struct 结构体标识名 {
类型名1 结构体成员表1;
类型名2 结构体成员表2;
…
结构体类型n 结构体成员表n;
}
struct student{
char name[12];
char sex;
int age;
}; // 只是定义,后面有分号
结构体只是说明列出该结构的组成情况,并没有给结构体分配内存;真正占用内存空间的是具有相应结构类型的变量、数组以及动态开辟的存储单元;因此在使用结构体变量、数组或指针变量之前,必须先对这些变量、数组或指针变量进行定义
- 结构体变量的定义
定义结构体类型的成员变量、数组和指针变量有以下四种方式:
- 在定义结构体类型的同时定义结构体变量,一般形式:
struct 结构体名{
成员定义表 ;
}变量名表; // 可以不限使用再定义新变量
struct student {
char name[10];
char sex;
struct data birthday;
int number;
float pers[4];
}std,pers[3],*p;
- 先声明结构体类型,再定义结构体变量,一般形式:
struct 结构体名{
成员定义表;
};
struct 结构体名 变量名表;
struct stduent{
…
};
struct stduent std,pers[3],*p;
- 直接定义结构体类型变量,省略结构体类型名;但这只能一次性使用:
struct {
成员定义表;
}变量名表;
struct {
char name[10];
char sex;
struct data birthday;
float sc[4];
} std,pers[3],*p;
// 只能使用一次性,不能再定义其他结构体变量名
- 使用typedef 说明一个结构体类型名,再用新类型名来定义变量
typedef struct {
char name[10];
char sex;
struct data birthday;
float sc[4];
} ST;
ST std,pers[3],*p;
- 结构体变量初始化
和一般的变量、数组一样,结构体变量和数组也可以在定义的同时赋初值;
- 结构体变量赋初值
所赋初值顺序放在一对花括号中,例如:
struct data{
int year,month,day;
} ;
struct stduent{
struct name[12] ,sex;
struct data birthday;
} s1={“zhangsan”,‘M’,"{1998,7,5}"}, s2={“Chenhong”,‘F’,{1993,3,4}},s3;
- 结构体数组赋初值
struct s{
char name[5],name[12],sex;
} stu[2] = {{“10002”,“List”,‘M’},{“10003”,“Wangming”,‘M’}};
- 结构体变量的引用
三种形式:
结构体变量名.成员名;
指针变量名->成员名;
(*指针变量名).成员名;
点号. 称为成员运算符;箭头->称为结构指向运算符
2.3 共用体类型的定义和引用
共用体的类型说明和变量的定义方式 与结构体的类型说明和便令定义方式相同。不同的是,结构体中的成员各自占有自己的内存空间,而共有体的变量中的所有成员占有同一个存储空间。
- 共用体类型的定义
一般形式:
union 标识名{
数据类型1 成员名1;
数据类型2 成员名2;
…
};
说明:
- union是关键字,是共用体类型的标志。共用体名是用户定义的标识类型。
- 大括号{}中的内容是组成该共用体的成员
- 当有多个相同类型的成员是,成员说明之间用逗号分隔
union un_1{
int i;
float y;
char ch;
};
- 共用体变量的定义
共用体变量定义和结构体相同,用以下四种方式进行定义:
- 在定义共用体类型的同时定义变量。一般形式如下:
union 共用体名{
成员定义表;
}变量名表;
- 先申明共用体类型,在定义共用体变量。一般形式如下:
union 共用体名变量名表;
- 直接定义共用体类型变量。一般形式如下:
union{
成员定义表;
}变量名表;
- 使用typedef说明一个共用体类型名,再用新类型名来定义变量。
- 共用体变量的引用和赋值
- 共用体变量中的每个成员的引用方式与结构体完全相同。
三种形式:共用体变量名.成员名 指针变量名->成员名 (*指针变量名).成员名
共用体中的成员变量同样可参与其所属类型允许的任何操作。
- 共用体变量的整体赋值
ASNI C标准允许在两个类型相同的共用体变量进行赋值操作。
【例如】
c1.i=3;
c2=c1;
printf("%d\n",c2.i);
// 程序执行结果:3
2.4 链表的建立
2.4.1 链表的组成
头指针:存放第一个数据节点的地址;
节点:包括数据域和指针域。
链表的结构形式:头指针—>数据域+指针域---->数据域+指针域---->…—>数据域+NULL
2.4.2 单向链表的建立
单向链表的每个结点应该是由两个成员组成:一个是数据域;另一个是指向下一个节点的指针域。
节点类型定义如下:
struct slist{
int data;
struct slist* next;
};
typedef struct slist SLIST;
建立带有头结点的单向链表步骤如下:
读取数据
生成新节点
将数据存入节点的成员变量中
将节点插入到链表中,重复上述操作直至输入结束
2.4.3 节点数据的输出、删除和插入
链表是一种重要的数据结构,可以动态进行数据的内存分配。对链表的操作包括链表的建立,链表节点的插入和删除等。
- 插入节点
若要在a,b之间插入c,则需要指针指向a,然后c->next=a->next;a->next=c;
- 删除节点
若在a,c,b三个连续节点中删除c,则将指针指向a后,再将a->next=c->next。
链表的操作原则是:保证操作顺利完成而且不致丢失。
【程序实例】编写函数inset_snode,它的功能是:在值为x的节点前插入值为y的节点,若值为x的节点不存在,则插在表尾。
#include
#inlcude
insert_snode(SLIST* head,int x,int y){
s=(SLIST*)malloc(sizeof(SLIST));
s->data->y;
q=head;p=head->next;
while((p!'\0')&&(p->data!=x)){
q=p;p=p->next;
}
s->netx=p;q->next=s;
}
3 编辑预处理、位运算和文件
文件:在外部介质上的数据的集合称为"文件"。
3.1 文件
文件定义:是指存储在外部介质上的数据的集合,是操作系统进行数据管理的基本单位。
文件的分类:1. 按照存取方式:分为顺序存取和直接存取文件。2. 按照数据存放方式:文本文件和二进制文件。
文本文件:输入数据时,数据转换成一串字符,每个字符以字符的ASCII码值存储到文件中,一个字符占一个字节。
二进制文件:当数据按二进制的形式输出到文件中时,数据是不经过任何转换,按计算机的存储形式直接存放到磁盘上。
文件指针一般形式:FILE* 指针变量名;文件指针用于存放文件缓冲区的首地址,在缓冲文件系统中可以进行文件的打开、关闭、读、写定位等操作。在对文件进行相应的操作之前,必须先定义一个指向文件的指针。
3.2 文件的打开与关闭
- fopen函数的调用形式:fopen(“文件名”,“文件使用方式”);
FILE* fp;
fp=open(“文件名”,“文件使用方式”);
- 文件名 是指要进行读/写操作的文件名称,用来指定所要打开的文件。
- 当函数调用成功时,函数返回一个FILE类型的指针;当打开文件出现了错误,fopen函数将返回NULL;
- 常用文件使用方式
r:以只读方式打开一个文本文件。
rb:以只读方式打开一个二进制文件。
w:以只写方式打开一个文本文件。
wb:以只写方式打开一个二进制文件。
a:为在文件后面添加数据打开一个文本文件。
ab: 为在文件后面添加数据打开一个二进制文件。其余功能’a’相同。
r+:以读/写方式打开一个文本文件。读写操作之间不需要关闭文件。对于文本文件来说,读/写总是从文件的起始位置开始。在写新的数据时,只覆盖新数据所占的空间,其后的旧数据并不丢失。
rb+: 以只读/写方式打开一个二进制文件。功能与’r++'相同,只是在读/写时,可由位置函数设置读/写的起始位置。
w+:先建立一个新文件,进行写操作,然后从头开始读。如果指定的文件已存在,则原有的内容讲全部消失。
wb+:功能与w+相同,只是在随后的读/写时,可以由位置函数设置读/写的起始位置。
a+: 功能与a相同,只是在文件尾部添加新的数据之后,可以从头开始读。
ab+:功能与’a+'相同,只是在文件尾部添加新的数据之后,可以由位置函数设置开始读的起始位置。
- 3个标准文件
在程序开始运行时,系统自动打开3个标准文件,并分别定义以下文件指针:
标准输入文件:stdin:指向终端输入
标准输出文件:stdout:指向终端输出
标准错误文件:stderr:指向终端标准错误输出
**这三个文件已在"stdio.h"头文件进行了声明。
- 用fclose函数关闭数据文件
当一个文件的读/写操作完成后,要将文件关闭。通过调用库函数fclose来实现关闭文件的操作。
fclose函数调用的一般形式如下:fclose(FILE* 文件指针)
如果文件正常关闭,则函数返回值为0;否则,返回值为非0;
fclose(fp);关闭fp所指向的文件。
3.3 文件的读与写
在C语言中,文件的读/写操作并没有固定的输入/输出文件,而是通过调用C语言中的库函数来实现。
文件读/写操作一般四种形式:
读/写文件中的一个字符;
读/写一个字符串;
读/写一个数据块;
对文件进行格式化读/写;
3.3.1 fgetc函数和fputc函数
- 通过调用fgetc函数和fputc函数来实现从文件中读/写一个字符。
调用fgetc函数从文件中读入一个字符,其一般形式如下:
fgetc(文件指针);
ch=fgetc(fp);
- 调用fputc函数在文件中写入一个字符,其一般形式如下:fputc(字符数据,字符指针);
将字符数据写入到"文件指针"所指向的文件中去,同时将读/写位置指针的向前移动一个字节(即指向一个写入位置)。
如果写入成功,则函数返回值就是写入的字符的数据;否则,返回一个符号常量EOF(其值在头文件stdio.h中,被定义为-1)。
3.3.2 fgets函数和fputs函数
- 通过调用fgets函数和fputs函数来实现从文件中读/写一个字符串。
调用fgets函数从文件中读入一个字符串,其一般形式如下:
fgets(str,fp); //fp是文件指针,str是存放字符串的起始地址;n是一个int型变量。从fp所指文件中读入n-1个字符放入以str为起始地址的空间内。读入结束后,系统将自动在最后加’\0’,并以str作为函数值返回。
- 调用fputs函数在文件中读入一个字符串,其一般形式如下:
fputs(str,fp); // fp是文件指针;str是待写入的字符串,可以是字符串常量、指向字符串的指针或存放字符串的字符数组名等。
3.3.3 fread函数和fwrite函数
通过调用fread函数和fwrite函数来实现从文件中读/写二进制文件。
其一般形式如下:
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
buffer是数据块的指针,对fread来说,它是内存块的首地址,输入的数据存入次内存块中;对于fwrite来说,它是准备输出的数据块的起始地址。size表示每个数据块的字节数。count用来指定每读/写一次,输入或输出数据块的个数(每个数据块具有size字节)。
如果调用fread函数成功,则函数返回值等于count;调用fwrite成功,则函数返回值等于count
3.3.4 fscanf函数和fprintf函数
通过调用fscanf函数和dfprintf函数来实现格式话读/写文件。
- fscanf函数只能从文本文件中按格式输入。
调用fscanf函数的一般形式如下:fscanf(文件指针,指针控制字符串,输入项表);
【例如】fscanf(fp,"%d %d",&a,&b);
- fprintf函数按格式将内存中的数据转换成对应的字符,并以ASCII代码形式输出到文本文件中。
调用fprintf()函数的一般形式如下:
fprintf(文件指针,格式控制字符串,输出列表);
fprintf(fp,"%d%d",x,y);
3.5 文件的定位
文件的定位是指通过文件位置指针来表示当前读/写的数据在文件中的位置。
3.5.1 rewind函数和fseek函数
- fseek函数用来移动文件位置指针到指定的文职上,接着的读/写操作将从此位置上开始。
调用fseek函数的一般形式如下:fseek(pf,offset,origin); // pf是文件指针;offset是以字节为单位的位移量,为长整型数;origin是起始点,用于指定位移量是以哪个位置为基准,起始点可即可用标识符来表示,也可用数字来表示。
- rewind函数又称"反绕"函数
调用rewind函数的一般形式如下:
rewind(pf);
此处为pf文件指针。此函数没有返回值,函数的功能是使文件的位置指针回到文件的开头。