结构体类型的声明
写在main函数外面
cpp
struct Book{
char book_name[20];
char author[20];
float price;
char id[19];
}a1,a2,a3;//这里必须要有封号
结构的特殊声明(可以不完全声明)
匿名结构体类型
cpp
struct{
char book_name[20];
char author[20];
float price;
char id[19];
}s1,s2;//只能在这里创建结构体变量
int main(){
return 0;
}
结构体变量的创建和初始化
cpp
struct Book{
char book_name[20];
char author[20];
float price;
char id[19];
}a1,a2,a3;//这里必须要有封号
int main(){
struct Book b1 = {"数据结构","lili",18.8f,"91029384020113"};
struct Book b2 = {.id="ug20260817",.book_name="liliLinux",.author="lili",.price=8.8f};
struct Book b3;
}
结构的自引用
数据结构:数据在内存中的组织结构
解决的问题:
1.解决 "数据数量不确定" 的问题
2.解决 "数据之间需要动态关联" 的问题
线性的数据结构:
数据在内存中连续存放:顺序表
|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 |链表:
结点要存放数据,还要找到下一个结点,怎么做到?
Struct Node
{
int data;
struct Node next;
}
不能这样写,会死循环
想找下一个结点,就把下一个结点的地址存放起来就好了
这时候就用指针
cpp
Struct Node
{
int data;
struct Node* next;
}

所以,结构体的自引用:
在一个结构体类型的结构体中,找到下一个同类型的下一个结构体变量。
存放数据的区域:数据域
存放指针的区域:指针域
对结构体类型重命名
typedef struct Node
{
int data;
struct Node* next; //这里面不能用重命名的名称
}Node; //Node就是新命名的
结构体成员访问操作符
1. 点操作符
struct Point p1;
p1.x = 10;
p1.y = 20;
2. 箭头操作符
struct Point *ptr = &p1;
ptr -> x = 30;
ptr -> y = 40;
3. (ptr ->x = 30;) 等效写法
(*ptr).x = 30;
结构体内存对齐(很重要)
用于计算结构体的大小
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
struct s1{
char c1;
char c2;
int n;
};
struct s2 {
char c1;
int n;
char c2;
};
int main() {
printf("%zd\n", sizeof(struct s1));
printf("%zd\n", sizeof(struct s2));
}
为什么s1结构体总大小结果是8,s2结果是12 ???
因为结构体在内存中存在对齐现象
这里就要引入偏移量的概念

一个字节是一个内存单元
结构体的对齐规则:
- 结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
- 结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数,所有对齐数中最大的)的整数倍
- 如果嵌套了结构体的備况,歌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。
对齐数 = 编译器默认的一个对齐数 与 该成员变量大小的较小值。
- VS 中默认的值为 8
- Linux中 goc 没有默认对齐数,对齐数就是成员自身的大小
offsetof 是宏用于计算结构体成员相较于结构体变量起始位置的偏移量
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stddef.h>
struct S1{
char c1;
char c2;
int n;
};
struct S2 {
char c1;
int n;
char c2;
};
int main() {
struct S1 s1 = { 0 };
printf("%zd\n", offsetof(struct S1,c1));
printf("%zd\n", offsetof(struct S1,c2));
printf("%zd\n", offsetof(struct S1,n));
}
结果是0 1 4

结构体总大小:8
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stddef.h>
struct S1{
char c1;
char c2;
int n;
};
struct S2 {
char c1;
int n;
char c2;
};
int main() {
struct S1 s1 = { 0 };
printf("%zd\n", offsetof(struct S2,c1));
printf("%zd\n", offsetof(struct S2,n));
printf("%zd\n", offsetof(struct S2,c2));
}
结果是0 4 8

结构体总大小:12
目前它们占9个字节,但因为最大对齐数是4,所以结构体总大小为12
为什么存在对齐?
1.平台原因:
某些硬件平台只能在某些地址处访问特定类型的数据
2.性能原因
怎么节省空间?
让占用空间小的成员尽量在一起
or
修改VS上为8的默认对齐数(一般设置为2)
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#pragma pack(1)
struct S{
char c1;
int n;
char c2;
};
#pragma pack()//改为原位
int main() {
printf("%zd\n", sizeof(struct S));
return 0;
}
结构体传参
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
struct S{
int arr[1000];
int n;
char ch;
};
void print1(struct S tmp) {//用tmp打印跟用S打印一样
//传值调用
for (int i = 0; i < 10; i++) {
printf("%d ", tmp.arr[i]);
}
printf("\n");
printf("n = %d", tmp.n);
printf("\n");
printf("ch = %c", tmp.ch);
printf("\n");
}
void print2(struct S* ps) {
//传址调用
for (int i = 0; i < 10; i++) {
printf("%d ", ps->arr[i]);
}
printf("\n");
printf("n = %d", ps->n);
printf("\n");
printf("ch = %c", ps->ch);
printf("\n");
}
int main() {
struct S s = { {1,2,3,4,5,6,7,8,9,10},10,'w' };
print1(s);
print2(&s);
return 0;
}
结论:结构体传参时,要传结构体的地址
