结构体

为什么需要结构体

为了表示一些复杂的事物,而普通的基本类型无法满足实际要求

什么叫结构体

把一些基本类型数据组合在一起形成一个新的符合数据类型,这个叫做结构体

如何定义结构体

有三种,第一种掌握,后两种不要求掌握,已经不用了

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
# include <stdio.h>

//使用第一种,后两种都有缺点
//第一种(重要) //只是定义了一个新的数据类型,没有定义变量
struct Student
{
int age;
float score;
char sex;
}; //分号不能省略

//第二种方式
struct Student2
{
int age;
float score;
char sex;
} st2;

//第三种方式 不知道什么数据类型
struct
{
int age;
float score;
char sex;
} st3;



怎么样使用结构体变量

赋值和初始化

定义的同时可以整体赋初值
如果定义完之后,则只能单个的赋初值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# include <stdio.h>

//结构体变量的赋值和初始化
struct Student
{
int age;
float score;
char sex;
}; //分号不能省略

int main(void)
{
struct Student st = { 80, 66.6, 'F' }; //初始化,定义的同时赋初值
struct Student st2;
st2.age = 10;
st2.score = 88;
st2.sex = 'F';
printf("%d %f %c\n", st.age, st.score, st.sex);
printf("%d %f %c\n", st2.age, st2.score, st2.sex);

return 0;
}

如何取出结构体变量中的每一个成员(重点)

  1. 结构体变量名.成员名
  2. 指针变量名->成员名 (第二种方式更常用)
    指针变量名->成员名 在计算机内部会被转化成 (*指针变量名).成员名的方式来执行
    所以说这两种方式是等价的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# include <stdio.h>

//如何取出结构体变量中的每一个成员
struct Student
{
int age;
float score;
char sex;
}; //分号不能省略

int main(void)
{
struct Student st = { 80, 66.6, 'F' }; //初始化,定义的同时赋初值
struct Student* pst = &st; //&st不能改成st

pst->age = 88;//第二种方式
st.age = 66.6f; //第一种方式 66.6在c语言中默认是double类型,如果希望希望一个实数是float类型,则必须在末尾加f或F,因此66.6是double,66.6f和66.6F是float类型


return 0;
}

在VS中的输出结果是:66 66.599998
//为什么66.6变66.599998,因为float和double都不能够保证准确存储.跟编码格式有关,只能存近似值
  1. (重点)pst->age 在计算机内部会被转化成(*pst).age 这就是->的含义,是一种硬性规定
  2. 所以 pst->age 等价于 (*pst).age 也等价于 st.age
  3. 我们之所以知道pst->age等价于 st.age,是因为pst->age是被转化成了(*pst).age来执行
  4. pst->age 的含义:
    pst所指向的那个结构体变量中的age这个成员

结构体变量和结构体指针变量作为函数参数传递的问题(实际讲指针的优点)

推荐使用结构体指针变量作为函数参数来传递
通过函数完成对结构体变量的输入和输出

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# include <stdio.h>
# include <string.h>
//通过函数完成对结构体变量的输入和输出
//结构体变量和结构体指针变量作为函数参数传递的问题(实际讲指针的优点)

struct Student
{
int age;
char sex;
char name[100];

}; //分号不能省

void InputStudent(struct Student *pstu); //函数在mian后面,需要前置声明
void OutputStudent(struct Student); //声明可不写参数

int main(void)
{
struct Student st; //对结构体变量输入

InputStudent(&st); //对结构体变量输入 必须发送st的地址
//printf("%d %c %s\n", st.age, st.sex, st.name);
OutputStudent(st); //对结构体变量输出 可以发送st的地址,也可以直接发送st的内容

return 0;
}

void OutputStudent(struct Student ss)
{

printf("%d %c %s\n", ss.age, ss.sex, ss.name);
}



void InputStudent(struct Student * pstu) //pstu只占4个字节
{
(*pstu).age = 10;
strcpy(pstu->name, "张三"); //不能写成 stu.name = "张三"; 需要在前面# include <string.h>
pstu->sex = 'F';
}




/*
* 本函数无法修改主函数18行st的值,所以本函数是错误的
void InputStudent(struct Student stu)
{
stu.age = 10;
strcpy(stu.name, "张三"); //不能写成 stu.name = "张三"; 需要在前面# include <string.h>
stu.sex = 'F';
}
*/

在VS中的输出结果是:
10 F 张三

发送地址还是发送内容(指针优点之一:快速的传递数据)

指针的优点之一:
快速的传递数据,减少了内存的耗用

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# include <stdio.h>
# include <string.h>
/*发送地址还是发送内容 30~40行代码
* 目的:指针的优点之一:
* 快速的传递数据
* 耗用内存小
* 执行速度快


*/



struct Student
{
int age;
char sex;
char name[100];

}; //分号不能省

void InputStudent(struct Student* ); //函数在mian后面,需要前置声明
void OutputStudent(struct Student*); //声明可不写参数

