构造类型-结构体
2020-04-19 本文已影响0人
晓晓桑
声明结构体
- 声明位置:可以在函数内部(只有此函数可用) 或者函数外部(所有函数都可用),但是在下面不行
- 关键字:struct
- 花括号之后要加分号
- 结构体名字不能相同
- 至少一个成员,不加成员报错
- 区分为有名字的结构体和无名字的结构体
注意:没有名字的结构体,后面一定要接着声明变量 - C中结构体不能有函数,可以用函数指针
- 声明的两种形式 :
1.在声明结构体类型的时候,顺便声明变量。-->这个时候可以不写结构体的名字
2.利用结构体名字声明变量。
//声明结构体 可以在函数外部,所有方法都可以用
struct Student {
char name[10];
unsigned int age;
double high;
char num[20];
};
int main(void) {
//声明结构体 可以在函数内部,只能在函数里面用
struct Student {
char name[10];
unsigned int age;
double high;
char num[20];
};
struct Student student;
return 0;
}

//声明的形式
struct Student {
char name[10];
unsigned int age;
double high;
char num[20];
} stu1, stu2;
//没有名字的结构体,后面一定要接着声明变量
struct {
char name[10];
unsigned int age;
double high;
char num[20];
} stu4, stu5;
int main(void) {
struct Student stu3;//struct一定要不要落下
return 0;
}
定义 初始化
//初始化
struct Student {
char name[10];
unsigned int age;
double high;
char num[20];//学号
} stu1 = {"小晓", 18, 1.60, "20200409"}, stu2;
int main(void) {
//顺序要对象,类型要对象
struct Student stu3 = {"晓晓", 27, 1.65, "20200409"};
return 0;
}
结构体取成员运算符
分两种: 实例变量struct Stu stu、指针变量struct Stu *p
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Student {
char name[10];
unsigned int age;
double high;
char num[20];//学号
} stu1 = {"小晓", 18, 1.60, "20200409"}, stu2;
int main(void) {
//顺序要对象,类型要对象
struct Student stu3 = {"晓晓", 27, 1.65, "20200409"};
//1。实例变量取值
//读
// stu3.num和(&stu3)->num都行。因为指针是地址,p-> 其实就是地址->
printf("%s,%d,%.2lf,%s\n", stu3.name, stu3.age, stu3.high, (&stu3)->num);//晓晓,27,1.65,20200409
//2。指针变量取值
//这个一定要初始化一定空间,可以直接指向对象,也可以malloc申请一块空间
struct Student *p1 = &stu3;//指针指向对象的地址,
//读
printf("%s,%d,%.2lf,%s\n", p1->name, p1->age, p1->high, p1->num);//晓晓,27,1.65,20200409
//3。也可以malloc申请一块空间
struct Student *p = (struct Student *) malloc(sizeof(stu3));//申请一个空间
p->age = 12;//赋值
(*p).high = 1.8;
strcpy(p->name,"大大");//p->name="asd"❌,因为数组定义好以后不能像初始化一样去赋值了
strcpy((*p).num,"2020");//可以写成(*p).num
//读
printf("%s,%d,%.2lf,%s\n", p->name, p->age, p->high, p->num);//大大,12,1.80,2020
// .和->优先级高于&和*
return 0;
}
结构体成员的赋值
- 成员单个赋值
p->age = 12;//赋值
(*p).high = 1.8;
strcpy(p->name,"大大");//p->name="asd"❌,因为数组定义好以后不能像初始化一样去赋值了
strcpy((*p).num,"2020");//可以写成(*p).num
- 复合文字结构
struct Student stu4;
stu4 = (struct Student) {"晓晓", 27, 1.65, "20200409"}; //强制转换
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Student {
char name[10];
unsigned int age;
double high;
char num[20];//学号
} stu1 = {"小晓", 18, 1.60, "20200409"}, stu2;
int main(void) {
struct Student stu3 = {"晓晓", 27, 1.65, "20200409"};
struct Student stu4;
//强制转换
stu4 = (struct Student) {"晓晓", 27, 1.65, "20200409"};
struct Student *p = &stu4;
printf("%s,%d,%.2lf,%s\n", p->name, p->age, p->high, p->num);//晓晓,27,1.65,20200409
printf("%s,%d,%.2lf,%s\n", stu4.name, stu4.age, stu4.high, stu4.num);//晓晓,27,1.65,20200409
return 0;
}
-
部分元素初始化
注意:初始化部分成员,其他的都默认为0、""
image.png
指针成员与函数成员
指针成员
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Stu {
int *p;
};
int main(void) {
//1.null 2.栈区地址 3。堆区地址
//1.
struct Stu stu = {NULL};
stu.p = malloc(8);
//2.初始化结构体
int a[5] = {1, 2, 3, 4, 5};
struct Stu stu2 = {a};//a[0],&a
//stu2.p是指针,.的优先级高于[]
printf("%d,%d\n", stu2.p[0], stu2.p[4]);//1,5
//3.malloc一个地址,然后指向数组
struct Stu *p1 = (struct Stu *) malloc(sizeof(stu2));
p1->p = a;// 或者 (*p1).p = a;
printf("%d,%d\n", stu2.p[0], stu2.p[4]);//1,5
//直接在结构体里malloc
struct Stu stu1 = {(int *) malloc(20)};
stu1.p[0] = 1;
stu1.p[1] = 12;
printf("%d,%d", stu2.p[0], stu2.p[1]);//1,2
return 0;
}
函数成员
C的结构体不能调用函数,结构体中可以房函数的地址,这样就可以调用函数了,如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void fun(void) {
printf("i am fun\n");
}
struct Stu {
//函数的指针
void (*p)();
};
int main(void) {
//初始化 函数名就是函数地址
struct Stu stu = {fun};
//stu.p是函数地址,stu.p()调用函数
stu.p(); //.和()级别相同,从左向右运算
return 0;
}
结构体嵌套
1.嵌套多少层都可以
struct里面声明一个struct类型
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Student {
char name[10];
int age;
};
struct Teacher {
char name[10];
int age;
struct Student student;
};
int main(void) {
//初始化
struct Teacher teacher2 = {"张老师", 39, "晓晓", 27};
//写不写花括号都可以
struct Teacher teacher = {"张老师", 39, {"晓晓", 27}};
struct Student student = {"大大", 27};
struct Teacher teacher3 = {"李老师", 39, student};
printf("%s,%d,%s,%d\n", teacher2.name, teacher2.age, teacher2.student.name, teacher2.student.age);//张老师,39,晓晓,27
printf("%s,%d,%s,%d", teacher3.name, teacher3.age, teacher3.student.name, teacher3.student.age);//李老师,39,大大,27
return 0;
}
2.struct里面写struct函数,不能直接初始化

