C语言结构体(struct
)详解
结构体概览表
功能 | 描述 |
---|---|
定义结构体 | 定义一个结构体类型 |
声明结构体变量 | 声明一个结构体变量 |
访问成员 | 使用点运算符(. )和箭头运算符(-> )访问成员 |
初始化结构体 | 在声明时初始化结构体 |
计算大小 | 使用sizeof 计算结构体的大小 |
作为函数参数 | 传递结构体或结构体指针作为函数参数 |
结构体嵌套 | 结构体中包含其他结构体 |
结构体与数组 | 结构体作为数组元素或包含数组的成员 |
内存对齐 | 结构体的内存对齐和填充 |
类型定义(typedef ) |
使用typedef 简化结构体声明 |
嵌入式应用 | 在嵌入式系统中使用结构体 |
拓展技巧 | 结构体指针运算和联合体比较 |
1. 结构体的基本概念
1.1 结构体定义
结构体通过struct
关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
struct Person {
char name[50];
int age;
float height;
};
在上面的示例中,定义了一个Person
结构体,其中包含三个成员:name
(字符数组)、age
(整数)和height
(浮点数)。
1.2 结构体变量声明
定义结构体后,可以声明结构体变量来使用它。例如:
struct Person person1;
这里声明了一个Person
结构体类型的变量person1
。
2. 结构体成员的访问
2.1 使用点运算符(.
)访问成员
可以通过点运算符(.
)访问结构体的成员变量。例如:
#include <stdio.h>
struct Person {
char name[50];
int age;
float height;
};
int main() {
struct Person person1;
// 初始化结构体成员
person1.age = 25;
person1.height = 175.5;
snprintf(person1.name, sizeof(person1.name), "Alice");
// 输出结构体成员
printf("Name: %s\n", person1.name);
printf("Age: %d\n", person1.age);
printf("Height: %.2f\n", person1.height);
return 0;
}
输出
Name: Alice
Age: 25
Height: 175.50
2.2 使用箭头运算符(->
)访问成员
如果结构体变量是指针类型,则可以通过箭头运算符(->
)访问其成员。例如:
#include <stdio.h>
struct Person {
char name[50];
int age;
float height;
};
void printPerson(struct Person *p) {
printf("Name: %s\n", p->name);
printf("Age: %d\n", p->age);
printf("Height: %.2f\n", p->height);
}
int main() {
struct Person person1 = {
"Bob", 30, 180.0};
struct Person *ptr = &person1;
printPerson(ptr);
return 0;
}
输出
Name: Bob
Age: 30
Height: 180.00
3. 结构体的初始化
3.1 结构体初始化
可以在定义结构体变量的同时进行初始化。例如:
#include <stdio.h>
struct Person {
char name[50];
int age;
float height;
};
int main() {
struct Person person2 = {
"Alice", 30, 160.0};
printf("Name: %s\n", person2.name);
printf("Age: %d\n", person2.age);
printf("Height: %.2f\n", person2.height);
return 0;
}
输出
Name: Alice
Age: 30
Height: 160.00
3.2 使用指定初始化器
C99标准引入了指定初始化器,可以按顺序或指定成员进行初始化。例如:
#include <stdio.h>
struct Person {
char name[50];
int age;
float height;
};
int main() {
struct Person person3 = {
.age = 40, .height = 180.0, .name = "Bob"};
printf("Name: %s\n", person3.name);
printf("Age: %d\n", person3.age);
printf("Height: %.2f\n", person3.height);
return 0;
}
输出
Name: Bob
Age: 40
Height: 180.00
4. 结构体的大小
结构体的大小取决于其成员的数量和类型,以及内存对齐的规则。可以使用sizeof
运算符来获取结构体的大小。例如:
#include <stdio.h>
struct Person {
char name[50];
int age;
float height;
};
int main() {
printf("Size of Person: %zu bytes\n", sizeof(struct Person));
return 0;
}
输出
在不同平台上的输出可能不同,例如:
- 32位系统:
Size of Person: 60 bytes
- 64位系统:
Size of Person: 64 bytes
5. 结构体作为函数参数
5.1 传递结构体的副本
结构体可以作为函数参数传递。如果传递的是结构体的副本,则会创建结构体的一个副本,可能会影响性能。
#include <stdio.h>
struct Person {
char name[50];
int age;
float height;
};
void printPerson(struct Person p) {
printf("Name: %s\n", p.name);
printf("Age: %d\n", p.age);
printf("Height: %.2f\n", p.height);
}
int main() {
struct Person person1 = {
"Alice", 30, 160.0};
printPerson(person1);
return 0;
}
输出
Name: Alice
Age: 30
Height: 160.00
5.2 传递结构体指针
为了提高效率,可以将结构体的指针传递给函数,这样只需传递指针而不是整个结构体。
#include <stdio.h>
struct Person {
char name[50];
int age;
float height;
};
void updateAge(struct Person *p, int newAge) {
p->age = newAge;
}
int main() {
struct Person person1 = {
"Bob", 30, 180.0};
updateAge(&person1, 35);
printf("Updated Age: %d\n", person1.age);
return 0;
}
输出
Updated Age: 35
6. 结构体的嵌套
结构体可以嵌套其他结构体。例如:
#include <stdio.h>
struct Address {
char street[100];
char city[50];
int postalCode;
};
struct Person {
char name[50];
int age;
struct Address address; // 嵌套的结构体
};
int main() {
struct Person person4 = {
"John",
28,
{
"123 Main St", "Metropolis", 12345}
};
printf("Name: %s\n", person4.name);
printf("Address: %s, %s %d\n", person4.address.street, person4.address.city, person4.address.postalCode);
return 0;
}
输出
Name: John
Address: 123 Main St, Metropolis 12345
7. 结构体与数组
结构体可以作为数组的元素,也可以包含数组作为成员。例如:
#include <stdio.h>
struct Person {
char name[50];
int age;
float height;
};
int main() {
struct Person people[2] = {
{
"Alice", 30, 160.0},
{
"Bob", 40, 180.0}
};
for (int i = 0; i < 2; i++) {
printf("Person %d: %s, %d, %.2f\n", i+1, people[i].name, people[i].age, people[i].height);
}
return 0;
}
输出
Person 1: Alice, 30, 160.00
Person 2: Bob, 40, 180.00
8. 结构体的内存对齐
结构体的内存对齐与填充是为了提高数据访问的效率。在C语言中,结构体的内存布局可能会受到对齐要求的影响,导致结构体的实际大小可能大于成员变量总和的大小。编译器通常会在成员之间插入填充字节,以确保每个成员的地址对齐。
8.1 对齐示例
#include <stdio.h>
struct Example {
char c; // 1 byte
int i; // 4 bytes, 3 bytes of padding
short s; // 2 bytes
};
int main() {
printf("Size of Example: %zu bytes\n", sizeof(struct Example));
return 0;
}
输出
Size of Example: 12 bytes
在这个例子中,Example
结构体的大小是12字节。虽然char
占1字节,int
占4字节,short
占2字节,成员变量的总和为7字节,但由于内存对齐要求,Example
结构体实际上占用12字节。
8.2 结构体对齐与#pragma pack
在某些情况下,可以使用#pragma pack
指令来控制结构体的对齐方式,从而减少内存占用。
#include <stdio.h>
#pragma pack(1) // 设置结构体对齐为1字节
struct PackedExample {
char c;
int i;
short s;
};
#pragma pack() // 恢复默认对齐
int main() {
printf("Size of PackedExample: %zu bytes\n", sizeof(struct PackedExample));
return 0;
}
输出
Size of PackedExample: 7 bytes
使用#pragma pack(1)
可以将PackedExample
结构体的对齐方式设置为1字节,从而减少结构体的实际大小为7字节,但可能会影响访问效率。
9. 类型定义(typedef
)简化结构体声明
使用typedef
可以为结构体定义一个新的类型名,使得结构体的声明更加简洁。例如:
#include <stdio.h>
typedef struct {
char name[50];
int age;
float height;
} Person;
int main() {
Person person1 = {
"Charlie", 28, 175.0};
printf("Name: %s\n", person1.name);
printf("Age: %d\n", person1.age);
printf("Height: %.2f\n", person1.height);
return 0;
}
输出
Name: Charlie
Age: 28
Height: 175.00
10. 嵌入式系统中的应用
在嵌入式系统中,结构体用于管理硬件寄存器、配置参数以及存储设备状态等。结构体能够帮助开发者以更结构化的方式访问硬件资源,提高代码的可读性和维护性。
10.1 示例:硬件寄存器配置
#include <stdio.h>
#include <stdint.h>
// 定义硬件寄存器配置结构体
typedef struct {
volatile uint32_t CONTROL;
volatile uint32_t STATUS;
volatile uint32_t DATA;
} UART_RegDef_t;
int main() {
UART_RegDef_t UART1; // 假设这是一个UART寄存器的实例
// 设置UART寄存器
UART1.CONTROL = 0x01; // 启用UART
UART1.STATUS = 0x00; // 清除状态
UART1.DATA = 0x55; // 发送数据
// 打印寄存器的配置
printf("UART1 CONTROL: 0x%X\n", UART1.CONTROL);
printf("UART1 STATUS: 0x%X\n", UART1.STATUS);
printf("UART1 DATA: 0x%X\n", UART1.DATA);
return 0;
}
输出
UART1 CONTROL: 0x1
UART1 STATUS: 0x0
UART1 DATA: 0x55
在这个示例中,结构体UART_RegDef_t
用于表示UART寄存器的配置,包含CONTROL
、STATUS
和DATA
寄存器。通过这种方式,可以方便地设置和读取寄存器的值。
11. 拓展技巧
11.1 结构体指针的算术运算
可以对结构体指针进行算术运算,通常用于数组访问。例如:
#include <stdio.h>
struct Person {
char name[50];
int age;
float height;
};
int main() {
struct Person people[3] = {
{
"Alice", 30, 160.0},
{
"Bob", 40, 180.0},
{
"Charlie", 25, 170.0}
};
struct Person *ptr = people; // 指向结构体数组的指针
for (int i = 0; i < 3; i++) {
printf("Person %d: %s, %d, %.2f\n", i+1, (ptr+i)->name, (ptr+i)->age, (ptr+i)->height);
}
return 0;
}
输出
Person 1: Alice, 30, 160.00
Person 2: Bob, 40, 180.00
Person 3: Charlie, 25, 170.00
11.2 结构体与联合体(union
)的比较
结构体和联合体都可以存储多个数据项,但结构体的每个成员都占有独立的内存空间,而联合体的所有成员共享同一块内存。使用结构体时每个成员都可用,而使用联合体时只有一个成员可以使用。
示例:结构体与联合体的比较
#include <stdio.h>
typedef union {
int intValue;
float floatValue;
char charValue;
} UnionType;
typedef struct {
int intValue;
float floatValue;
char charValue;
} StructType;
int main() {
UnionType u;
StructType s;
u.intValue = 10;
printf("Union intValue: %d\n", u.intValue);
u.floatValue = 5.5; // 修改联合体中的值
printf("Union floatValue: %f\n", u.floatValue);
// 注意:这时intValue的值是不确定的
s.intValue = 10;
s.floatValue = 5.5;
s.charValue = 'A';
printf("Struct intValue: %d\n", s.intValue);
printf("Struct floatValue: %f\n", s.floatValue);
printf("Struct charValue: %c\n", s.charValue);
return 0;
}
输出
Union intValue: 10
Union floatValue: 5.500000
Struct intValue: 10
Struct floatValue: 5.500000
Struct charValue: A
7. 结束语
- 本节内容已经全部介绍完毕,希望通过这篇文章,大家对C语言中的结构体
struct
有了更深入的理解和认识。- 感谢各位的阅读和支持,如果觉得这篇文章对你有帮助,请不要吝惜你的点赞和评论,这对我们非常重要。再次感谢大家的关注和支持!