结构体

定义

结构体是一种构造数据类型,其将不同的数据类型整合起来,形成一个自定义的数据,类似于
JavaScript中的类,不同的是,不能够定义函数;

1
2
3
4
5
6
7
// 结构体是一种构造数据类型
// 把不同的数据类型整合起来,成为一个自定义的数据类型
struct man{
int age;
char name[10];
char* sex;
};

声明变量

已创建的结构体的声明有两种方式,一种是在定义时直接声明,一种是通过”.”操作符访问,并赋值;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 初始化结构体
// 方式1
struct man m1 = { 10, "jj" };

// 方式2
struct man m2;
m2.age = 10;
// 对于数组类型,只能使用strcopy函数进行赋值
//strcpy(m2.name, "lala");
sprintf(m2.name, "uu");

// char* 类型可以直接赋值
m2.sex = "girl";

// 只能在声明时进行赋值,否则只能用"."访问符进行赋值
//m2 = { 10, "jj" };

创建结构体的方式

方式1:创建的同时,为结构体声明变量;

1
2
3
4
5
6
// 定义结构体同时声明Human、man成员变量
struct Human{
int age;
char* name;
char sex[3];
} Human,man = {10,"coco","man"};

方式2:创建匿名的结构体;

1
2
3
4
5
6
7
// 匿名结构体
// 匿名结构体必须为其创建变量
// 用来控制结构体变量的个数(因为变量在声明时就必须创建,实现单例效果)
struct{
char name[10];
int age;
}m1,m2;

匿名结构体可以实现Java中类似的单例效果!

结构体嵌套

结构体支持嵌套,既可以是定义时嵌套,也可以是声明时嵌套;

定义时嵌套:

1
2
3
4
5
6
struct Stu{
int age;
struct Tea{
int age;
} t;
};

声明时嵌套:

1
2
3
4
5
6
7
8
9
10
struct Teacher{
char name[20];
};

// 方式1
struct Student{
char name[20];
int age;
struct Teacher t;
};

结构体内存大小

结构体虽然是多种数据类型的集合,但其占用内存大小并不一定是所有数据类型的总和,而是大于
等于总和;

1
2
3
4
struct StructSize{
int age;
double weight;
};

这个结构体的内存不是int+double = 4+8=12,而是要根据最大的数据类型来定,其内存大小必须
是能够整除最大的数据类型的最小值,即必须能够整除double,所以必须再加上4等于16;

1
2
3
4
5
struct StructSize{
int age;
int height;
double weight;
};

这个数据结构内存大小为int + int + double = 16,刚好能够整除double,所以是16;

这样设计的目的是为了让访问数据的跨度保持相同,提高访问数据的效率;

结构体指针

结构体指针能够让我们更加方便的访问其中的数据;

1
2
3
4
5
6
7
8
9
10
// 方式1
struct Student stu1 = { "ff", 20, { "hh" } };

// 结构体指针
struct Student *p = &stu1;

// 访问数据方式1
printf("%s,%d\n", (*p).name, (*p).age);
// 方式2(推荐)
printf("%s,%d\n", p->name, p->age);

通过指针快捷的遍历结构体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 遍历结构体数组
struct Student s[2] = { {10,"lili"}, {20,"huahua"} };

// 采用数组遍历的方式比较麻烦
int i = 0;
for (; i < sizeof(s) / sizeof(struct Student); i++){
printf("%s,%d\n", s[i].name, s[i].age);
}

// 采用指针遍历
struct Student* ps = s;
for (; ps < s+2; ps++){
printf("%s,%d\n", ps->name, ps->age);
}

结构体实现类

C语言是面向过程编程的,但很多时候需要借鉴面向对象的思想,而结构体+指针,能够让我们模拟出
类的效果。首先通过函数指针,能够实现类方法的效果,而为结构体再定义一个指针别名,则能够
模拟类实例在参数传递时是引用传递的效果,因为结构体在参数传递时是通过值传递的;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 // 定义结构体和指针的别名
typedef struct Woman{
int age;
char name[20];
} W,*WP;

// 结构体函数指针成员(类似于Java的类)
struct FunctionTest{
char* hello;
// 函数指针,模拟方法
int(*sayHello)(char* h);
}

int sayHellow(char* text){
printf("%#x\n",&text);
return 0;
}

void main(){
W w = { 11, "woman" };

// 此处定义指针方便了对结构体的访问
// 要让结构体有类引用的效果,通过函数的参数指针来实现
WP wp = &w;

printf("%d,%s\n", wp->age, wp->name);

struct FunctionTest fun;
fun.hello = "hello";
fun.sayHello = sayHellow;

fun.sayHello("hello i am fine");

getchar();
}