结构体数组
一个数组,每个元素是结构体类型,他就叫结构体数组
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Teacher {
char name[20];
int age;
};
int main(void) {
//加花括号可以部分不初始化
struct Teacher teacher[3] = {{"张老师", 23},
{"李老师", 29},
{"王老师", 24}};
//不加花括号也行
struct Teacher teacher2[3] = {"张老师", 23,
"李老师", 29,
"王老师", 24};
for (int i = 0; i < 3; ++i) {
//结果:
//张老师,23
//李老师,29
//王老师,24
printf("%s,%d\n", teacher[i].name, teacher[i].age);
}
// //加花括号可以部分不初始化
struct Teacher teacher3[3] = {{"张老师"},
{},
{"王老师", 24}};
//复合赋值
teacher[0] = (struct Teacher) {"欧阳老师", 90};
printf("%s,%d\n", teacher[0].name, teacher[0].age);//欧阳老师,90
return 0;
}
结构体大小
内存对齐(字节对齐)
cpu处理数据
- 32位cpu一次能处理的数据是32bit位,4字节
- 64位cpu一次能处理的数据是64bit位,8字节
- 起始地址是偶数,因为从0开始 +4+4/+8+8
字节对齐:
假设数据挨着存储,char c,int a; 或者跨字节存储时,cpu要读两次,把两次读组成一个数据,效率就低了。
内存对齐是数据存储的规则,因为cpu读的规律是定的。假设我的数据按字节段存储char c,int a,分别存在各种的字节段,不垮字节段存储,那么每个数据cpu只需要读取一次就可以了。这种存储方式执行效率高,但是会浪费一点空间。
char c; short s;这两种如何存?
存在一个四字节的内存就够了,char存到第一个字节的时候,short存储在第三第四个字节,留出第二个。
结构体大小的计算规则
结构体大小是:结构体定义的变量所占的字节数。
- 以最大类型为字节对齐宽度
- 依次填补各个成员字节
-
结尾补齐
image.png
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Teacher {
char c;
int age;
double d;
short s;
};
int main(void) {
struct Teacher teacher2;
//解释看上面的图
printf("%u,%u", sizeof(struct Teacher), sizeof(teacher2));//24,24
return 0;
}
从上往下分配,如果上面int 和short换一下顺序,大小就改变了

struct Teacher {
char c;
short s;
int age;
double d;
};
int main(void) {
struct Teacher teacher2;
printf("%u,%u", sizeof(struct Teacher), sizeof(teacher2));//16,16
return 0;
}
综上所述:结构体要是按照类型的自己数从小到达写的话,会节省空间。
手动设置字节对齐 : #pragma pack(4);
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//手动设置内存对齐的字节数
#pragma pack(4) //设置的要小于等于结构体里面最大的那个自己数
struct Teacher {
char c;
int age;
double d;
short s;
};
int main(void) {
struct Teacher teacher2;
// 有#pragma pack(4):20 没有#pragma pack(4):24,24
printf("%u,%u", sizeof(struct Teacher), sizeof(teacher2));
//分析一下:
//char c占在四字节的第一个字节
//int age在四字节填满
// double d占两个四字节
// s在一个四字节的前两个内存中
// 一共加起来是20个字节
return 0;
}
注意:
1.结构体不能互相嵌套实例,可以嵌套指针
2.结构体不能包含自己的实例
以下错误❌

以下对🙆
