Autoleader控制组-C语言结构体(复合类型)学习笔记

1.结构体概述

2.结构体定义和初始化

3.结构体数组

4.结构体套结构体

5.结构体赋值

6.结构体和指针

结构体指针

结构体套指针

const修饰的结构体指针变量

7.结构体作为函数形参

8.共用体(联合体)

共用体概述

共用体赋值

共用体判断大小端

9.枚举实现bool类型

bool

typedef

一.结构体概述
结构体:将多个相同或不相同类型的数据存放在一块连续的内存空间中。
二.结构体定义初始化

定义一个结构体数据类型

关键字 struct 代表这是一个结构体类型
stu 是这个结构体的名字
整个结构体的类型是 struct stu

struct stu//定义一个结构体类型,用来保存学生的信息
{
//结构体类型struct stu中用三个成员 id age name,每个成员可以是任意类型
	int id;
	int age;
	char name[128];
};//这里一定要加分号

注意
定义结构体struct stu时,它只是一个类型,一个模板,没有空间,不能在{}里对成员赋值

结构体变量的定义有三种

//第一种
struct stu
{
    int id;
	int age;
	char name[128];
};
struct stu Mike;//这种用得比较多
//第二种
struct stu
{
    int id;
	int age;
	char name[128];
}Mike,Bob;
//第三种
struct //没有结构体名,这种用得比较少,因为只能在这里定义结构体变量,下次再定义定义不了
{
    int id;
	int age;
	char name[128];
}Mike,Bob;

定义结构体类型时是没有空间的,但是当我们定义了结构体变量时,这个变量就有了空间,可以对这个结构体变量的成员初始化

struct stu
{
    int id;
	int age;
	char name[128];
} a;
struct stu b;
int main()
{
	struct stu d={1,20,"ljm"};//对结构体变量b中的三个成员赋值
	struct stu d={.age=20};//给部分成员初始化,其他成员内容为0
	return 0;
}

如何给结构体成员赋值(如何操作结构体成员)

如果通过结构体变量操作结构体成员,使用点域.操作
如果通过结构体地址操作结构体成员,使用->

点域操作:

struct stu
{
    int id;
	int age;
	char name[128];
} ;
int main()
{
	struct stu d;
	d.id=2;
	d.age=20;
	//d.name="world";//erro name是一个常量,不能赋值,要用字符串的拷贝
	strcpy(d.name,"world");
	printf("%d %d %s\n",d.id,d.age,d.name);
	return 0;
}

指向操作:

(&d)->id=3;
(&d)->age=20;
strcpy((&d)->name,"world");//这里&b一定要加括号,因为->优先级更高
printf("%d %d %s\n",(&d)->id,(&d)->age,(&d)->name);

三.结构体数组
是一个数组,数组的每一个元素都是结构体。比如定义一个结构体变量struct stu d 时,只有一个学生的信息,但如果我定义一个结构体数组,那么就可以存放多个学生信息。

//定义一个结构体数组,结构体数组有五个元素,每个元素是 struct stu 类型
struct stu num[5]={{1,20,"Lucy"},{2,20,"Mike"},{3,20,"Bob"},{4,20,"Jame"},{5,20,"Mac"},};
for(int i=0;i<sizeof(num)/sizeof(num[0]);i++){
	printf("%d %d %s\n",num[i].id,num[i].age,num[i].name);
}

四.结构体套结构体
结构体里有一部分成员也是结构体

struct stu
{
    int id;
	int age;
	char name[128];
} ;
//下面我还想定义一个结构体 struct stu_heima,这个结构体中的成员会有一部分跟 struct stu 的成员一样,那么我就把 struct stu 套在 struct stu_heima 里
 struct stu_heima
{
	struct stu s;
	char subject[128];
};

那么怎么对结构体里的结构体赋值呢

int main()
{
	struct stu_heima h;
	h.s.id=1;
	h.s.age=20;
	strcpy(h.s.name,"ljm");
	strcpy(h.subject,"c++");
	printf("%d %d %s\n",h.s.id,h.s.age,h.s.name,h.subject);
}

五.结构体赋值

