C语言语法基础--自带数据结构和文件


C语言本省对大量数据提供的数据结构:数组、结构体、共用体。包括:位运算、文件和编辑预处理。

1 数组

1.1 数组

1.1.1 数组的定义和数组元素的引用

数据是将多个相同数据类型的变量组成的集合结构,方便处理;
数组两要素:数据和下标。

  1. 一维数组的定义、引用及初始化
    一维数组是指数组中的每个元素只带有一个下标的数组。
  • 一维数组的一般定义形式:
    类型说明符 数组名[常量表达式];
    long array[10];
  • 引用:保证数组下标不越界;一个数组不能进行整体运算。
  • 初始化:数据类型 数组名[长度]={常量1,常量2,常量3,…};
#include <stdio.h>
int main(){
	int i,arr[10];	// 定义
	for(i=0;i<10;i++){
		printf("please input number%d:",i+1);
		scanf("%d",&arr[i]);		//依次从键盘输入10个数,为数组赋值。
	}
}
  1. 二维数组的定义、引用及初始化
  • 一般形式: 数据类型 数组名[常量表达式1][常量表达式2];
    二维数组在内存空间是连续的,按照行存放。
  • 二维数组引用:一般引用形式:数组名[下标表达式1][下标表达式2];
  • 初始化:int array[2][2]={{1,1},{2,2}};
    可以省略行下标,但不能省略列下标。

1.1.2 字符数组

字符数组:就是数组中的每个元素都是字符。

  1. 字符数组的一般定义式:
    一维数组:char 数组名 [下标表达式] char ch[8];
    二维字符数组:char 数组名[行下标表达式][列下标表达式] char ch[8][8];
    说明一个字符数组时,数组名前的数据类型为char。
  2. 字符数组的引用:一般引用形式:
    一维字符数组:数组名[下标表达式]
    二维字符数组:数组名[行下标表达式][列下标表达式]
  3. 字符数组的初始化:对字符数组初始化时,使用对一般数组元素初始化的方法,把字符逐个赋值给数组元素。初值个数少于数组长度,系统会自动补’\0’。
  4. 字符数组的输入/输出:
  • 用"%c"格式将字符逐个输入或输出,并且输入时需要在最后认为的加入’\0’,输出时以’\0’作为结束标志。
  • 用’%s’格式字符串将整个字符串一次输入或输出。
#include <stdio.h>
main(){
	int i;
	char day[4][10]={'Mornning','Afternoon','Everything','Night'};
	for(i=0;i<4;i++){
		printf("\n %s\t",day[i]);	// day[i]代表该行数组元素的首地址
	}

}

1.1.3 字符串

  1. 用字符串完成初始化:以字符’\0’作为字符串的结束标识。
    char ch[8]=“Beijing”; //最后一个’\0’系统自动加上的。
  2. 常用字符串处理函数
  • scanf("%s",地址);
  • 用gets函数输入字符串:gets(地址);
  • printf("%s",字符串首地址); //一次输出多个
  • puts(字符串首地址); // 自动利用’\n’取代字符串结束表示’\0’。用puts函数输出字符串时,会自动输出一个换行符,不要求另加换行符。
  • 求字符串长度函数strlen(s);
  • 字符串复制函数strcpy(s1,s2);
  • 字符串比较函数strcmp(s1,s2);

1.1.4 数组应用举例

【例子】使用冒泡法对数组元素进行排序

#include <stdio.h>
int main(){
	int arr[10]={1,4,42,56,82,12,18,50,23,62};	// 定义一个含有10个元素的数组arr,并且进行初始化
	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】

// 对长度为20的一维数组,对其中依次存放从2开始的偶数,将这些数每5个一行逆序输出,然后求出这些偶数和以及平均值,并输出最终的结果
#include <stdio.h>
# include <conio.h>

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 <stdio.h>
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语言中,用户自定义的数据类型:

  1. typedef 已有类型 起新名;
  2. 结构体(struct):把具有相互关系的不同类型的数据组成一个有机整体;
  3. 共用体(union): 又称联合体,使几种不同类型的变量公用一段存储空间。

2.1 typedef

一般形式:typedef 类型名 标识符;// 类型名一定是在此语句之前已有定义的类型标识符。typedef语句的作用仅仅是用"标识符"来代表已存在的"类型名",并未产生新的数据类型。
基本都是和struct连用

2.2 结构体

2.2.1 结构体类型的定义和引用

  1. 一般形式:
    struct 结构体标识名 {
    类型名1 结构体成员表1;
    类型名2 结构体成员表2;

    结构体类型n 结构体成员表n;
    }
    struct student{
    char name[12];
    char sex;
    int age;
    }; // 只是定义,后面有分号
    结构体只是说明列出该结构的组成情况,并没有给结构体分配内存;真正占用内存空间的是具有相应结构类型的变量、数组以及动态开辟的存储单元;因此在使用结构体变量、数组或指针变量之前,必须先对这些变量、数组或指针变量进行定义
  2. 结构体变量的定义
    定义结构体类型的成员变量、数组和指针变量有以下四种方式:
  • 在定义结构体类型的同时定义结构体变量,一般形式:
    struct 结构体名{
    成员定义表 ;

}变量名表; // 可以不限使用再定义新变量

struct student {
	char name[10];
	char sex;
	struct data birthday;
	int number;
	float pers[4];
}std,pers[3],*p;	// 定义了一个结构体变量std,具有三个元素的结构体数组pers和基类型为结构体类型的指针变量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;
  1. 结构体变量初始化
    和一般的变量、数组一样,结构体变量和数组也可以在定义的同时赋初值;
  • 结构体变量赋初值
    所赋初值顺序放在一对花括号中,例如:
    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’}};
  1. 结构体变量的引用
    三种形式:
    结构体变量名.成员名;
    指针变量名->成员名;
    (*指针变量名).成员名;
    点号. 称为成员运算符;箭头->称为结构指向运算符

