Auc的个人博客

vuePress-theme-reco Auc    2020 - 2021
Auc的个人博客 Auc的个人博客

选择一个主题吧~

  • 暗黑
  • 自动
  • 明亮
主页
分类
  • JavaScript
  • Vue
  • 数据结构与算法
  • 文档
  • 面试题
  • 笔记
标签
笔记
  • CSS
  • ES6
  • JavaScript
  • Vue
  • C语言
文档
  • Vueのapi
  • Vue Router
  • axios
  • Vue CLI
面试
  • JS
  • Vue
  • 基础
时间线
联系我
  • GitHub (opens new window)
author-avatar

Auc

62

文章

11

标签

主页
分类
  • JavaScript
  • Vue
  • 数据结构与算法
  • 文档
  • 面试题
  • 笔记
标签
笔记
  • CSS
  • ES6
  • JavaScript
  • Vue
  • C语言
文档
  • Vueのapi
  • Vue Router
  • axios
  • Vue CLI
面试
  • JS
  • Vue
  • 基础
时间线
联系我
  • GitHub (opens new window)
  • C

    • 写在前面
    • C语言概述
    • 数据类型、运算符与表达式
    • 语句、函数、作用域与数组与字符串
    • 指针
    • 结构体
    • typedef关键字

结构体

vuePress-theme-reco Auc    2020 - 2021

结构体

Auc 2021-03-11 C语言笔记

# 结构体

# 认识结构体

# 声明结构体

学过面向对象语言的同学可以类比一下,C中的结构体跟对象比较相似。可以使用结构体(Struct)来存放一组不同类型的数据。

结构体是一种集合,它里面包含了多个变量或数组,它们的类型可以相同,也可以不同,每个这样的变量或数组都称为结构体的成员(Member)。

/*声明结构体*/
struct 结构体名{
    结构体所包含的变量或数组
};
1
2
3
4
struct stu{
  char *name;  //姓名
  int num;  //学号
  int age;  //年龄
  char group;  //所在学习小组
  float score;  //成绩
};
1
2
3
4
5
6
7
  1. 结构体成员的定义方式与变量和数组的定义方式相同,只是不能初始化。
  2. 注意大括号后面的分号;不能少,这是一条完整的语句。

# 结构体变量

// 声明结构体变量 stu1, stu2
struct stu stu1, stu2;
1
2

也可以在定义结构体的同时定义结构体变量

struct stu{
  char *name;  //姓名
  int num;  //学号
  int age;  //年龄
  char group;  //所在学习小组
  float score;  //成绩
} stu1, stu2;
1
2
3
4
5
6
7

如果只需要 stu1、stu2 两个变量,后面不需要再使用结构体名定义其他变量,那么在定义时也可以不给出结构体名

struct{  //没有写 stu
  char *name;  //姓名
  int num;  //学号
  int age;  //年龄
  char group;  //所在学习小组
  float score;  //成绩
} stu1, stu2;
1
2
3
4
5
6
7

# 结构体与结构体变量的区别

  1. 结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间;
  2. 结构体变量才包含了实实在在的数据,需要内存空间来存储。

注意

注意在编译器的具体实现中,各个成员之间可能会存在缝隙,对于 stu1、stu2,成员变量 group 和 score 之间就存在 3 个字节的空白填充(见下图)。这样算来,stu1、stu2 其实占用了 17 + 3 = 20 个字节

# 成员的获取与赋值

#include <stdio.h>

int main()
{
	/*【声明结构体】*/
	struct stu {
		char *name;
		int age;
		float score;
	};
	/*【声明结构体变量】*/
	struct stu stu1, stu2;

	/*上面代码等价于*/
	/*【声明结构体并同时声明结构体变量】*/
	/*
	* struct stu {
	*	char *name;
	*	...
	* } stu1, stu2;
	*/

	/*【给结构体成员赋值】*/
	stu1.name = "Jack";
	stu1.age = 18;
	stu1.score = 138.5;

	/*可以更精简一点,上面代码等价于*/
	/*【声明结构体并同时声明结构体变量并同时给结构体成员赋值】*/
	/*
	* struct {
	*	char *name;
	*	...
	* } stu1, stu2 = { "Jack", 18, 138.5};
	*/

	/*【读取结构体成员的值】*/
	printf("性名:%s\n年龄:%d\n成绩:%f\n", stu1.name, stu1.age, stu1.score);
}
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

注意

上例中整体赋值仅限于定义结构体变量的时候,在使用过程中只能对成员逐一赋值,这和数组的赋值非常类似。

# 结构体数组

结构体数组: 是指数组中的每个元素都是一个结构体。在实际应用中,C语言结构体数组常被用来表示一个拥有相同数据结构的群体,比如一个班的学生、一个车间的职工等。

# 简单定义结构体数组

struct stu{
    char *name;  //姓名
    int age;  //年龄
    float score;  //成绩
}class[5];
// 表示一个班级有5个学生。
1
2
3
4
5
6

# 定义时同时初始化

结构体数组在定义的同时也可以初始化

struct stu{
    char *name;  //姓名
    int age;  //年龄
    float score;  //成绩
}class[3] = {
    {"张三", 18, 145.0},
    {"李四", 19, 130.5},
    {"王五", 18, 148.5},
};
1
2
3
4
5
6
7
8
9

# 省略数组长度

当对数组中全部元素赋值时,也可不给出数组长度

struct stu{
    char *name;  //姓名
    int age;  //年龄
    float score;  //成绩
}class[] = {
    {"张三", 18, 145.0},
    {"李四", 19, 130.5},
    {"王五", 18, 148.5},
};
1
2
3
4
5
6
7
8
9

