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;
}
结构体内容就到这里,我们下篇文章见。
笔记内容来自网课: