C语言结构体,链表,共用体,枚举类型

定义结构体struct

一个个体的多个属性,是一系列数据的集合。

struct Student 结构体名//先声明结构体类型
{
int ID;
char nike name;
float height;
int  grades[10];
struct Cake;//
}student1,student2;//别忘了最后的分号,定义这个类型的两个变量。
struct Student student3;//另一个定义方式

和函数类似,像一张图纸,所以要在其中存放具体数据。区分结构体类型(Student)和结构体变量(student)。只能对变量进行赋值,存取,运算。结构体内的成员名字可以和外面的一样,不代表同一个对象(和函数那边的好像)。

初始化结构体变量

struct Student student3={12312817,"CAKE",32.342,{99,75}};//一开始就初始化

student3=(struct stu){12312817,"CAKE",32.342,{99,75}};//后来初始化

结构体成员的访问和.运算符

student.ID=12312817;//用来指定结构体内部成员
ID=12312817;//错误,无ID定义
wusong.number--;
scanf("%s %s",&wusong.weapon,name);//各种操作都可以。如果结构体里面的是char[20],不用&
printf("%s",wusong.nickname);

同一结构体里的成员可以整体赋值。student1=student2;

但是这个不能整体输出!

结构体的嵌套

结构体的成员本身可以属于某种结构体类型。

struct Date//第一个结构体
{
int year;
int month;
int day;
};
struct Person//第二个结构体
{
char name[20];
struct Date birthday;第二个结构体里面的结构体。
};

结构体数组定义和使用

一般形式:第一种(声明时):struct 结构体名{成员列表}数组名[数组长度];

第二种(声明后):struct 结构体名 数组名[长度]

初始化:={初值列表}

struct Person
{
    char name[20];
    int count;
} leader[3] = {{"a", 0}, {"b", 0}, {"b", 0}};
struct Person leader[3]={"a",0,"b",0,"c",0};

学生按照成绩排序,应用结构体数组,排序法,结构体内容的交换。

struct Student {//定义结构体
	int id;
	int score;
};

int main() {
	struct Student stu[5] = {{110, 55}, {111, 56}, {112, 34}, {113, 46}, {114, 64},}, temp;
	int i, j, k, n = 5;
	for (i = 0; i < n - 1; i++) {
		for (j = 0; j < n - 1 - i; j++) {
			if (stu[j].score < stu[j + 1].score) {//和之前的排序几乎一样
				temp = stu[j];//temp结构体用来当中间交换的结构体
				stu[j] = stu[j + 1];
				stu[j + 1] = temp;
			}
		}
	}
	for (k = 0; k < n; k++) {
		printf("%d,%d\n", stu[k].id, stu[k].score);
	}

}

结构体和指针

指向结构体的指针变量指向结构体变量,可以引用结构体数组里的元素。指针类型和结构体类型一致struct Sudent *pt

访问方式:

	struct Student {
		int age;
		char name[20];
	};
	struct Student *p, *pt, stu1 = {5, "sb"}, stu[3] = {{3, "cake"}, {2, "wowoji"}, {8, "jueqi"}};//初始化
	p = &stu1; //指针指向结构体
	pt = stu; //指针指向结构体数组
	stu1.name = (*p).name; //两种表示等价
	stu1.name = p->name;
	for (pt; pt < stu + 3; pt++) { //指向结构体数组的指针怎么使用
		printf("%d,%s\n", pt->age, pt->name);
	}

结构体做函数参数

1传递结构体变量,相当于传值

2传递对应指针!很棒的方法。

3传整个结构体变量(少用,因为开销大)

好处:参数列表变短了。代码扩展度高

应用示例:

input函数,接受结构体数组指针,往多个结构体里输入数据和求学生平均成绩。

max函数,接受结构体数组指针,找成绩最高的学生,并返回对应结构体。

print 函数,接受了整个结构体,输出成绩最高学生的信息。