int main(void)
{
struct Student st; //对结构体变量输入
//printf("%d\n", sizeof(st)); //sizeof(变量)查询变量占了几个字节 108个

InputStudent(&st); //对结构体变量输入 必须发送st的地址
OutputStudent(&st); //对结构体变量输出 可以发送st的地址,也可以直接发送st的内容 但为了减少内存的耗费,也为了提高执行速度,推荐发送地址

return 0;
}

void OutputStudent(struct Student *pst) //可以发送st的地址,也可以直接发送st的内容 但为了减少内存的耗费,也为了提高执行速度,推荐发送地址
{

printf("%d %c %s\n", pst->age, pst->sex, pst->name);
}



void InputStudent(struct Student* pstu) //pstu只占4个字节
{
(*pstu).age = 10;
strcpy(pstu->name, "张三"); //不能写成 stu.name = "张三"; 需要在前面# include <string.h>
pstu->sex = 'F';
}




/*
* 本函数无法修改主函数18行st的值,所以本函数是错误的
void InputStudent(struct Student stu)
{
stu.age = 10;
strcpy(stu.name, "张三"); //不能写成 stu.name = "张三"; 需要在前面# include <string.h>
stu.sex = 'F';
}
*/

结构体变量的运算

结构体变量不能相加,不能相减,也不能相互乘除
但结构体变量可以相互赋值
例子:

1
2
3
4
5
6
7
8
9
10
11
struct Student
{
int age;
char sex;
char name[100];
}, //分号不能省

struct Student st1, st2;
st1+st2 st1*st2 st1/st2 都是错误的,结构体变量不能相加,不能相减,也不能相互乘除
st1 = st2 或者st2 = st1 都是正确的

举例

前置知识:冒泡排序

该程序流程控制复习p165-14:15
流程控制复习

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
36
37
38
39
40
# include <stdio.h>

//冒泡排序
void sort(int * a, int len)
{
int i, j, t;

for (i = 0; i < len - 1; ++i) //流程控制复习:p165 15:38
{
for (j = 0; j < len - 1 - i; ++j)
{
if (a[j] > a[j + 1]) //>表示升序 <表示降序
{
t = a[j];
a[j] = a[j + 1];
a[j + 1] = t;
}
}
}
}

int main(void)
{
int a[6] = { 10, 2, 8, -8, 11, 0 };
int i = 0;

sort(a, 6);

for (i = 0; i < 6; ++i)
{
printf(" %d", a[i]);
}
printf("\n");

return 0;


return 0;
}

动态构造存放学生信息的结构体数组

动态构造一个数组,存放学生的信息
然后按分数排序输出

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# include <stdio.h>
# include <malloc.h>

struct Student
{
int age;
float score;
char name[100];
};

int main(void)
{
int len;
struct Student * pArr;
int i, j;
struct Student t;

//动态的构造一维数组
printf("请输入学生的个数:\n");
printf("len = ");
scanf("%d", &len);
pArr = (struct Student *)malloc(len* sizeof(struct Student ));

//输入
for (i = 0; i < len; ++i)
{
printf("请输入第%d个学生的信息: \n", i + 1);
printf("age = ");
scanf("%d", & pArr[i].age);

printf("score =");
scanf("%f", &pArr[i].score); //float用%f

printf("name =");
scanf("%s", pArr[i].name); //name是数组名,本身就一件是数组首元素的地址,不需要加取地址符&. %s表示字符串类型

}

//按学生成绩升序排序,冒泡算法
for (i = 0; i < len - 1; ++i)
{
for (j = 0; j < len - 1 - i; ++j)
{ //大于就是升序,小于就是降序
if (pArr[j].score > pArr[j + 1].score) //比较需要标准,而不是整体比较,所以后面要加.score比较分数
{
t = pArr[j]; //互换的是位置而不是成绩
pArr[j] = pArr[j + 1];
pArr[j + 1] = t;
}
}
}


printf("\n\n学生的信息是:");
//输出
for (i = 0; i < len; ++i)
{
printf("第%d个学生的信息是:\n", i + 1);
printf("age = %d\n", pArr[i].age);
printf("name = %s\n", pArr[i].name);
printf("score = %f\n", pArr[i].score);
}
return 0;
}
在VS中的输出结果是:
请输入学生的个数:
len = 4
请输入第1个学生的信息:
age = 10
score =6
name =zhanshan
请输入第2个学生的信息:
age = 20
score =88.8
name =lisi
请输入第3个学生的信息:
age = 22
score =55.5
name =wangwu
请输入第4个学生的信息:
age = 21
score =98.9
name =xiaojuan


学生的信息是:第1个学生的信息是:
age = 10
name = zhanshan
score = 6.000000
2个学生的信息是:
age = 22
name = wangwu
score = 55.500000
3个学生的信息是:
age = 20
name = lisi
score = 88.800003
4个学生的信息是:
age = 21
name = xiaojuan
score = 98.900002