2.3 共用体类型的定义和引用

共用体的类型说明和变量的定义方式 与结构体的类型说明和便令定义方式相同。不同的是,结构体中的成员各自占有自己的内存空间,而共有体的变量中的所有成员占有同一个存储空间。

  1. 共用体类型的定义
    一般形式:
    union 标识名{
    数据类型1 成员名1;
    数据类型2 成员名2;

    };
    说明:
  • union是关键字,是共用体类型的标志。共用体名是用户定义的标识类型。
  • 大括号{}中的内容是组成该共用体的成员
  • 当有多个相同类型的成员是,成员说明之间用逗号分隔
    union un_1{
    int i;
    float y;
    char ch;
    };
  1. 共用体变量的定义
    共用体变量定义和结构体相同,用以下四种方式进行定义:
  • 在定义共用体类型的同时定义变量。一般形式如下:
    union 共用体名{
    成员定义表;
    }变量名表;
  • 先申明共用体类型,在定义共用体变量。一般形式如下:
    union 共用体名变量名表;
  • 直接定义共用体类型变量。一般形式如下:
    union{
    成员定义表;
    }变量名表;
  • 使用typedef说明一个共用体类型名,再用新类型名来定义变量。
  1. 共用体变量的引用和赋值
  • 共用体变量中的每个成员的引用方式与结构体完全相同。
    三种形式:共用体变量名.成员名 指针变量名->成员名 (*指针变量名).成员名
    共用体中的成员变量同样可参与其所属类型允许的任何操作。
  • 共用体变量的整体赋值
    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 节点数据的输出、删除和插入

链表是一种重要的数据结构,可以动态进行数据的内存分配。对链表的操作包括链表的建立,链表节点的插入和删除等。

  1. 插入节点
    若要在a,b之间插入c,则需要指针指向a,然后c->next=a->next;a->next=c;
  2. 删除节点
    若在a,c,b三个连续节点中删除c,则将指针指向a后,再将a->next=c->next。
    链表的操作原则是:保证操作顺利完成而且不致丢失。
    【程序实例】编写函数inset_snode,它的功能是:在值为x的节点前插入值为y的节点,若值为x的节点不存在,则插在表尾。
#include <stdio.h>
#inlcude <stdlib.h>
insert_snode(SLIST* head,int x,int y){
	s=(SLIST*)malloc(sizeof(SLIST));	//生成新节点
	s->data->y;		//在节点中存入y的值
	q=head;p=head->next;	//工作指针初始化,p指向第一个结点
	while((p!'\0')&&(p->data!=x)){	//表非空且未到末尾,查找x的位置
		q=p;p=p->next;		// q指向p的前驱节点
	} 
	s->netx=p;q->next=s;	//x存在,插在x之前;则x不存在,p的值为NULL,插在末尾。
}

3 编辑预处理、位运算和文件

文件:在外部介质上的数据的集合称为"文件"。

3.1 文件

文件定义:是指存储在外部介质上的数据的集合,是操作系统进行数据管理的基本单位。
文件的分类:1. 按照存取方式:分为顺序存取和直接存取文件。2. 按照数据存放方式:文本文件和二进制文件。
文本文件:输入数据时,数据转换成一串字符,每个字符以字符的ASCII码值存储到文件中,一个字符占一个字节。
二进制文件:当数据按二进制的形式输出到文件中时,数据是不经过任何转换,按计算机的存储形式直接存放到磁盘上。

文件指针一般形式:FILE* 指针变量名;文件指针用于存放文件缓冲区的首地址,在缓冲文件系统中可以进行文件的打开、关闭、读、写定位等操作。在对文件进行相应的操作之前,必须先定义一个指向文件的指针。

