C语言——结构体

目录

一、定义和使用结构变量

1、建立结构体类型

 2、定义结构体类型变量

3、结构体变量的初始化和引用

二、使用结构体数组

1、指向结构体变量的指针

 2、指向结构体数组的指针

3、用结构体变量和结构体变量的指针作函数参数

四、用指针处理链表

1、什么是链表

 2、建立简单的静态链表

3、建立动态链表

 4、输出链表

 五、共用体类型

1、什么是共用体类型

 2、引用共用体变量的方式

 3、共用体类型数据的特点

六、使用枚举类型

七、用typedef声明新类型名


一、定义和使用结构变量

1、建立结构体类型

用户建立不同类型数据组成的组合数据结构,称为结构体,用于反应不同变量间的联系。

定义结构体的一般形式为:

struct  结构体名

        {

                类型名 成员名;

        };

	struct Student
	{
		int num;
		char name[20];
		char sex;
		int age;
		float score;
		char adder[30];
	};

 花括号内是该结构体所包含你的子项,称为结构体的成员,对各成员都应进行类型的声明。

此外,成员还可以属于另一个结构体类型

	struct Date
	{
		int month;
		int day;
		int year;
	};
	struct Student
	{
		int num;
		char name[20];
		char sex;
		int age;
		struct Date birthday;//属于上一个结构体类型
		char addr[30];
	};

 2、定义结构体类型变量

前面建立了一个结构体类型,其相当于一个模型,没有变量,等价于int,float,char这一类,因而应当定义结构体类型的变量,并在其中存放具体的数据。定义结构体类型变量有三种方法:

(1)先声明结构体类型,再定义该类型变量 

struct Date
	{
		int month;
		int day;
		int year;
	};//先声明
	
struct Date birthday;//再定义

 (2)在声明类型的同时定义变量

struct Date
	{
		int month;
		int day;
		int year;
	}date1,date2;//date1,date2即为定义的结构体类型变量

(3)不指定类型名而直接定义结构体类型变量 

struct 
	{
		int month;
		int day;
		int year;
	}date1,date2;//date1,date2即为定义的结构体类型变量,但没有类型名

3、结构体变量的初始化和引用

(1)定义结构体变量时,可以对它初始化,赋予初始值再引用这个变量。引用的格式为:

        结构体变量名.成员名

例:将学生信息放在一个结构体内,输出该学生的信息 
#include <stdio.h>
#include <stdlib.h>
int main()
{
	struct Student  //声明结构体类型
	{
		long int num;
		char name[20];
		char sex;
		char addr[20];
	}a={10101,"LiLin",'M',"123Beijing Road"};//初始化结构体变量
	printf("NO.%ld\nname:%s\nsex:%c\naddress:%s\n",a.num,a.name,a.sex,a.addr);
}

(2)若成员本身又属于另外一个结构体类型,则要用若干成员运算符,一级一级地找到最低一级的成员。只能对最低级地成员进行赋值。 

student1.num //结构体student1中的成员num
student1.birthday.month//结构体变量student1中成员birthday中的成员month

 (3)对结构体变量的成员可以像普通变量一样进行各种运算

student1.score=student2.score//赋值
sum=student1.score+student2.score//加法
student1.age++ //自加

(4)同类的结构体变量可以相互赋值

student1=student2

二、使用结构体数组

定义结构体数组一般形式为:

(1)struct 结构体名

        {成员表列} 数组名[数组长度];

(2)先声明一个结构体类型(如struct Person),再用此类型定义结构体数组:

        struct Person leader[3];

struct Date
	{
		int month;
		int day;
		int year;
	}birthday[3]={2001,1,1,2022,1,2,2020,1,3};//定义结构体数组并初始化

或声明后再定义结构体数组
struct Date birthday[3]={2001,1,1,2022,1,2,2020,1,3};
例:有三个候选人,10个选民,每个选民只能投一票,编写一个投票程序,先后输入候选人名字,最后输出各人得票结果 
#include <stdio.h>
#include <stdlib.h>

struct Person  							//声明结构体类型 struct Person 
{
	char name[20];
	int count;
}leader[3]={"Li",0,"Zhang",0,"Sun",0};  //定义结构体数组并初始化 

int main()
{
	int i,j;
	char leader_name[20];
	for(i=1;i<=10;i++)
	{
		scanf("%s",leader_name);				//候选人名字 
		for(j=0;j<3;j++)
		{
			if(strcmp(leader_name,leader[j])==0) leader[j].count++;//与结构体数组进行匹配 
		}
	}
	printf("\nresult:\n");
	for(i=0;i<3;i++)
	{
		printf("%5s:%d\n",leader[i].name,leader[i].count);
	}
	return 0;
}

 三、结构体指针

1、指向结构体变量的指针

指向结构体对象的指针变量既可以指向结构体变量,也可以指向结构体数组中的元素。指针变量的基类型必须与结构体变量的类型相同。

struct Student *pt;
例:使用结构体指针输出学生信息 
#include <stdio.h>
#include <stdlib.h>

int main()
{
	struct Student
	{
		long num;
		char name[20];
		char sex;
		float score;
	 } ;
	struct Student stu_1;
	struct Student *p;
	p=&stu_1;
	stu_1.num=10101;
	strcpy(stu_1.name,"fangfang");//使用字符串复制函数给stu_1.name赋值 
	stu_1.sex='M';
	stu_1.score=100;
	printf("No:%ld\nname:%s\nsex;%c\nscore:%5.1f\n",stu_1.num,stu_1.name,stu_1.sex,stu_1.score);
	printf("No:%ld\nname:%s\nsex;%c\nscore:%5.1f\n",(*p).num,(*p).name,(*p).sex,(*p).score);	  //使用两种方式输出学生信息 
	return 0;
}
如果p指向一个结构体变量stu,以下三种用法等价
(1)stu.成员名  如 stu.num
(2)(*p).成员名  如 (*p).num 
(3)p->成员名  如 p->num

 2、指向结构体数组的指针

 例:有三个学生信息,存放在结构体数组中,使用指向结构体数组的指针输出学生信息 
#include <stdio.h>
#include <stdlib.h>

struct Student
	{
		int num;
		char name[20];
		char sex;
		int age;
	 } ;
	 
struct Student stu[3]={{10101,"Li",'M',18},{10102,"Fang",'M',21},{10103,"Wang",'F',20}}; //定义结构体数组并初始化 

int main()
{
	struct Student *p;
	printf("NO.   Name                sex age\n");
	for(p=stu;p<stu+3;p++)
	{
		printf("%-6d%-20s%2c%4d\n",p->num,p->name,p->sex,p->age);//输出结果 
	}
	return 0;
}

3、用结构体变量和结构体变量的指针作函数参数

 将一个结构体变量的值传递给另一个函数,有3种方法:

(1)用结构体变量成员作参数

(2)用结构体变量作实参

(3)用指向结构变量(或数组元素)的指针作实参,将结构体变量(或数组元素)的地址传给形参

#include <stdio.h>
#include <stdlib.h> 

struct Student 
{
	int num;
	... 
 } 

int main()
{
	struct Student max(struct Student stu[]);
	struct Student stu[N],*p=stu;
	max(p);
}

struct Student max(struct Student stu[])
{
	......
	return stu[m];
}

四、用指针处理链表

1、什么是链表

 链表是一种重要的数据结构,能够进行动态的存储分配,根据需要开辟内存空间,相比于事先定义长度的数组,应用更为灵活。

链表有一个“头指针”变量,如上图,以head表示,其存放一个地址,指向第一个元素,链表中,每一个元素称为一个“结点”,每个节点包括两个部分:(1)用户需要用到的实际数据;

(2)下一个结点的地址。当指向最后一个元素后,该元素不在指向其他元素,称之为“表尾”,它的地址部分存放一个“NULL”(空地址),链表到此结束。由上图知,链表中各个元素是不连续的,因而若无“头指针”,整个链表无法访问。创建链表使用结构体变量最合适。设计的结构体类型如下:

struct Student
{
	int num;
	float score;
	struct Student *next;//next 是指针变量,指向结构体变量 
}; 

 2、建立简单的静态链表

例:创建一个由3个学生数据的结点组成的链表,并输出各结点中的数据 
#include <stdio.h>
#include <stdlib.h> 
 
struct Student
{
	int num;
	float score;
	struct Student *next;//next 是指针变量,指向结构体变量 
}; 

int main()
{
	struct Student a,b,c,*head,*p;//定义3个结构体变量作为链表结点 
	a.num=10101;a.score=89.5;  //初始化结点a,b,c 
	b.num=10102;b.score=90;
	c.num=10103;c.score=91;
	head=&a;//将a地址赋给头指针 
	a.next=&b;//将b的起始地址赋给a结点的next成员 
	b.next=&c;//将c的起始地址赋给b结点的next成员 
	c.next=NULL;//c结点的next成员不存放其他结点地址 
	p=head;//使得p指向a结点 
	do
	{
		printf("%ld%5.1f\n",p->num,p->score);
		p=p->next;
	}while(p!=NULL);//输出链表 
	return 0;
}

3、建立动态链表

前面静态链表是在已经创建好结点后进行链表输出,而动态链表是指程序从无到有建立一个链表,即一个一个的开辟结点和输入结点数据,并建立起前后相链的关系。下面通过一个例子来展示。

例:写一个函数建立有3名学生数据的单向动态链表 
#include <stdio.h>
#include <stdlib.h> 
#define LEN sizeof(struct Student)

struct Student
{
	long num;
	float score;
	struct Student *next;//next 是指针变量,指向结构体变量 
}; 

int n;

struct Student *creat(void) //定义返回一个指向链表表头的指针 
{
	struct Student *head;
	struct Student *p1,*p2;
	n=0;
	p1=p2=(struct Student *)malloc(LEN);//先开辟一个新结点,p1,p2指向该结点 
	scanf("%ld,%f",&p1->num,&p1->score);//输入结点数据 
	head=NULL;//初始化表头 
	while(p1->num!=0)//当第一个结点输入数据不为零时进入循环 
	{
		n=n+1; 
		if(n==1)head=p1; //若n等于1,则为第一次进入,将第一个结点的地址赋给头指针 
		else p2->next=p1;//若n不为1,则 将p2的next成员指向p1所指向的结点 
		p2=p1;
		p1=(struct Student *)malloc(LEN);//开辟新结点后,将p1指向新结点 
		scanf("%ld,%f",&p1->num,&p1->score);//输入新结点的学生数据 
	
	}
	p2->next=NULL//当p1->num等于0时,代表输入结束,则将p2指向空地址 
	return(head);//返回链表表头 
 } 

int main()
{
	struct Student *pt;
	pt=creat();//调用函数 
	printf("\nnum:%ld\nscore:%5.1f\n",pt->num,pt->score);//输出第一个结点学生数据 
	return 0;
}

 4、输出链表

写一个函数用于输出整个链表

struct Student
{
	long num;
	float score;
	struct Student *next;//next 是指针变量,指向结构体变量 
}; 

void print(struct Student *head)//定义print函数
{
	struct Student *p;
	printf("\nNow,These %d records are:\n",n);
	p=head;使p指向第一个结点
	if(head!=NULL)//若不是空表
	{
		do
		{
			printf("%ld%5.1f\n",p->num,p->score);//输出结点存储的数据
			p=p->next;//指向下一个结点
		}while(p!=NULL);
	}
}

 五、共用体类型

1、什么是共用体类型

共用体类型指的是同一段内存单元可以存放不同类型的变量。存储的变量虽然字节可能不同,但起始地址均相同,因而后一个数据会覆盖前面数据。

定义共用体类型变量的一般形式为:

union 共用体名

{

        成员表列

}变量表列;

当然,和结构体类似,共用体变量还有其他定义形式是

union Date
{
	int i;
	char ch;
	float f;
}a,b,c;
或
union Date
{
	int i;
	char ch;
	float f;
};
union Date a,b,c;
或
union 
{
	int i;
	char ch;
	float f;
}a,b,c;

 共用体变量和结构体变量的不同:

        结构体变量所占用的内存长度是各成员占的内存长度之和,每个成员均有自己的内存空间;而共用体变量所占的内存长度等于最长的成员的长度

 2、引用共用体变量的方式

共用体变量的引用方式和结构体的相同:

a.i;

a.ch;

a.f;

 3、共用体类型数据的特点

(1)同一个内存段可以用来存放几种不同类型的成员,但是在每一个瞬间只能存放其中一个成员。

#include <stdio.h>
#include <stdlib.h> 

union Date
{
	int i;
	char ch;
	float f;
}a;



int main()
{
	a.i=97;
	printf("%d\n",a.i); // 输出a.i,为97
	printf("%c\n",a.ch);//97对应字符a,则输出a.ch时,输出字符'a'
	printf("%f\n",a.f);//数值为0,则输出0.000000
	return 0;
}

 (2)可以对共用体进行初始化,但初始化表中只能有一个变量 

union Data
{
	int i;
	char ch;
	float f;
}a={1,'a',1.5};//不能初始化三个成员 

union Data a={16};//对第一个成员初始化 
union Data a={.ch='j'};//允许对指定成员进行初始化 

 (3)给共用体一个成员赋值后,该数据会覆盖上一个数据

六、使用枚举类型

若一个变量只有几种可能存在的值,则可定义为枚举类型,所谓枚举,就是指把所有可能存在的值均列出来,变量的值只能在这范围中。

声明枚举类型的一般形式为:

enum [枚举名]{枚举元素列表} 

enum Weekday {sun,mon,tue,wed,thu,fri,sat};
enum Weekday workday,weekend; 

 每一个枚举元素均代表一个整数,C语言编译时按定义时的顺序默认它们的值为0,1,2,3,,,当然,也可以在定义枚举类型时显示地指定数值,如enum Weekday {sun=0,mon=7,tue,wed,thu,fri,sat};之后顺序加1,sat为12。

七、用typedef声明新类型名

        除了可以直接使用C提供的标准类型名(如int,char,float,double和long等)和程序编写者自己声明地结构体,共用体,枚举类型外,还可以使用typedef指定新的类型名来代替已有的类型名。有以下两种情况:  

1、简单地用一个新的类型名代替原有的类型名

typedef int Integer;
typedef float Real;
......

2、命名一个简单的类型名代替复杂的类型表示方法

(1)命名一个新的类型名代表结构体类型

typedef struct
{
	int month;
	int day;
	int year;
}Date;

Date birthday;
Date *p;

 (2)命名一个新的类型名代表数组类型

typedef int Num[100];//声明Num为整形数组类型名 
Num a;//定义a为整型数组名,有100个元素 

(3)命名一个新的类型名代表指针类型 

typedef char * String;//声明String为字符指针类型 
String p,s[10];//定义p为字符指针变量,s为字符指针数组 

 (4)命名一个新的类型名代表指向函数的指针类型

typedef int(*pointer)()//声明pointer为指向函数的指针类型,该函数返回整型值 
pointer p1,p2;//p1,p2为pointer类型指针变量 

归纳:

(1)先按定义变量方法写出定义体(如:int i;)

(2)将变量名换成新类型名(如:将i换成Count)

(3)在最前面加typedef(如:typedef int Count)

(4)然后用新类型名去定义变量。


本文章总结于谭浩强的C语言程序设计(第五版),并加上了自己的一些理解。

欢迎大家提出问题并指正~

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
#include"stdio.h" #include"stdlib.h" #define NULL 0 struct student { long num; char name[20]; int score[6]; struct student *next; }; void show() { printf("\nthere is a cataloge as follow.\n"); printf("***************************************\n"); printf("* *\n"); printf("* 1. create *\n"); printf("* 2. Insert *\n"); printf("* 3. print *\n"); printf("* 4. delete *\n"); printf("* 5. modify *\n"); printf("* 6. save_to_file *\n"); printf("* 7. lode from file *\n"); printf("* 8. exit *\n"); printf("***************************************\n"); printf("please input 1--8 to choice what you want:\n"); } struct student *create() { struct student *head,*p,*last; int i; int temp2; char name[20]; p=head=(struct student *)malloc(sizeof(struct student)); head->next=NULL; last=p; while(1) { last->next=p; last=p; p=(struct student *)malloc(sizeof(struct student)); /*last->next=p; last=p;*/ p->next=NULL; printf("number:"); scanf("%ld",&p->num); if(p->num==0)break; getchar(); printf("name:"); scanf("%s",p->name); printf("score:"); for(i=0;i<6;i++) { scanf("%d",&temp2); p->score[i]=temp2; } printf("next student's information.\n"); } free(p); return head; } void Insert(struct student *head) { struct student *p,*q; int score; long num; int i; printf("\nEnter the student's information you want to insert.\n"); printf("number:"); scanf("%ld",&num); q->num=num; getchar(); printf("name:"); scanf("%s",q->name); printf("score:(chinese,math,english,biology,physics,chemistry)\n"); for(i=0;i<6;i++) { scanf("%d",&score); q->score[i]=score; } q->next=NULL; p=head; while(p->next->num<q->num&&p->next!=NULL) p=p->next; q->next=p->next; p->next=q; if(p->next==NULL) p->next=q; } void delete(struct student *head) { struct student *p,*q; long num; printf("enter the student's information you want to delete.\n"); printf("number:"); scanf("%ld",&num); getchar(); p=head; while(p->next!=NULL&&p->next->num!=num) p=p->next; q=p->next; p->next=p->next->next; free(q); } void print(struct student *head) { struct student *p; int i; p=head->next; if(p==NULL) { printf("\nthere is no information.\n"); exit(0); } printf("\nnumber\tnamme\tchinese\tmath\tenglish\tbiology\tphysics\tchemistry\n"); while(p!=NULL) { printf("\n%ld\t%s",p->num,p->name); for(i=0;i<6;i++) printf("\t%d",p->score[i]); p=p->next; } } void modify(struct student *head) { struct student *p; int choice,i; long num; char name[20]; int score[6]; printf("\nEnter what student's information you want to modify.\n"); printf("number:"); scanf("%ld",&num); getchar(); printf("\nname:"); scanf("%s",name); printf("\n"); p=head->next; while(p->num!=num&&p->name[20]!=name[20]&&p!=NULL) p=p->next; printf("\nplease choice what you want to modify:1-number 2-name 3-score.\n"); scanf("%d",&choice); switch(choice) { case 1:printf("\nEnter the true number:"); scanf("%ld",&num); p->num=num; break; case 2:printf("\nEnter the true name:"); scanf("%s",p->name); break; case 3:printf("\nEnter the right score:"); for(i=0;i<6;i++) { scanf("%d",&score[i]); p->score[i]=score[i]; } break; } } void save_in(struct student *head) { struct student *p; FILE *fp; char file_name[30]; printf("please enter the file name you want to save.\n"); scanf("%s",file_name); printf("save to file:%s",file_name); if((fp=fopen(file_name,"w"))==NULL) { printf("can't open the file.\n"); exit(0); } p=head; while(p->next!=NULL) { fwrite((void*)p->next,sizeof(struct student),1,fp); p=p->next; } fclose(fp); } struct student *load_from_file() { struct student *head,*p,*last; FILE *fp; char file_name[30]; head=(struct student *)malloc(sizeof(struct student)); last=head; head->next=NULL; printf("please enter the file name you want to save.\n"); scanf("%s",file_name); printf("save to file:%s",file_name); if((fp=fopen(file_name,"r"))==NULL) { printf("can't open the file.\n"); exit(0); } p=(struct student *)malloc(sizeof(struct student)); p->next=NULL; while(fp=fread((void *)p,sizeof(struct student),1,fp)==1) { last->next=p; last=p; p=(struct student *)malloc(sizeof(struct student)); p->next=NULL; } free(p); fclose(fp); return head; } void main() { struct student *la; int choice; /*char Yes_No;*/ la=(struct student *)malloc(sizeof(struct student)); la->next=NULL; while(1) { show(); scanf("%d",&choice); switch(choice) { case 1:la=create(); break; case 2:Insert(la); break; case 3:print(la); break; case 4:delete(la); break; case 5:modify(la); break; case 6:save_in(la); break; case 7:la=load_from_file(); break; case 8:exit(0); } } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IC 1396

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值