C语言struct的用法(非常详细,附带示例)
在实际编程中,我们经常需要将多个相关的数据组织在一起,但数组只能存储相同类型的数据,这时就需要用到结构体。结构体(struct)是一种用户自定义的数据类型,它允许我们将不同类型的数据(比如整型、浮点型、字符型等)组合成一个整体,形成一个新的、复合的数据类型。
也就是说,数据结构可以包含多个成员,每个成员都有自己的名称和类型。
举个例子,假设我们要记录学生的信息,包括学号、姓名、性别和成绩,这些信息的数据类型并不相同,如果分别定义变量会很麻烦,而使用结构体就可以将这些信息很好地组织在一起。这种组织方式不仅使程序的结构更加清晰,而且便于数据的管理和维护。
结构体的定义
结构体类型需要先定义,然后才能使用。结构体的定义语法如下:
struct 结构体名 { 成员类型1 成员名1; 成员类型2 成员名2; // ... 更多成员 };
这里的 struct 是关键字,专门用来定义结构体;结构体名
是我们给这个新的复合类型起的名字;花括号内部列出了结构体的所有成员,每个成员都有自己的类型和名称,就像普通的变量声明一样。
值得注意的是,结构体定义的末尾需要加上分号,这是很多初学者容易忽略的细节。
让我们用一个具体的例子来说明结构体的定义:
struct Book { char title[50]; char author[50]; int year; float price; };
在这个例子中,我们定义了一个名为 Book 的结构体,它包含四个成员:title 和 author 是字符数组,用于存储书名和作者名;year 是整数类型,用于存储出版年份;price 是浮点数类型,用于存储书的价格。
结构体变量的声明
定义了结构体后,我们就可以声明该类型的变量了。有两种方式可以做到这一点:一种是先定义结构体,先后再声明变量;另一个是在定义结构体的同时声明变量。
//方式1:先定义结构体再声明变量,也即使用结构体名来声明变量 struct Book book1; // 声明一个结构体变量 struct Book book2, book3; // 可以一次声明多个变量 // 方式2:在定义结构体的同时声明变量 struct Book { char title[50]; char author[50]; int year; float price; } book4, book5;
结构体变量的初始化/赋值
结构体变量的初始化可以在声明时进行,也可以在声明后单独进行,以下是几种常见的初始化方式。
声明时直接初始化
这是最直接的初始化方式。我们可以在声明结构体变量的同时,使用大括号{ }
来指定各个成员的初始值。成员的初始化顺序应与结构体定义中的顺序一致。
struct Book book1 = {"C Programming", "Dennis Ritchie", 1978, 29.99};
这种方法简洁明了,但要求我们清楚地记住结构体成员的顺序。如果结构体成员较多或者顺序容易混淆,这种方法可能会增加出错的风险。
声明后逐个成员赋值
有时我们可能需要在声明结构体变量后的某个时刻再对其进行初始化。这种情况下,我们可以先声明结构体变量,然后逐个为其成员赋值。
struct Book book2; strcpy(book2.title, "The C Programming Language"); strcpy(book2.author, "Brian W. Kernighan"); book2.year = 1988; book2.price = 59.99;
通过结构体变量访问成员时,需要使用点号.
运算符。
注意,对于字符数组成员(如 name),我们需要使用 strcpy 函数来赋值,而不能直接使用赋值运算符。
使用指定初始化器
C99 标准引入了指定初始化器,这种方法允许我们通过成员名称来初始化结构体,而不必严格遵守成员的定义顺序。即使以后在定义中修改了各个成员的顺序,也不用修改代码。
struct Book book3 = { .title = "C: A Modern Approach", .author = "K. N. King", .year = 2008, .price = 79.99 };
结构体成员的访问
访问结构体成员有两种方式:使用点运算符.
和箭头运算符->
。
通过结构体变量访问成员时需要使用点号运算符,它的语法格式如下:
结构体变量名.成员名
比如,要打印 book1 的标题,我们可以这样做:
printf("Book title: %s\n", book1.title);
通过结构体指针访问成员时需要使用箭头远算符,它的语法格式如下:
结构体指针->成员名
例如,要打印 book1 的作者,我们可以这样做:
struct Book *pBook = &book1; printf("Book author: %s\n", pBook->author);
这里,pBook->author 等价于 (*pBook).author,但前者的写法更加简洁和易读。
综合示例
下面通过一个完整的示例来综合运用结构体的各项知识:
#include <stdio.h> #include <string.h> //定义学生结构体 struct Student { int id; char name[50]; int age; float score; }; //函数声明 void printStudent(struct Student stu); void updateScore(struct Student *p, float newScore); int main() { //创建并初始化结构体变量 struct Student stu1 = {1001, "张三", 18, 85.5}; //创建第二个学生,并逐个赋值 struct Student stu2; stu2.id = 1002; strcpy(stu2.name, "李四"); stu2.age = 19; stu2.score = 92.5; //打印学生信息 printf("修改前的信息:\n"); printStudent(stu1); printStudent(stu2); //修改学生成绩 updateScore(&stu1, 88.5); updateScore(&stu2, 95.0); //打印修改后的信息 printf("\n修改后的信息:\n"); printStudent(stu1); printStudent(stu2); return 0; } //打印学生信息的函数 void printStudent(struct Student stu) { printf("学号:%d, 姓名:%s, 年龄:%d, 成绩:%.1f\n", stu.id, stu.name, stu.age, stu.score); } //修改学生成绩的函数 void updateScore(struct Student *p, float newScore) { p->score = newScore; }
运行结果:
修改前的信息: 学号:1001, 姓名:张三, 年龄:18, 成绩:85.5 学号:1002, 姓名:李四, 年龄:19, 成绩:92.5 修改后的信息: 学号:1001, 姓名:张三, 年龄:18, 成绩:88.5 学号:1002, 姓名:李四, 年龄:19, 成绩:95.0
在这个示例中,我们定义了一个学生结构体,创建了两个学生变量并分别使用不同的方式进行初始化,然后通过函数来打印和修改学生信息。在 printStudent 函数中使用点号运算符访问结构体成员,在 updateScore 函数中使用箭头运算符通过指针修改结构体成员。这个示例完整地展示了结构体的定义、初始化、成员访问以及在函数中的使用方法。
总结
C语言结构体(struct)是一种自定义的、复合的数据类型,它可以包含多个成员,每个成员都有自己的类型和名字。
注意,结构体是一种类型,定义结构体以后还需要声明变量,然后才能使用。
使用结构体时,有几点需要注意:
- 结构体的大小通常大于其所有成员大小的总和,这是因为编译器可能会在成员之间插入填充以确保内存对齐。
- 结构体变量之间的赋值是允许的,但这会导致所有成员的逐一复制,对于大型结构体来说可能会影响性能。
- 在函数间传递结构体时,通常建议使用指针,这样可以避免不必要的大量数据复制。