3.2 文件的打开与关闭

  1. fopen函数的调用形式:fopen(“文件名”,“文件使用方式”);
    FILE* fp;
    fp=open(“文件名”,“文件使用方式”);
  • 文件名 是指要进行读/写操作的文件名称,用来指定所要打开的文件。
  • 当函数调用成功时,函数返回一个FILE类型的指针;当打开文件出现了错误,fopen函数将返回NULL;
  1. 常用文件使用方式
    r:以只读方式打开一个文本文件。
    rb:以只读方式打开一个二进制文件。
    w:以只写方式打开一个文本文件。
    wb:以只写方式打开一个二进制文件。
    a:为在文件后面添加数据打开一个文本文件。
    ab: 为在文件后面添加数据打开一个二进制文件。其余功能’a’相同。
    r+:以读/写方式打开一个文本文件。读写操作之间不需要关闭文件。对于文本文件来说,读/写总是从文件的起始位置开始。在写新的数据时,只覆盖新数据所占的空间,其后的旧数据并不丢失。
    rb+: 以只读/写方式打开一个二进制文件。功能与’r++'相同,只是在读/写时,可由位置函数设置读/写的起始位置。
    w+:先建立一个新文件,进行写操作,然后从头开始读。如果指定的文件已存在,则原有的内容讲全部消失。
    wb+:功能与w+相同,只是在随后的读/写时,可以由位置函数设置读/写的起始位置。
    a+: 功能与a相同,只是在文件尾部添加新的数据之后,可以从头开始读。
    ab+:功能与’a+'相同,只是在文件尾部添加新的数据之后,可以由位置函数设置开始读的起始位置。
  2. 3个标准文件
    在程序开始运行时,系统自动打开3个标准文件,并分别定义以下文件指针:
    标准输入文件:stdin:指向终端输入
    标准输出文件:stdout:指向终端输出
    标准错误文件:stderr:指向终端标准错误输出
    **这三个文件已在"stdio.h"头文件进行了声明。
  3. 用fclose函数关闭数据文件
    当一个文件的读/写操作完成后,要将文件关闭。通过调用库函数fclose来实现关闭文件的操作。
    fclose函数调用的一般形式如下:fclose(FILE* 文件指针)
    如果文件正常关闭,则函数返回值为0;否则,返回值为非0;
    fclose(fp);关闭fp所指向的文件。

3.3 文件的读与写

在C语言中,文件的读/写操作并没有固定的输入/输出文件,而是通过调用C语言中的库函数来实现。
文件读/写操作一般四种形式:
读/写文件中的一个字符;
读/写一个字符串;
读/写一个数据块;
对文件进行格式化读/写;

3.3.1 fgetc函数和fputc函数

  1. 通过调用fgetc函数和fputc函数来实现从文件中读/写一个字符。
    调用fgetc函数从文件中读入一个字符,其一般形式如下:
    fgetc(文件指针);
    ch=fgetc(fp);
  2. 调用fputc函数在文件中写入一个字符,其一般形式如下:fputc(字符数据,字符指针);
    将字符数据写入到"文件指针"所指向的文件中去,同时将读/写位置指针的向前移动一个字节(即指向一个写入位置)。
    如果写入成功,则函数返回值就是写入的字符的数据;否则,返回一个符号常量EOF(其值在头文件stdio.h中,被定义为-1)。

3.3.2 fgets函数和fputs函数

  1. 通过调用fgets函数和fputs函数来实现从文件中读/写一个字符串。
    调用fgets函数从文件中读入一个字符串,其一般形式如下:
    fgets(str,fp); //fp是文件指针,str是存放字符串的起始地址;n是一个int型变量。从fp所指文件中读入n-1个字符放入以str为起始地址的空间内。读入结束后,系统将自动在最后加’\0’,并以str作为函数值返回。
  2. 调用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函数来实现格式话读/写文件。

  1. fscanf函数只能从文本文件中按格式输入。
    调用fscanf函数的一般形式如下:fscanf(文件指针,指针控制字符串,输入项表);
    【例如】fscanf(fp,"%d %d",&a,&b);
  2. fprintf函数按格式将内存中的数据转换成对应的字符,并以ASCII代码形式输出到文本文件中。
    调用fprintf()函数的一般形式如下:
    fprintf(文件指针,格式控制字符串,输出列表);
    fprintf(fp,"%d%d",x,y);

3.5 文件的定位

文件的定位是指通过文件位置指针来表示当前读/写的数据在文件中的位置。

3.5.1 rewind函数和fseek函数

  1. fseek函数用来移动文件位置指针到指定的文职上,接着的读/写操作将从此位置上开始。
    调用fseek函数的一般形式如下:fseek(pf,offset,origin); // pf是文件指针;offset是以字节为单位的位移量,为长整型数;origin是起始点,用于指定位移量是以哪个位置为基准,起始点可即可用标识符来表示,也可用数字来表示。
  2. rewind函数又称"反绕"函数
    调用rewind函数的一般形式如下:
    rewind(pf);
    此处为pf文件指针。此函数没有返回值,函数的功能是使文件的位置指针回到文件的开头。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值