目录
一.为什么要使用结构体
二.结构体的声明和初始化
三.结构体的使用
举例:冒泡排序
(1)对ElemType的介绍
(2)使用结构体数组
(3)结构体指针
四.结构体内存大小
一.为什么要使用结构体
1.C语言中的数据结构有整形(int,long,......),浮点型(flaot,double),字符型(char),布尔类型,数组,字符串等,但是这些在实际应用中是不够的。
2.在前面见到的程序中,所用的变量大多是互相独立,互不干扰的。但在实际应用中,很多数据之间是有内在联系的。例如,一个学生的一些信息(学号,姓名,性别,年龄,成绩等)
3.C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,成为结构体。
二.结构体的声明和使用
1.结构体类型的声明
1.1声明一个结构体类型的一般形式:
struct 结构体名
{成员列表};
举例:
struct Student{
int age;
char name;
int score;
char sex;
char addr;
};
注意:
结构体类型的名字是由一个关键字struct和结构体名组合而成的(例如:struct Student)。结构体名是由用户指定的,又称“结构体标记”(structure tag),以区别于其他类型的结构体类型。上面的结构体声明中Student就是结构体名(结构体标记)。
花括号内部:(结构体成员)
对各成员进行类型声明: 类型名 成员名;
“成员表列”也称为“域表”,每一个成员是结构体中的一个域。成员名命名规则与变量名相同。
说明:
(1)结构体类型并非只有一种,而是可以设计出许多结构体类型。
(2)成员可以属于另一个结构体的类型。
1.2定义结构体类型变量
(1)先声明结构体变量,再定义该类型的变量
用声明的结构体变量来定义变量:
struct Student student1,student2;
结构体类型名 结构体变量名
(2)在声明的同时定义变量
一般形式:
struct 结构体名
{成员列表
}变量名列表;
举例:
struct Student{
int age;
char name;
int score;
char sex;
char addr;
}student1,student2;
1.3结构体的重命名
typedef+变量的声明;
例如:
typedef struct student {
const char*name;
int score;
} student,*PStu;
在之后的代码中可直接使用student为 变量类型。
2.结构体变量的初始化
再定义结构体变量时,可以对它初始化,即赋予初始值。然后可以引用这个变量,例如输出它的成员的值。
举例:
#include<stdio.h>
int main(){
typedef struct Student{
int age;
char name;
int score;
char sex; //对结构体进行重命名
}student;
student s[]={10,"zs",100,"男"}//对结构体变量进行初始化
return 0;
}
2.1对结构体变量中成员的引用
引用方式:
(1)结构体变量名.成员名
"."是成员运算符,它在所有的运算符中的优先级最高,因此可以把student.name作为一个整体来看待,相当于一个变量。
注意:不能企图通过输出结构体变量名来达到输出结构体变量所有成员的值。
例如:printf("%s\n",student);//这个是错误的
只能对结构体变量中的各个成员分别进行输入和输出
(2)结构体变量名->成员名
“->”是指向结构体成员运算符。
使用:printf("%s\n",student->name);
补充;
(1)对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型可以进行的运算)
(2)同类的结构体变量可以互相赋值
(3)可以引用结构体变量成员的地址,也可以使用结构体变量的地址(说明:结构体变量的地址主要用做函数参数,传递结构体变量的地址)
——摘自《C语言程序设计》
三.结构体的使用
举一个例子:冒泡排序
#include<stdio.h>
#include<string.h>
//typedef 类型重命名
typedef struct student {
const char*name;
int score;
} student,*PStu;
typedef student ElemType;
void swap(ElemType* a, ElemType* b) {
ElemType temp = *a;
*a = *b;
*b = temp;
}
void BubbleSort(ElemType* s, int len) {
int flag = 0;
for (int i = 0; i < len; i++) {
flag = 0;
for (int j = 0; j < len - 1 - i; j++) {
if (s[j].score > s[j + 1].score) { //对成员的引用
swap(&s[j], &s[j + 1]);
flag = 1;
}
else if (s[j].score == s[j + 1].score) {
if (strcmp(s[j].name ,s[j + 1].name) < 0) {
swap(&s[j], &s[j + 1]);
}
}
}
if (!flag) {
break;
}
}
}
int main() {
student s[] = { {"zs",100},{"ls",100},{"ww",99} };
int len = sizeof(s) / sizeof(s[0]);
BubbleSort(s, len);
for (int i = 0; i < len; i++) {
printf("%s %d\n", s[i].name, s[i].score); //对结构体成员变量的输出
}
}
(1)ElemType的介绍
在《数据结构》中,关于数据元素的类型定义均用“ElemType e;”来表示,其中e是表示数据元素的变量,而ElemType则是它的类型,ElemType的含义就是“数据元素的类型”,是一个抽象的概念,是表示我们所要使用的数据元素应有的类型。
ElemType 在程序定义中代表某一不确定的类型,一种抽象的数据类型。为了程序便于修改,让elem代表多种数据类型。它代表所有可能的数据类型。在算法中,出特别声明外,规定ElemType的默认是int型。
(2)结构体数组
一个结构体变量中可以存放一组有关联的数据,如需要存放多组有关联的数据,则需要使用结构体数组。
在上述冒泡排序中{“zs”,100}{"ls",100}{"ww",99}三组数据存放在一个数组中即为结构体数组。
1)定义结构体数组的一般形式:
struct 结构体名
{成员列表}数组名[数组长度];
或 先声明一个结构体类型,在用此类型定义结构体数组:
结构体类型 数组名[数组长度];
2)对结构体数组初始化的形式是在定义数组的后面加上:={初值表列};
(3)结构体指针
指向结构体对象的指针变量既可以指向结构体变量,也可以指向结构体数组中的元素。指针变量的基类型必须与结构体变量的类型相同。
如果p指向一个结构体变量stu,一下3中用法等价:
1)stu.成员名 2)(*p).成员名 3)p->成员名
指向结构体数组的指针
(1)声明结构体类型struct student,并定义结构体数组,同时初始化
(2)定义一个指向struct student 类型数据的指针变量p
(3)使p指向结构体数组的首元素,输出它指向的元素中有关信息
(4)使p指向结构体数组的下一个元素,输出它指向的元素中的有关信息
(5)再使p指向结构体数组的下一个元素,输出它指向的元素中的有关信息
用结构体变量和结构体变量的指针作函数参数
将一个结构体变量的值传递给另一个函数,有三种方法:
(1)用结构体变量的成员做参数。例如将stu.name作函数实参,将实参值传递给形参。用法和普通变量作实参一样。应当注意实参与形参的类型保持一致。
(2)用结构体变量作实参。
(3)用指向结构体变量(或数组元素)的指针作实参,将结构体变量(或数组元素)的地址传给形参。
——摘自《C语言程序设计》
四.结构体内存的大小
(1)变量首地址,必须是MIN{结构体最大基本数据类型,指定对齐方式}所占字节数的整数倍。
(2)每个成员变量相对于结构体首地址的偏移量,都是MIN{该成员变量整数倍,指定对齐方式}
(3)结构体总大小为 MIN{结构体最大基本数据类型整数倍,指定对齐方式的整数倍}
VS默认对齐方式为8个字节,Linux系统默认对齐方式为4个字节
举例分析内存大小:
#pragma pack(4)
typedef struct Student{
short a; //2
char c; //1+1
short b; //2
char d; //1
char f;//1
short e;//2
}Student;
#pragma pack()
//共计10个字节,所以内存大小为10个字节
#pragma pack(8)
typedef struct Student {
int a; //4
char c;//1+1
short b;//2
long long d;//8
char e;//1+7
}Student;
#pragma pack()
//共计24个字节
根据规则得出结构体内存大小。