七、结构体

一、结构体的定义和使用

(一)定义:

1.一般格式:

不同数据类型组成组合型数据结构,例如:学生的姓名,年龄,分数,性别
在这里插入图片描述
注意:结构体在声明时不会分配内存空间,只有在进行结构体变量时才会分配,结构体声明时不能赋值

2.结构体的声明:

struct student{//struct是关键字,此结构体类型为struct student 
	char name[50];
	int age;
	int score;
};//注意分号

3.结构体变量的三种定义:

struct student{
	char name[50];
	int age;
	int score;
};
 
int main(){
	
	//1.先声明结构体,后定义结构体变量
	struct student stu;//定义了一个结构体变量 
	
	return 0;
}

//2.在声明类型的同时定义变量 
struct Date{
	int year;
	int month;
	int day
}student1,stuent2;//定义了2个结构体变量 

//3.不使用类型,直接定义结构体变量
struct {
	int id;
	char dept[];
}emp1,emp2; 

第一种方式:比较灵活,推荐使用;第二种方式:不灵活,不推荐使用,第三种方式:不推荐使用
在这里插入图片描述### 4.结构体的初始化:

//结构体变量只有在定义时才可以初始化 
struct student stu = {"zhangsan",20,90};//正确
stu = {"lisi",20,80};//报错,结构体类似于数组,是常量,只有在定义时可以初始化

(二)使用:

1.如果是普通变量,使用.运算符:

struct student{
	char name[50];
	int age;
	int score;
};
 
int main(){
	struct student stu = {"zhangsan",20,90};
	
	//注意name是数组,赋值使用拷贝,如下:
	strcpy(stu.name,"lisi"); 
	stu.age = 15;
	stu.score = 70; 
	printf("%s %d %d",stu.name,stu.age,stu.score);
	return 0;
}

2.如果是指针变量,使用->运算符:

struct student{
	char name[50];
	int age;
	int score;
};
 
int main(){
	struct student* p; 
	strcpy(p -> name,"wangwu");
	p -> age = 15;
	p -> score = 90;	
	printf("%s %d %d",p->name,p->age,p->score);
	
	return 0;
}

二、结构体数组

(一)定义:

在这里插入图片描述

(二)应用:

struct student{
	char name[50];
	int age;
	int score;
};
 
int main(){
	struct student stu[5] = {
		{"zhangsan",20,90},
		{"lisi",18,90},
		{"wangwu",20,90},
		{"maqi",20,90},
		{"dongdong",17,90},
	};
	
	int average;//平均分 
	int sum = 0; //总成绩 
	for(int i=0;i<5;i++){
		sum = sum + stu[i].score; 
	}
	average = sum / 5;
	printf("平均成绩为:%d\n",average);
	
	return 0;
}

(三)结构体的嵌套:

struct person{
	char name[50];
	char sex;
};
struct student{
	int id;
	struct person p;//嵌套 
};
 
int main(){
	struct student stu;
	stu.id = 100;
	strcpy(stu.p.name,"lisi");
	stu.p.sex = 'M';
	printf("%d %s %c\n",stu.id,stu.p.name,stu.p.sex); 
	return 0;
}

通过指针定义同理stu->p->age,也可以:stu->p.name

三、结构体指针

(一)定义:

在这里插入图片描述

(二)指向结构体的指针:

struct student{
	char name[50];
	int id;
	char sex;
	int score;
};
int main(){
	struct student stu;
	struct student* p;
	p = &stu;//即:p为指向结构体变量的指针 
	stu.id = 123;
	strcpy(stu.name,"zhangsan");
	stu.score = 90;
	stu.sex = 'F';
	printf("%d %s %d %c\n",stu.id,stu.name,stu.score,stu.sex);//通过结构体访问
	printf("%d %s %d %c\n",p->id,p->name,p->score,p->sex); 
	return 0;
}

(三)指向结构体数组的指针:

struct student{
	char name[50];
	int id;
	char sex;
	int score;
};

int main(){
	struct student stu[3] = {
		{"zhangsan",123,'F',90},//name赋值不需要字符拷贝函数 
		{"lisi",234,'F',90},
		{"wangwu",345,'M',90}
	};
	struct student* p;

	for(p = stu;p < stu + 3;p ++){//p++移动元素 p = stu:指针指向结构体数组 
		printf("%s %d %c %d\n",p->name,p->id,p->sex,p->score);	
	}
	
	return 0;
}

(四)结构体普通变量作为函数参数:

struct student{
	char name[50];
	int age;
};

int main(){
	struct student stu = {0};//初始化为0
	set_student(stu);
	printf("name = %s age = %d\n",stu.name,stu.age); 
	return 0;
}

//给结构体赋值 
void set_student(struct student tem){
	strcpy(tem.name,"zhangsan");
	tem.age = 20;
} 

