首页 > 编程笔记 > C语言笔记(精华版) 阅读:1198

C语言结构体用法详解(包括定义、初始化、赋值、成员访问等细节)

通义灵码

在现实生活中,我们经常需要用多个不同类型的数据来描述一个对象,比如要描述一个学生,需要记录他的姓名、学号、年龄、成绩等信息;要描述一个商品,需要记录它的名称、价格、库存等信息。


如果使用普通的变量来存储这些数据,不仅需要定义很多独立的变量,而且这些变量之间缺乏关联性,不利于数据的管理和使用。为了解决这个问题,C语言提供了结构体(Structure)这种复合数据类型。
 

结构体可以将多个不同类型的数据组织在一起,形成一个新的数据类型。这些数据可以是基本数据类型(如 int、float、char 等),也可以是其他的结构体类型。每个数据在结构体中被称为成员或者字段。通过结构体,我们可以将所有相关的数据打包成一个整体,更好地表达数据之间的逻辑关系。

结构体的定义

要使用结构体,需要先定义结构体类型,它的基本语法格式如下:

struct 结构体名称 {
    成员类型1 成员名称1;
    成员类型2 成员名称2;
    ...
    成员类型n 成员名称n;
};

struct 是定义结构体的关键字,结构体名称用于标识这个新的数据类型,花括号内部包含了若干成员变量的声明。每个成员变量都有自己的类型和名称,它们之间用分号分隔。
 

下面通过一个具体的例子来说明结构体的定义和使用。假设我们要开发一个学生信息管理系统,需要存储学生的基本信息:

  1. struct Student {
  2. char name[50]; // 姓名
  3. int id; // 学号
  4. int age; // 年龄
  5. float score; // 成绩
  6. };

这里定义了一个名为 Student 的结构体类型,它包含 4 个成员。注意,为了和变量名、函数名进行区分,结构体名的首字母一般要大写。

结构体的使用

结构体是一种类型,而不是变量,不能赋值;定义了结构体类型后,还需要声明结构体变量才能使用。

声明结构体变量

声明结构体变量有两种方式:先定义类型再声明变量,或者在定义类型的同时声明变量。

  1. // 方式 1:先定义类型,再声明变量
  2. struct Student s1; //使用了已经定义的结构体类型 Student
  3.  
  4. // 方式 2:定义类型的同时声明变量
  5. struct Student {
  6. char name[50];
  7. int id;
  8. int age;
  9. float score;
  10. } s1, s2;

初始化结构体成员

结构体变量的成员可以在声明时初始化,也可以在声明后单独赋值。初始化时要注意成员的顺序必须与定义时的顺序一致。

  1. // 声明时初始化
  2. struct Student s1 = {"张三", 10001, 18, 85.5};
  3.  
  4. // 声明后单独赋值
  5. struct Student s2;
  6. strcpy(s2.name, "李四"); // 字符数组不能直接赋值,需要使用 strcpy
  7. s2.id = 10002;
  8. s2.age = 19;
  9. s2.score = 92.5;

访问结构体成员

如果是结构体变量,可以使用点运算符.访问结构体成员;如果是结构体指针,则使用箭头运算符->访问结构体成员。请看下面的例子:

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. struct Student {
  5. char name[50];
  6. int id;
  7. int age;
  8. float score;
  9. };
  10.  
  11. int main() {
  12. struct Student s1 = {"张三", 10001, 18, 85.5};
  13. struct Student *ptr = &s1;
  14. // 使用点运算符访问成员
  15. printf("姓名:%s\n", s1.name);
  16. printf("学号:%d\n", s1.id);
  17. // 使用箭头运算符访问成员
  18. printf("年龄:%d\n", ptr->age);
  19. printf("成绩:%.1f\n", ptr->score);
  20. return 0;
  21. }

输出结果:

姓名:张三
学号:10001
年龄:18
成绩:85.5

结构体变量之间的赋值

结构体变量之间可以直接赋值,这将复制所有成员的值,也即把一个结构体的内存直接拷贝给另一个结构体。
 

但是需要注意,这是一种浅拷贝,如果结构体中包含指针成员,赋值操作只会复制指针的值,而不会复制指针指向的数据,这种情况下需要手动进行深拷贝。


请看下面的例子:

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. struct Student {
  5. char name[50];
  6. int age;
  7. float score;
  8. };
  9.  
  10. int main() {
  11. struct Student stu1 = {"张三", 18, 92.5};
  12. struct Student stu2;
  13. // 结构体变量赋值
  14. stu2 = stu1;
  15. // 修改 stu2 的成员
  16. strcpy(stu2.name, "李四");
  17. stu2.age = 20;
  18. printf("stu1:%s, %d, %.1f\n", stu1.name, stu1.age, stu1.score);
  19. printf("stu2:%s, %d, %.1f\n", stu2.name, stu2.age, stu2.score);
  20. return 0;
  21. }

输出结果:

stu1:张三, 18, 92.5
stu2:李四, 20, 92.5

结构体的嵌套定义

结构体还可以嵌套定义,即一个结构体的成员可以是另一个结构体,这种特性使得我们可以构建更复杂的数据类型。请看下面的代码:

  1. struct Date {
  2. int year;
  3. int month;
  4. int day;
  5. };
  6.  
  7. struct Student {
  8. char name[50];
  9. int age;
  10. struct Date birthday; // 结构体嵌套
  11. float score;
  12. };
  13.  
  14. // 嵌套结构体的初始化
  15. struct Student stu = {
  16. "张三",
  17. 18,
  18. {2005, 8, 15}, // 嵌套的结构体成员也用花括号
  19. 92.5
  20. };

使用 typedef 重命名

在实际编程中,为了简化代码,我们经常使用 typedef 关键字为结构体类型定义一个新的类型名,这样在声明变量时就可以省略 struct 关键字。请看代码:

  1. typedef struct Student {
  2. char name[50];
  3. int age;
  4. float score;
  5. } Stu; // 定义别名 Stu
  6.  
  7. // 使用别名定义变量,不需要再写 struct
  8. Stu stu1 = {"张三", 18, 92.5};
  9. Stu stu2;

结构体类型的大小

需要注意的是,结构体的大小不一定等于所有成员大小的简单相加。由于内存对齐的原因,编译器可能会在成员之间插入一些填充字节。如果需要了解结构体的实际大小,可以使用 sizeof 运算符:

  1. #include <stdio.h>
  2.  
  3. struct Test {
  4. char c; // 1 字节
  5. int i; // 4 字节
  6. double d; // 8 字节
  7. };
  8.  
  9. int main() {
  10. printf("结构体大小:%zu 字节\n", sizeof(struct Test));
  11. return 0;
  12. }

输出结果可能是:

结构体大小:16 字节

虽然成员大小加起来是 13 字节,但由于内存对齐,实际的结构体大小是 16 字节。这种内存对齐机制是为了提高程序的运行效率,但同时也会占用更多的内存空间。

 

总起来说,结构体是一种自定义的、复合的数据类型,而不是变量。变量可以直接使用,而数据类型还需要声明变量才能使用。理解这一点非常重要,这是结构体的本质。

结构体在C语言编程中有着广泛的应用,通过合理使用结构体,我们可以更好地组织和管理复杂的数据。在开发较复杂的程序时,结构体常常与其他高级特性(如动态内存分配、文件操作等)结合使用,构建更复杂的数据结构和算法。

相关文章