目录
2 结构体变量的定义也可以与结构体的声明同时,这样就简化了代码。
结构体
结构体就是一些值的结合,这些值成为成员变量,这些变量,可以是不同的类型 。
结构的声明
struct tag
{
member_list;//成员变量
};
结构体变量的几种表达形式
1 结构体变量写在结构体声明的之后
#include"stdio.h"
struct stu
{
char name[20];
int age;
char sex[5];
char id[20];
};
int main()//下面为结构体变量的初始化
{
struct stu ok = { "haha",21,"man","okkk"};
printf("%s %d %s %s" ,ok.name,ok.age,ok.sex,ok.id);
};
2 结构体变量的定义也可以与结构体的声明同时,这样就简化了代码。
#include"stdio.h"
struct stu
{
char name[20];
int age;
char sex[5];
char id[20];
}stu = { "okk",20,"man","ok" };
3 对结构体的成员逐个赋值:
#include"stdio.h"
#include"string.h"
struct stu
{
char name[20];
int age;
char sex[5];
char id[20];
};
int main()//下面为结构体变量的初始化
{
struct stu stu1;
strcpy(stu1.name, "ok");//数组名为常量,不能初始化
stu1.age = 20;
};
4 可以对结构体进行整体赋值:有2种
第一种
#include"stdio.h"
struct stu
{
char name[20];
int age;
char sex[5];
char id[20];
};
int main()
{
struct stu ok = { "haha",21,"man","okkk"};
printf("%s %d %s %s" ,ok.name,ok.age,ok.sex,ok.id);
};
第二种
struct stu
{
char name[20];
int age;
char sex[5];
char id[20];
}stu1;
int main()
{
stu1 = stu { "okkk", 20, "oo", "ooo"};结构体定义在声明同时进行
}
匿名结构体
下面来介绍一下匿名结构体类型顾名思义,就是没有名字的结构体类型。
struct
{
int a;
int b;
float c;
}x;//必须要有这个才能引用,好比一个变量。
匿名结构体只能使用一次,前面如何使用已经说过了,结构声明和结构体定义一起进行。
结构体的自引用
下面来看一下结构体的自引用
struct Node
{
int data;
struct Node next;
};
上图就是表示结构体的自引用比如说一个数组内有1,2,3,4,5。出现1之后,要立马出现2, 这个就是表示结构体的自引用,而上面写的正不正确,运行一下。
程序出现错误,Node表示正在运行,说明文件不断在引用,说明这个引用是错误的。
struct Node
{
int data;
struct Node* next;
};
这个就表示,第一个数字和下一个数字的地址,这样就不会冲突。就不会产生结构体内的不断死循环。
结构内存对齐
#include"stdio.h"
struct S
{
char c;
int a;
char c1;
};
struct S1
{
char c;
char c1;
int a;
};
int main()
{
struct S s = { 0 };
struct S1 s1 = { 0 };
printf("%d\n", sizeof(s1));
printf("%d\n", sizeof(s));
}
为什么不是6和6呢?这就涉及到了一个结构体的内存对齐问题
下面用图表示一下可能会更加好
根据下面的几个点来注意
默认对齐数
#include"stdio.h"
#pragma pack(2)//修改默认对齐数为2//节省2个空间
struct S
{
char c;
int a;
char c1;
};
struct S1
{
char c;
char c1;
int a;
};
int main()
{
struct S s = { 0 };
struct S1 s1 = { 0 };
printf("%d\n", sizeof(s1));
printf("%d\n", sizeof(s));
}
#include"stdio.h"
#include"stddef.h"
struct S
{
char c;
char a;
int c1;
};
int main()
{
printf("%d\n", offsetof(struct S, c));//与原始位置偏移的多少。
printf("%d\n", offsetof(struct S, a));
printf("%d\n", offsetof(struct S, c1));
}
位段
下面先来看一个例子
#include"stdio.h"
struct S
{
int a : 2;
int b : 5;
int c : 10;
int d : 30;
};
int main()
{
struct S s;
printf("%d\n", sizeof(s));可以猜一猜字节会是多少
}
有的小伙伴可能会猜到字节是16。
其实是8,这就涉及到了一个我们本次要说的位段问题。
#include"stdio.h"
struct S
{
char a: 3;
char b: 4;
char c: 5;
char d: 4;
};
int main()
{
struct S s = {0};
s.a = 10;
s.b = 20;
s.c = 3;
s.d = 4;
}
来看下字符的内存分配,我们首先看一下它们总共占了几个字节,a和b占一个字节,c占一个字节,d占一个字节,总共三个字节,分别将他们由10进制,变成2进制,再截取他们的所占的位段。
上图所示就是,所占的内存。
上面就是&s地址所占的内存的大小
分别所占的内存是2 2 3 4
总结
位段的内存分配
位段组成
结构体的应用
结构数组
#include"stdio.h"
struct stu
{
char name[20];
int age;
char sex[5];
char id[20];
}stu1[5] ;
int main()
{
int a;
struct stu stu1 [5]= { { "okkk", 20, "oo", "ooo" },{"ooook",30,"iiii","ooooo"} };
int length = sizeof(stu1) / sizeof(struct stu);
int i = 0;
for (i = 0; i < length; i++)
{
printf("%s %d %s %s\n", stu1[i].name, stu1[i].age, stu1[i].sex, stu1[i].id);
}
}
先定义,后初始化,整体赋值。
结构体传参
#include"stdio.h"
struct S
{
int a;
char c;
double d;
};
void Init(struct S* ps)
{
ps->a = 100;
ps->c = 'w';
ps->d = 3.14;
}
void print1(struct S tmp)
{
printf("%d %c %lf", tmp.a, tmp.c, tmp.d);
}
void print2(struct S* ps)
{
printf("%d %c %lf",ps->a,ps->c,ps->d);
}
int main()
{
struct S s = { 0 };
Init(&s);//地址传参
print1(s);//值传参
print2(&s);//地址传参比值传参更省空间。
}
枚举
#include"stdio.h"
enum color
{
gree,
red,
yellow
};
int main()
{
enum color s = gree; //我们选了一个绿色
};
#include"stdio.h"
enum color
{
gree,
red,
yellow
};
int main()
{
enum color s;
printf("%d\n", gree);\\从零开始的初始值
};
这个就是从初始值零开始的
上图就是赋值从1开始的。
联合体
#include"stdio.h"
union Un
{
char c;
int i;
};
int main()
{
union Un un;
printf("%d\n", sizeof(un));
}
小伙伴们可以猜下,这个un变量名,占几个字节,有点可能会猜成5个字节,因为一个字节和四个字节,下面运行下代码可以看下,占几个字节。
占4个字节,这就引出了联合体的定义他们共用一个空间。既然他们共用一个空间话,那它们地址应该相同。
它们的地址确实相同,如果不理解联合的定义,也可以理解成它们的地址相同。那么问题来了,那么联合体的字节是怎么确定的呢?联合体的字节是它们中的类型占的最大的字节。比如说整型和字符类的在一起,那么联合体的字节就是4。