int main()
{
	struct stu a={1,34,"bob"};
	struct stu b;
	b=a;//这里的内核其实是把a拷贝到b,相同类型的变量是可以相互赋值的
	return 0;
}

六.结构体和指针

结构体指针
结构体传参时因为结构体本身内存比较大,所以我们一般传结构体的地址进去,所以要用结构体指针

int main()
{
	struct stu *p;//定义一个指针,这个指针类型是结构体
	//需要注意的是,p是结构体地址,所以通过p操作结构体内成员时要用指向
	p->id=3;
	p->age=20;
	strcpy(p->name,"world");
	printf("%d %d %s\n",p->id,p->age,p->name);
	return 0;
}

这个代码有个非常大的问题,这里的p是野指针,是没有明确空间的
所以当我们使用指针时一定要避免出现野指针
这里有两个解决方案

1.先定义一个结构体变量a,再把a的地址给p
2.用malloc向系统申请空间

1.这种比较少用

struct stu a;
struct stu *p=&a;

2.这种比较常用

struct stu *p=malloc(sizeof(struct stu));

结构体套指针
结构体成员中有指针

strut tea{
	int id;
	char *p;
};
int main()
{
	strut tea *tmp=(strut tea *)malloc(sizeof(strut tea));//这里要记得类型转换,malloc出来的是void*
	tmp->id=100;
	tmp->p="hello";//这是OK的,“”表示取hello的地址,然后把这个地址给p,所以p就指向了hello,p不是野指针
	//strcpy(tmp->p,"hello");(err:这里p就是野指针了,这里是表示把hello拷贝到p所指向的空间上,但p所指向的空间是随意的,所以如果要用这个,得先malloc一个空间给p:tmp->p=(char*)malloc(128))
	printf("%s\n",tmp->p);
	return 0;
}

用了malloc一定要记得free

结构体指针加结构体套指针怎么操作成员

strut t
{
int a;
};
strut tea{
	int id;
	char *p;
	strut t *b;
};
int main()
{
	strut tea *tmp=(strut tea *)malloc(sizeof(strut tea));
	tmp->id=100;
	tmp->p="hello";//也可以写成 tmp->p=(char*)malloc(128));strcpy(tmp->p,"hello")
	tmp->b=(strut t*)malloc(sizeof(strut t));//这里的b也要记得先malloc再对a赋值,不然又会出现野指针
	tmp->b->a=200;
	
	//free(tmp->p);
	free(tmp->b);
	free(tmp);
	
	return 0;
}

用了几次malloc就要free几次,而且free一定要注意顺序,要从里到外释放

const修饰的结构体指针变量(跟const修饰指针差不多)

struct c13
{
	int id;
	char name[128];
};
int main()
{
	struct c13 a;
	const c13 const *p=&a;//const修饰的是*,不能通过p修改p指向的那块空间
	const c13 *const p=&b;//const修饰的是指针变量p,不能修改p本身的内容(指向)
	return 0;
}

七.结构体作函数形参

一般是传结构体的地址,即结构体指针,跟指针作函数形参差不多,需要注意的是结构体数组作函数的形参

struct c13//先定义一个结构体
{
	int id;
	char name[128]
};
void set_stu(struct c13 *p,int n)//定义一个函数,传入一个结构体指针,因为后面要传入的是一个结构体数组,所以还要一个参数来放数组的大小
{
	char buff[128]="";
	for(int i=0;i<n;i++){
		//(*(p+i)).id=i+10;
		p[i].id=i+10;
		sprintf(buf,"%d%d%d",i,i,i);
		strcpy(p[i].name,buf);
	}
}
int main()
{
	struct c13 num[5];//定义一个结构体数组
	memset(num,0,sizeof(num)/sizeof(num[0]));//初始化函数,把num里面的每个元素初始化为0
	set_num(num,sizeof(num)/sizeof(num[0]));//把结构体数组数组传入自定义的函数,因为数组名本身就是地址,所以直接用num
	for(int i=0;i<sizeof(num)/sizeof(num[0]);i++){
		printf("%d %s\n",num[i].id,num[i].name);
	}
	return 0;
}

八.共用体(联合体)

联合体 union 是一个能够在同一个存储空间存储不同数据类型的类型
联合体所占的内存长度等于其最长成员的长度倍数
同一内存段可以用来存放几种不同类型的成员,但每一瞬间只有一种起作用;
共用体变量中起作用的是最后一次存放的成员,在存入一个新的成员后原有的成员值会被覆盖
共用体变量的地址和它各成员的地址都是同一地址

共用体定义赋值

union my
{
	char a;
	short b;
	int c;
};//共用体的大小是4,因为成员中最大的是int
int main()
{
	union my tmp;
	tmp.a=0x01;//这个时候共用体的四个字节里的最低位放了01
	tmp.c=0x01020304;//这个时候共用体的四个字节放下了01020304,并把a覆盖了
	tmp.b=0x0a0b;//这个时候共用体的四个字节低两位放下了0a0b,并把c的低两位0304覆盖了
	//最后tmp是0b0a0201(从低位到高位)
	printf("%x\n",tmp.b);//因为b是两个字节,所以只会取两个字节,输出0a0b
	printf("%x\n",tmp.a);//取一个字节,输出0b
	printf("%x\n",tmp.c);//取四个字节,输出01020a0b
	return 0;
}

共用体与结构体的区别
共用体是所有成员共用一个内存空间,结构体成员都有自己的内存空间

共用体判断大小端

关于大小端
小端:低位存低地址,高位存高地址
一般用于大型的服务器,网络上的数据
大端:低位存高地址,高位存低地址
一般用于小型计算机
小端存小端取,大端存大端取

union jg
{
	char a;
	short b;
};
int main()
{
	union jg tmp;
	tmp.b=0x0102;
	if(tmp.buf[0]==0x01){
		printf("大端\n");
	}
	else{
		printf("小端\n");
	}
	return 0;
}

九.枚举实现bool类型

枚举:将变量的值一一列举出来,变量的值只限于列举出来的值的范围内
enum 枚举名
{
枚举值表;
};
在枚举值表中应列出所有可用值,也称为枚举元素
枚举值是常量,不能在程序中用赋值语句再对它赋值,也没有空间
枚举元素本身由系统定义了一个表示序号的数值从0开始顺序定义为0,1,2…

/*define SUN 0
define RAIN 1
define SNOW 2      这样一个一个定义宏太麻烦了,所以我们可以用枚举*/
enum weather{SUN,RAIN,SNOW};//系统默认SUM==0,RAIN==1,SNOW==2
//也可以自己改序号:enum weather{SUN,RAIN=5,SNOW} SUM==0,RAIN==5,SNOW==6
int main()
{
	enum weather tmp=SNOW;//也可以定义一个 enum weather 变量
	int a=0;
	scanf("%d",&a);
	if(a==SUN){
		printf("sleep\n");
	}else if(a==RAIN){
		printf("music\n");
	}else if(a==SNOW){//a==tmp
		printf("game\n");
	}
	return 0;

}

可以利用枚举写一个自己的bool类型
关于bool类型:来自头文件<stdbool.h>里面定义了false=0,true=1
关于typedef:用来给类型取别名。用法:typedef 原类型 新类型

#include<stdbool.h>
int main()
{
	bool a;
	a=false;
	printf("%d\n",a);//输出的是0
	return 0;
}
enum BOOL {false,true};
typedef enum BOOL bool;
int main()
{
	bool a;
	a=false;
	printf("%d\n",a);
	return 0;
}

结构体也可以用typedef定义别名,就不用每次定义结构体类型都写得太麻烦

struct stu
{
	int id;
	int age;
};
typedef struct stu TT;
int main()
{
	TT tmp;
	tmp.id=10;
	tmp.age=20;
	return 0;
}

typedef和define的区别
(define也可以用来取别名)

#define CHAR char*//
typedef char* CHAR32;
int main()
{
	CHAR x,y;//char *x,y
	CHAR32 j,k;//char *x,*y
	printf("%d %d\n",sizeof(x),sizeof(y));//4 1
	printf("%d %d\n",sizeof(j),sizeof(k));//4 4
	return 0;
}

结构体内容就到这里,我们下篇文章见。
笔记内容来自网课:在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值