在这里插入图片描述为什么输出结果不是name = zhangsan age = 20?
分析:
在set_student(stu);中,采用的是值传递,值传递不能修改实参的值,故而如此

修改如下:

struct student{
	char name[50];
	int age;
};

int main(){
	struct student stu = {0};//初始化为0
	set_student(&stu);//添加取地址符 
	printf("name = %s age = %d\n",stu.name,stu.age);  
	return 0;
}

//给结构体赋值 
void set_student(struct student* tem){//上文取地址,则此处形参为指针类型 
	strcpy(tem->name,"zhangsan");//由.改为-> 
	tem->age = 20;//由.改为->
} 

在这里插入图片描述

(五)结构体指针变量作为函数参数:

struct student{
	char name[50];
	int age;
};

int main(){
	struct student stu = {0};//初始化为0 
	struct student* p;
	p = &stu; 
	set_student(p);
	printf("name = %s age = %d\n",p->name,p->age);  
	return 0;
}

//给结构体赋值 
void set_student(struct student* tem){
	strcpy(tem->name,"zhangsan");
	tem->age = 20;//由.改为->
} 

在这里插入图片描述

(六)使用const修饰结构体指针形参变量:

struct student{
	char name[50];
	int age;
};

int main(){
	struct student stu;
	show (&stu);
	show2(&stu);
	return 0;
}

void show(struct student* const stu){
	//stu = NULL;//error 当const修饰时,stu是常量,不能修改
	//*stu = NULL;//也是错误 
	
	stu->age = 10;//正确 
} 

void show2(const struct student* stu){
	stu = NULL;
	//*stu = NULL;//error
	//stu->age = 10; //error
} 

四、链表

(一)概念:

在这里插入图片描述

(二)建立静态链表:

//建立三个学生的链表 
struct Node{
	int num;
	struct Node* next;
};

struct student{
	float score;
	struct student* next;//下一节点指针 
};

int main(){
	struct student a,b,c,*head,*p;//*head为头指针,*p为遍历(输出)指针 
	//将链表首元素a的地址赋值给head
	head = &a; 
	a.score = 89.5;
	a.next = &b;//a.next是指针,赋值是地址故需要& 
	b.score = 90;
	b.next = &c;
	c.score = 85;
	c.next = NULL;
	p = head;//输出链表
	do{
		printf("score = %.1f	",p->score); 
		p = p->next;
	} while(p != NULL);
	return 0;
} 

![在这里插入图片描述](https://img-blog.csdnimg.cn/8bce98b76bc04f7fbb86e016971d8955.png#pic_center

五、共用体、枚举、typedef

(一)共用体:

1.概念:

在这里插入图片描述

2.union的大小是内部最大的成员大小:

union test{
	unsigned int a;
	unsigned short b;
	unsigned long long c;
};
int main(){
	printf("union test的大小:%d\n",sizeof(union test));//union test:数据类型,与结构体相似
	printf("long long的大小:%d\n",sizeof(long long));
	return 0;
}

在这里插入图片描述

3.共用体共用同一个内存段,每个成员的地址一样:

union test{
	unsigned int a;
	unsigned short b;
	unsigned long long c;
};

int main(){
	union test t;
	printf("%p %p %p\n",&t.a,&t.b,&t.c);
	return 0;
}

在这里插入图片描述因为每个成员地址一样,给某个成员赋值,会影响到其他成员:

union test{
	unsigned int a;
	unsigned short b;
	unsigned long long c;
};

int main(){
	union test t;
	t.a = 0x123;
	printf("%x %x %x\n",t.a,t.b,t.c);//%x:十六位输出 
	return 0;
}

在这里插入图片描述

(二)枚举:

1.概念:

在这里插入图片描述

2.若第一个成员未赋值,则系统默认赋值0,依次递增:

enum weekday{
	sun,mon,tue,thu,fri,sat
};

int main(){
	enum weekday a,b,c;
	a = sun;
	b = mon;
	c = tue;
	printf("a = %d b = %d c = %d\n",a,b,c);
	return 0;
}

在这里插入图片描述

3.枚举练习:

enum flag{
	true,false
};


int main(){
	enum flag f;
	f = true;
	if(f == 1){
		printf("真!");
	}else{
		printf("假!");//输出,因为第一个类型默认为0 
	}
	
	return 0;
}

(三)typedef:

1.概念:

在这里插入图片描述

2.typedef其实就是起别名:

typedef int int64;
int64 a = 10; //等价于int a = 10 
printf("%d\n",a);

3.typedef给结构体取别名:

typedef struct student{
	int id;
	double score;
	int num;	
}student;//给结构体取的别名 
int main(){

	student stu;//不再需要struct student stu,用别名代替 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值