结构体

254 阅读5分钟

结构体(Struct)是C语言中一种非常重要的数据类型,它允许我们将不同类型的数据组合在一起,形成一个新的复合数据类型。也就是说我们可以通过结构体自定义所需的不同数据类型的集合,这个集合的不同数据用来描述一类事物的特征。

比如:定义公司的员工(staff),用来辨别不同的员工需要不同的信息(名字,性别,年龄,身高,体重,电话号码...)众所周知,数组是相同类型元素的集合,只能存放同一类型的数据。所以,在面对具有复杂特征的对象时,数组并不能准确描述出所需信息。而结构体则弥补了这一不足。

结构体类型声明:

关键字(struct)+结构体变量/自定义类型名称(name)+

{ 数据类型 成员变量1;数据类型 成员变量2;数据类型 成员变量3.....}n1,n2;

结构体变量是结构体类型的实例。可以将结构体变量看作是一个包含多个成员变量的容器

成员变量可以是标量,数组,指针,甚至是其他的结构体。结构体的成员名可以与程序中的变量名相同,但两者实际上代表的是两种不同的信息。(结构体成员变量前需要明确结构体类型才能引用)。

1. 在函数外部声明

可以在函数外部声明结构体变量。这种方式适用于全局变量,可以在多个函数中使用。

image-20241115151646904.png

2.在函数内部声明

image-20241115153240970.png

当只需要在某个函数内部使用某个数据结构时,可以在该函数内部声明结构体变量。这样可以避免全局变量的使用,减少命名冲突,并且使代码更加模块化。

注意点:结构体声明相当于一个命令语句,所以声明后需要在最后加上分号(;)

同时,结构体变量之间也需要用分号隔开。

结构体的使用:

一般形式:

声明了结构体之后,我们就可以在程序中使用它来定义变量。例如:

struct Company p1 ;//声明
p1声明结构体

所定义的结构体变量,所占内存空间为所有成员变量的内存总和,地址用首成员变量的地址表示

image.png

结构体变量的初始化

若对一个结构体变量进行完全初始化,输入数据的顺序需要与声明结构体类型时顺序一一对应(C99标准允许对结构体进行单独初始化)

struct Company
//{
//	char Boss_name[20];
//	char Company_name[30];
//	int Staff_Number;
//	double area;
//};
struct Company p1 = { "张三","张三能力有限公司",66,33333.33 };
struct Company p={.name="张三"};//只对张三的名字进行初始化

注意:在未初始化的结构体中,系统会根据成员变量各自的类型进行初始化。数值型定义为0,字符型初始化为'\0',指针型成员初始化为NULL(空指针).

也可以通过点运算符(.)来访问结构体的成员并赋值:

strcpy(s1.name, "李丽");  // 给s1的name成员赋值
s1.age = 18;               // 给s1的age成员赋值
s1. telt= "18888888888";              // 给s1的tele成员赋值

s1.age相当于访问结构体变量中age成员变量的位置。

具体来说,s1.age 表示的是 s1 结构体变量中 age 成员的内存位置。可以对这个位置进行读取或写入操作。

同时,在C语言中,结构体是允许嵌套的。就比如一个结构体变量的特征,可以用另一个结构体变量来描述这时,需要通过多个点运算符分级访问(.)

image-20241115171443568.png

而在使用嵌套结构体变量时,对内部结构体变量的引用形式要用结构体声明时的变量名称。

//struct Company
//{
//	char Boss_name[20];
//	char Company_name[30];
//	int Staff_Number;
//	double area;
//};
//
//
//struct staff
//{
//	struct Company p;//结构体成员变量可以也为结构体
//	char sex[4];
//	char name[20];
//	int age;
//	char tele[12];
//	double salary;
//};
//
//void print1(struct staff* s)
//{
//	printf(" % s % s % d % s % lf", (*s).name, (*s).sex, (*s).age, (*s).tele, (*s).salary);
//}
//int main()
//{
//
//
//	struct Company p1 = { "张三","张三能力有限公司",66,33333.33 };
//	struct Company p2 = { "李四","李四能力无限公司",44,44444.44 };
//	struct staff s1 = { p1,"女","李丽",18,"18888888888",5479.5};
//	struct staff s2 = { p2,"男","王强",21,"19999999999",6758.6 };
//	printf("%s %s %d %lf\n", p1.Boss_name, p1.Company_name, p1.Staff_Number, p1.area);
//	printf("%s %s %s %d %s %lf\n", s1.p.Company_name, s1.sex, s1.name, s1.age, s1.tele, s1.salary);
//print1(&s1);
//}

image-20241115171859713.png

image-20241115171925457.png

对结构体内成员的引用

结构体地址+传参

传参要么传结构体本身,要么传结构体地址(传值/传址)

传值与结构体的一般用法一致。

函数形式:返回值类型+函数名(struct 结构体变量+形参)

使用:函数名(结构体名)

image-20241115175643774.png

当用结构体变量地址作函数参数时,对成员变量的访问用箭头运算符(->)解引用。//结构体指针->成员变量

image-20241115173233518.png 或者解引用后用点运算符访问。//结构体变量.成员变量

#include <stdio.h>
#include <string.h>

struct Student {
    char name[8];
    int C;
    int M;
    int E;
};

int main() {
    int N;
    scanf("%d", &N);
    struct Student students[N];
int i;

    // 读取学生信息
    for ( i = 0; i < N; i++) {
        scanf("%s %d %d %d", students[i].name, &students[i].C, &students[i].M, &students[i].E);
    }
int j;
    // 比较学生成绩
    for ( i = 0; i < N; i++) {
        for ( j = i + 1; j < N; j++) {
            int total_diff = abs(students[i].C + students[i].M + students[i].E - students[j].C - students[j].M - students[j].E);
            int C_diff = abs(students[i].C - students[j].C);
            int M_diff = abs(students[i].M - students[j].M);
            int E_diff = abs(students[i].E - students[j].E);

            if (C_diff <= 5 && M_diff <= 5 && E_diff <= 5 && total_diff <= 10) {
                if (strcmp(students[i].name, students[j].name) < 0) {
                    printf("%s %s\n", students[i].name, students[j].name);
                } else {
                    printf("%s %s\n", students[j].name, students[i].name);
                }
            }
        }
    }

    return 0;
}

image-20241115173932943.png