一 结构体
结构体: 一系列不同类型的数据的结合
- 注意:类型!= 变量。 结构体名代表的只是结构体类型,没有内存空间。
- 结构体中的成员可以单独使用
- 结构体是C编程中一种用户自定义的数据类型,类似于Java的JavaBean
1 定义结构体
struct Studet {
char name[20];
int age;
char gender[10];
int classId;
};
//使用:struct Studet st;
也可以定义全局,与方法中使用的结构体类型一致,作用域不同
struct Studet {
char name[20];
int age;
char gender[10];
int classid;
}Lucy;
2 匿名结构体
用一种特殊的结构体,没有结构体名称直接定义变量名:
作用:不能再申请对应类型的变量,类似java的匿名内部类
struct {
char name[20];
int age;
int classid;
} stu2,stu3;
注意:
- 类型不等于变量,结构体名代表的只是结构体类型,不会分配内存空间
- 对结构体成员可以单独成员可以单独使用
3 初始化
- 第一种初始化方式:
struct关键字可以不要
struct Student {
char name[20];
int age;
} ;
int test4() {
struct Student stu1 = { "lucy" ,20};
return 0;
}
- 第二种初始化方式
struct Student stu2;
strcpy(stu2.name, "lucy");
stu2.age = 20;
**注意:**数组的初始化用strcpy
- 第三种初始化方式
struct Student {
char name[20];
int age;
} Lucy = { "lucy", 20 };
结构体中的成员可以单独使用
struct Student stu2;
strcpy(stu2.name, "lucy");
stu2.age = 20;
printf("%s,%d\n", stu2.name, stu2.age);
运行结果:lucy,20
错误:
错误 C4996 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. NDK_C c:\users\pf0zybaj\source\repos\ndk_c\ndk_c\lsn04.cpp 32
属性->预处理-> 添加: _CRT_SECURE_NO_WARNINGS
5 使用typedef定义
//Student 相当于类名
//student和a 可以不定义,表示结构变量,也就Student类型的变量
struct Student
{
char name[50];
int age;
} student,a;
//使用typedef定义
typedef struct{
char name[50];
int age;
} Student;
当结构体需要内存过大,使用动态内存申请。结构体占用字节数和结构体内字段有关,指针占用内存就是4/8字节,因此传指针比传值效率更高。
struct Student *s = (Student*)malloc(sizeof(Student));
memset(s,0,sizeof(Student));
printf("%d\n", s->age);
6 字节对齐
内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址开始访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序一个接一个地存放,这就是对齐。
字节对齐的问题主要就是针对结构体。
struct MyStruct1
{
short a;
int b;
short c;
};
struct MyStruct2
{
short a;
short c;
int b;
};
//自然对齐
//1、某个变量存放的起始位置相对于结构的起始位置的偏移量是该变量字节数的整数倍;
//2、结构所占用的总字节数是结构中字节数最长的变量的字节数的整数倍。
// short = 2 补 2
// int = 4
// short = 2 补 2
sizeof(MyStruct1) = 12
// 2个short在一起组成一个 4
sizeof(MyStruct2) = 8
#pragma pack(2) //指定以2字节对齐
struct MyStruct1
{
short a;
int b;
short c;
};
#pragma pack() //取消对齐
//short = 2
//int = 4
//short = 2
合理的利用字节可以有效地节省存储空间
不合理的则会浪费空间、降低效率甚至还会引发错误。(对于部分系统从奇地址访问int、short等数据会导致错误)
二 结构体数组
结构体声明后,结构体数组与普通数据类型数组的数组一样
1 第一种方式初始化数组
//能够识别,结构清晰,可以一眼看出初始化是否有问题
struct Student stu[3] = { { "lucy", 20 },{ "lilei", 32 },{ "Hanmeimei", 35 } };
//也支持不用{},但不建议:
//struct Student stu[3] = {"lucy", 20 , "lilei", 32 ,"Hanmeimei", 35 };
2 第二种方式初始化数组
struct Student s[5];
for (int i = 0;i < 5;i++) {
s[i].age = 20 + i;
strcpy(s[i].name, "lucy");
}
for (int i = 0;i < 5;i++) {
printf("s %d:%s,%d\n", i, s[i].name, s[i].age);
}
三 结构体指针
- 赋值
struct Student stu[3] = { { "lucy", 20 },{ "lilei", 32 },{ "Hanmeimei", 35 } };
struct Student * stud = stu;
- 单独定义,分配内存,初始化并使用
struct Student {
char * name;
int age;
};
int test4() {
struct Student * stud;
//分配内存
stud = (Student *)malloc(sizeof(struct Student) * 4);
//初始化
memset(stud, 0, sizeof(struct Student) * 4);
for (int i = 0;i < 4;i++) {
// (stud + i)->age = 20 + i;
// (stud + i)->name = (char * )"lucy";
//也可写成如下,因为初始化的时候具备了数组属性
stud[i].age = 20 + i;
stud[i].name = (char *)"lucy";
}
for (int i = 0;i < 4;i++) {
printf("stud %d: %s, %d\n", i, (stud + i)->name, (stud + i)->age);
}
system("pause");
return 0;
}
运行结果:
stud 0: lucy, 20
stud 1: lucy, 21
stud 2: lucy, 22
stud 3: lucy, 23
四 结构体中添函数指针成员变量
struct Man {
int age;
char *name;
int(*Msg)(char *, int);
};
int message(char * str, int age) {
//创建一个窗口
MessageBox(0, TEXT("hello"), TEXT("Lijian"), 0);
return 0;
}
int test4() {
struct Man man;
man.age = 40;
man.name = (char *)"lijian";
man.Msg = message;
man.Msg((char *)man.name, man.age);
system("pause");
return 0;
}
五 结构体中添加结构体指针成员变量
struct Node {
int data;
Node * next;
};
//在单链表的末尾添加一个数据
int enqueNode(Node *head, int data) {
Node * node = (Node *)malloc(sizeof(Node));
if (node == NULL) {
return 0;
}
node->data = data;
node->next = NULL;
//用p是为了不改变head的值
Node *p = head;
while (p->next != NULL) {
p = p->next;
}
p->next = node;
return 1;
}
int test4() {
Node * list;
list = (Node *)malloc(sizeof(struct Node));
list->data = 0;
list->next = NULL;
int num = 10;
int i = 0;
for (i = 0; i < num; i++) {
enqueNode(list, i + 1);
}
while (list->next != NULL)
{
printf("%d \n", list->data);
list = list->next;
}
system("pause");
return 0;
}
输出:
0
1
2
3
4
5
6
7
8
9