前言:
在C语言中,结构体是一种特殊的数据类型。在C++没有出现之前,C语言就提供了类似于C++中class的用法,但很多人学完C语言,还不清楚结构体的用法,以及如何计算结构体的大小。如果说指针是C语言的灵魂,那么结构体的使用就是三板斧,吃遍天,掌握结构体的使用对于我们使用C语言至关重要。今天将会以最简单的方式让大家学会如何使用结构体,创作不易,如对您有帮助,辛苦三连~
《1》结构体定义:
结构体的定义:
(简单来讲就是类似于int的数据类型,只是结构体类型可以包含多种
常用的数据类型,这样在定义一个复杂的数据类型时会更加实用)
结构体是 C 语言中的一种复合数据类型,它允许您将多个不同类型的变量组合在一起,
以便作为一个单独的实体进行处理。结构体可以包含不同类型的成员变量,这些成员变
量可以是基本类型(如整数、浮点数等)或其他结构体类型。
结构体的定义使用 struct 关键字,然后在大括号中列出结构体的成员变量。以下是一
个示例:
struct Person {
char name[20];
int age;
float height;
};
在上面的示例中,我们定义了一个名为 Person 的结构体,它有三个成员变量:name、
age 和 height。name 是一个字符数组,用于存储人的姓名;age 是一个整数,用于
存储人的年龄;height 是一个浮点数,用于存储人的身高。
《2》结构体的使用方法:
结构体的使用:
要使用结构体,您可以先声明一个结构体变量,然后通过点操作符 . 来访问结构体的成员变量。
以下是一个示例:
#include <stdio.h>
#include <string.h>
//定义一个结构体
struct Person {
char name[20];
int age;
float height;
};
int main() {
struct Person person1; //声明一个 Person 类型的结构体变量,Person是结构体数据类型,
//表示是一个Person类型的数据,类似于int/char,person1
是结构体名
// 初始化结构体成员变量
strcpy(person1.name, "John");
person1.age = 25;
person1.height = 1.75;
// 输出结构体成员变量的值
printf("Name: %s\n", person1.name);
printf("Age: %d\n", person1.age);
printf("Height: %.2f\n", person1.height);
return 0;
}
在上面的示例中,我们首先声明了一个 Person 类型的结构体变量 person1。然后,我们使用
strcpy 函数将字符串 "John" 复制到 person1.name 中,将整数值 25 赋给 person1.age,
将浮点数值 1.75 赋给 person1.height。最后,我们使用 printf 函数输出结构体成员变量的值。
结构体的用途包括但不限于:组织和管理相关的数据、创建复杂的数据结构、传递多个相关的值作为
函数参数等。结构体提供了一种灵活和方便的方式来处理和操作多个相关的数据。
《3》typedef+结构体:
第二种常见的结构体使用方法:
typedef 是 C 语言中的一个关键字,用于为已有的数据类型取一个新的名称。它的语法如下:
typedef 原类型 新类型;
在定义一些复杂类型时,给结构体取名字可能会很长,这时可以用typedef给结构体取别名,
达到简洁易读的效果,在实际的开发中,也是会经常用到的。
以下是一个使用 typedef 定义结构体别名的示例:
#include <stdio.h>
typedef struct {
char name[20];
int age;
float height;
} Person;
int main() {
Person person1; // 使用 Person 别名声明结构体变量
// 初始化结构体成员变量
strcpy(person1.name, "John");
person1.age = 25;
person1.height = 1.75;
// 输出结构体成员变量的值
printf("Name: %s\n", person1.name);
printf("Age: %d\n", person1.age);
printf("Height: %.2f\n", person1.height);
return 0;
}
在上面的示例中,我们使用 typedef 关键字为 struct Person 定义了一个新的别名 Person。
然后,我们可以使用 Person 别名来声明结构体变量 person1。这样,我们就可以直接使用
Person 来代替 struct Person,使代码更加简洁和可读。
typedef 还可以用于为其他类型定义别名,例如枚举类型、函数指针等。它提供了一种方便的方
式来创建自定义的数据类型,以适应特定的需求。
《4》计算结构体大小:
要计算结构体的大小,可以使用 sizeof 运算符。sizeof 运算符可以返回一个对象或类型
的大小(以字节为单位)。以下是一个示例:
#include <stdio.h>
typedef struct {
unsigned int protocol_number;
unsigned char address[20];
unsigned int address_length;
// 其他成员...
} ProtocolTable;
int main() {
ProtocolTable my_table;
size_t size = sizeof(my_table);
printf("Size of ProtocolTable: %zu bytes\n", size);
return 0;
}
在上面的示例中,我们定义了一个结构体 ProtocolTable,然后使用 sizeof 运算符计算结构体
my_table 的大小,并将结果赋值给变量 size。最后,我们使用 %zu 格式说明符将 size 的值
打印出来。
请注意,sizeof 运算符返回的是一个 size_t 类型的值,因此我们使用 %zu 格式说明符来打印
这个值。另外,sizeof 运算符计算的是结构体的大小,包括所有成员变量的大小以及可能的填充字节。
《5*》结构体最大字节对齐:
结构体最大字节对齐是程序员面试或者笔试必会被考到的题,同时字节对齐也是非常必要的操作,避免了内存的浪费,也方便了数据的存取。
结构体的字节对齐是为了优化内存访问的效率。在结构体中,每个成员变量都会占用一定的内存空间,
而字节对齐规则会决定成员变量在内存中的起始地址和对齐方式。
在大多数情况下,结构体的字节对齐方式是按照成员变量的大小进行对齐的,即成员变量的起始地址
必须是其大小的整数倍。例如,一个 char 类型的成员变量需要占用 1 字节的内存,而一个 int
类型的成员变量需要占用 4 字节的内存,因此 int 类型的成员变量的起始地址必须是 4 的倍数。
但是,有时候编译器会根据平台的要求或者优化策略进行额外的字节对齐,以提高内存访问的效率。
这可能会导致结构体的大小比成员变量的大小之和要大。
以下是一个与结构体最大字节对齐相关的笔试题:
#include <stdio.h>
struct Data {
char c;
int i;
double d;
};
int main() {
struct Data data;
printf("Size of struct Data: %zu bytes\n", sizeof(data));
return 0;
}
在上面的代码中,我们定义了一个结构体 Data,它包含一个 char 类型的成员变量 c、
一个 int 类型的成员变量 i,以及一个 double 类型的成员变量 d。
请问,这个结构体的大小是多少字节?为什么?
答案是 24 字节。原因是大多数编译器会根据成员变量的大小和对齐要求进行字节对齐。
在这个例子中,char 类型的成员变量 c 占用 1 字节,int 类型的成员变量 i 占用
4 字节,double 类型的成员变量 d 占用 8 字节。
由于 int 类型的成员变量 i 大小为 4 字节,所以它的起始地址必须是 4 的倍数。
因此,在 char 类型的成员变量 c 后面会有 3 个字节的填充空间,使得 int 类型的
成员变量 i 起始地址为 4 的倍数。同样,double 类型的成员变量 d 大小为 8 字节,
所以在 int 类型的成员变量 i 后面会有 4 个字节的填充空间,使得 double 类型的
成员变量 d 起始地址为 8 的倍数。
因此,结构体的大小为 1 字节(char 类型的成员变量 c)+ 3 字节的填充空间 +
4 字节(int 类型的成员变量 i)+ 4 字节的填充空间 + 8 字节(double 类型的成员变量 d)= 24 字节。