#include <stdio.h>
#include <stdlib.h>
#define N 3//预处理
//用指向结构体变量的指针作为实参
struct Student { //结构体定义
	int num;
	char name[20];
	float score[3];//前三个要录入
	float aver;
};
void input(struct Student stu[]);
struct Student max(struct Student stu[]);
void print(struct Student stud);//三个函数

int main() {//调用函数

	struct Student stu[N], *p = stu; //指针定义
	input(p);
	print(max(p));
	return 0;

}

void input(struct Student stu[]) {
	int i;
	printf("输入各学生的:学号,姓名,三门课的成绩:\n");
	for (i = 0; i < N; i++) {
		scanf("%d %s %f %f %f", &stu[i].num, &stu[i].name, &stu[i].score[0], &stu[i].score[1], &stu[i].score[2]);
		stu[i].aver = (stu[i].score[0] + stu[i].score[1] + stu[i].score[2]) / 3.0;
	}
}

struct Student max(struct Student stu[]) {
	int i, m = 0;
	for (i = 0; i < N; i++) {
		if (stu[i].aver > stu[m].aver)

			m = i;
	}
	return stu[m];
}

void print(struct Student stud) {
	printf("\n成绩最高的学生是:\n");
	printf("学号:%d,平均成绩:%f\n", stud.num, stud.aver);
}

链表:实现非连续的储存

是一种数据结构,与数组优劣互补。各节点地址不连续,各节点有两个部分(数据,下一结点的地址)。除此之外,还有头指针(起始地址),表尾(指针为NULL)。

优点:     易删改,只需修改元素间关系就行。

                化整为零,不需大段连续空间。

缺点:     访问效率低。

链表与结构体

定义:

struct node{
int num;//数据域
struct node*next;//指针域
}a,b,c;

静态链表链接和输出:

struct node *head,*p;
head=&a;//链接
a.next=&b;
b.next=&c;
c.next=NULL;
p=head;//输出开始,找到链子头
do{
printf("%ld%5.1f\n",p->num,p->score);
p=p->next;//p指向了下一个结点!
}while(p!=NULL);

动态链表的建立(基础版)

pa=(struct Student*)malloc(sizeof(struct Student));
pa->num=10101;pa->score=19;//一个结点的创建,不再依赖于结构体变量的不断声明
pb=(struct Student*)malloc(sizeof(struct Student));
pb->num=10101;pb->score=19;
pc=(struct Student*)malloc(sizeof(struct Student));
pc->num=10101;pc->score=19;//多个结点创建

//链接起来
head=pa;//链接
pa->next=pb;
pb->next=pc;
pc->next=NULL;

复用指针建立链表,动态建立多个结点:

三个指针就能实现多个结点的创建和链接

动态创建链表的函数,返回头指针:

#LEN sizeof(struct Student)

//把这一段当一个创建链表的函数
struct Student *creat(void)
{
struct Student *p1,*p2,*head;//p1指向新结点,p2指向最后一个结点
p1=p2=(struct Student*)malloc(LEN);//开辟第一个结点
scanf("%ld,%f",&p1->num,&p1->score);
head=NULL;
int n=0;
while(p1->num!=0)//学号为0时终止
{n=n+1;
if(n==1)
    head=p1;//找到链头
else
    p2->next=p1;//让结点链接上去
p2=p1;//p2移上去
p1=(struct Student*)malloc(LEN);//开辟新结点
scanf("%ld,%f",&p1->num,&p1->score);
}
p2->next=NULL//结束封底
return (head);
}

链表结点的插入操作

一般情况:结点s插入结点p和下一个结点之间:先让s->next=p->next;再让p->next=s;注意顺序,别让后面的结点丢失。

表头插入:法一:s->next=head;head=s;

                法二(增加头结点:仅仅存放位置信息,使得所有有效结点都有前驱结点):s->next=L->next;L->next=s;这样与一般情况的结构一致。

其中,需要一个循环来找到结点位置。和一个if else判断插入位置。(无头结点)

//找到插入位置  位置:position,结点指针:head,p
p=head;
while(position>=1&&p->next!=NULL)
{
    position--;
    p=p->next;
}

创建带有头结点的链表

Node *head = malloc(sizeof(Node));
head->data = 0; // 头结点的数据域通常设置为0
head->next = NULL; // 头结点的指针域指向NULL

带头结点的有链列表的合并(以后写)//暂时理解困难,先理解插入与删除

struct node*mergeNodes(struct node*L1, struct node *L2)
{
    struct node*p1=L1,*q1=L1->next,*p2=L2,*q2=L2->next;
    while (p2!=NULL)//链表遍历常用方式
    {
        q2=p2->next;//用q2记下p2在L2中的下一个结点
    while (q1!=NULL&&q1->data<p2->data)//为什么这里的是q1!=NULL而不是p1
    {
        p1=q1;q1=q1->next;
    }
//如果已经到达L1表尾,可直接把L2其余部分链接到L1尾部
    if(q1==NULL)
        break;
    p2->next=q1;
    p1->next=p2;
    p1=p2;
    p2=q2;//   p2指向L2的下一个结点
}
    if(q1==NULL)
    {
    p1->next=p2;
    }
return L1;
}

带头结点的链表中删去结点

struct node*removeNode(struct node*L,int value)//给链表与删除的位置
{
    struct node*p,*q;
    p=L;
    q=L->next;
    while(q!=NULL&&q->data!=value)//寻找删除结点中
    {
    p=q;
    q=q->next;
    }
    if(q!=NULL)//哥们找到了,但是要判断是不是超范围了
    {
    p->next=q->next;
}
else{printf("the node is not found!\n")};
free(q);
return L;
}

p->next=p->next->next;(简略)

q=p->next;p->next=q->next;free(q);(干净彻底)

共用体union(别用)

同一段内存存放不同类型的变量。定义方式与结构体一样。理解为:“名字,外号,id”选一个来称呼。

共用体与结构体对比(特点)

相似:先定义后引用。系统仅给共用体变量分配空间。、

不同:结构体变量的大小是各成员之和;共用体是最长成员的长度(共享了内存)。

     初始化方式不同,因为共用体同一时刻只能有一个变量存放。共用体变量初始化只能初始化第一个成员。共用体赋值后,之前的信息被取代。&max=&max.a=&max.b。

枚举类型enum erate(完善中)

形式上像构造类型,实际上是基本类型。如果一个变量只有几种可能的值,可定义为枚举类型。

可以更加自然地表示非数值计算中的数据:数值表示月份,星期之类的数据。

声明:

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

定义方式与结构体类似。枚举变量只能从枚举类型中列出的枚举元素中取值。每个枚举元素代表一个整数,按顺序为0,1,2.。。。。枚举变量可以用来判断比较。

// 定义枚举类型
enum Weekday {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
};
// 使用枚举类型作为函数参数
void printDay(enum Weekday day) {
    switch(day) {
        case Monday:
            printf("Today is Monday\n");
            break;
        case Tuesday:
            printf("Today is Tuesday\n");
            break;
        case Wednesday:
            printf("Today is Wednesday\n");
            break;
        case Thursday:
            printf("Today is Thursday\n");
            break;
        case Friday:
            printf("Today is Friday\n");
            break;
        case Saturday:
            printf("Today is Saturday\n");
            break;
        case Sunday:
            printf("Today is Sunday\n");
            break;
        default:
            printf("Invalid day\n");
            break;
    }
}

int main() {
    int dayInput;//虽然说可以直接给today赋值整数,但是这样更合理
    printf("Enter the day (0-6): ");
    scanf("%d", &dayInput);
    // 检查输入是否在枚举范围内
    if (dayInput < 0 || dayInput > 6) {
        printf("Invalid input\n");
        return 1;
    }
    // 将用户输入的整数转换为枚举类型
    enum Weekday today = (enum Weekday)dayInput;
    // 使用枚举类型作为输出
    printf("The value of today is %d\n", today);

    // 调用函数,将枚举类型作为参数传递
    printDay(today);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值