# 使用结构体数组中元素的成员

  1. 单独初始化: class[0].name = "张三";
  2. 获取: int liSiAge = class[1].age。

# 综合示例

#include <stdio.h>

/*1. 打印班级表格*/
/*2. 计算全班学生的总成绩、平均成绩和以及 140 分以下的人数*/
int main()
{
	struct stu {
		char* name;
		int age;
		float score;
	} class[] = {
		{"张三", 18, 145.0},
		{"李四", 19, 130.5},
		{"王五", 18, 148.5},
		{"陈六", 17, 139.0},
		{"张七", 17, 144.5}
	};

	int len = sizeof(class) / sizeof(struct stu), _140num = 0;
	float sum = 0, average = 0;
	printf("姓名\t年龄\t成绩\t\n");
	for (int i = 0; i < len; i++) {
		/*打印班级表格*/
		printf("%s\t%d\t%.2f\t\n", class[i].name, class[i].age, class[i].score);

		/*计算*/
		sum += class[i].score;
		if (class[i].score < 140) {
			_140num++;
		}
	}
	average = sum / len;
	printf("班级总成绩:%.2f\n班级平均成绩:%.2f\n140 分以下的人数:%d\n", sum, average, _140num);
	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

打印结果

注意

在做本题时,遇到一个坑,C语言为强类型语言,声明时的数据类型在使用时要用对应的数据类型,比如声明时 float sum;,在打印时一定要用 %f(上例中为%.2f表示单精度浮点型保留两位小数),而不能用 %d

# 结构体指针

当一个指针变量指向结构体时,我们就称它为结构体指针

struct 结构体名 *变量名;

跟定义结构体变量时基本一样。

# 定义一个结构体指针

//结构体
struct stu {
    char *name;  //姓名
    int age;  //年龄
    float score;  //成绩
} stu1 = { "Tom", 18, 136.5 };
// 结构体指针
struct stu *pstu = &stu1;

/*可以简写*/
//结构体
struct stu {
    char *name;  //姓名
    int age;  //年龄
    float score;  //成绩
} stu1 = { "Tom", 18, 136.5 }, *pstu = &stu1;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

注意

  1. 结构体变量名和数组名不同,数组名在表达式中会被转换为数组指针,而结构体变量名不会,无论在任何表达式中它表示的都是整个集合本身,要想取得结构体变量的地址,必须在前面加 &;
  2. 万万不可直接取一个结构体名的,也不能将它赋值给其他变量,如下:
struct *pstu = &stu // (X)
// 因为结构体不占内存,只有结构体变量才占内存
struct *pstu = &stu1
1
2
3

# 获取结构体成员

  1. 一般形式: (*pointer).memberName
  2. 常用形式: pointer -> memberName

注意

  • 第一种形式中,因为 . 的优先级高于 *,所以一定别忘了括号;
  • 第二种写法中,-> 是一个新的运算符,可以通过结构体指针直接取得结构体成员,这也是 -> 在C语言中的唯一用途。

# 示例

  1. 结构体指针的使用
#include <stdio.h>

/*使用结构体指针*/
int main() {
	struct stu
	{
		char *name;
		int age;
		float score;
	} stu1 = { "Tom", 24, 135.5 }, *p = &stu1;

	/*使用普通结构体变量成员*/
	printf("姓名:%s\n年龄:%d\n成绩:%.2f\n", stu1.name, stu1.age, stu1.score);
	/*使用结构体指针访问成员*/
	printf("姓名:%s\n年龄:%d\n成绩:%.2f\n", p->name, p->age, p->score);
	/*二者打印结果一致*/
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  1. 使用结构体数组指针
#include <stdio.h>

int main()
{
	struct str {
		char *name;
		int age;
		float score;
	} class[] = {
		{"张三", 18, 145.0},
		{"李四", 19, 130.5},
		{"王五", 18, 148.5},
		{"陈六", 17, 139.0},
		{"张七", 17, 144.5}
	}, *p = class;

	int len = sizeof(class) / sizeof(struct str);
	for (int i = 0; i < len; i++, p++) {
		printf("姓名:%s\t年龄:%d\t成绩:%.1f\t\n", p->name, p->age, p->score);
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 结构体指针作为函数参数

结构体变量名代表的是整个集合本身,作为函数参数时传递的整个集合,也就是所有成员,而不是像数组一样被编译器转换成一个指针,最好的办法就是使用结构体指针,这时由实参传向形参的只是一个地址,非常快速

#include <stdio.h>
/*结构体指针作为函数参数*/
struct stu {
	char* name;
	int age;
	float score;
} class[] = {
	{"张三", 18, 145.0},
	{"李四", 19, 130.5},
	{"王五", 18, 148.5},
	{"陈六", 17, 139.0},
	{"张七", 17, 144.5}
};
/*计算全班学生的总成绩、平均成绩和以及 140 分以下的人数*/
void stuMath(struct stu *p, int len)
{
	float sumScore = 0;
	int _140num = 0;
	for (int i = 0; i < len; i++)
	{
		sumScore += (p + i)->score;
		if ((p + i)->score < 140)
		{
			_140num++;
		}
	}
	printf("总成绩:%.1f\n平均成绩:%.1f\n140分以下的人数:%d\n", sumScore, sumScore/len, _140num);
}

int main()
{
	int len = sizeof(class) / sizeof(struct stu);
	stuMath(class, len);
	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