C语言---自定义类型:结构体(1)

简介: C语言---自定义类型:结构体

结构体回顾

结构体

自定义的类型:结构体、联合体、枚举

结构是一些值的集合,这些值成为成员变量,结构的每个成员可以是不同类型的变量

//描述一本书:书名、作者、定价、书号
 
//结构体类型---类似于整型、浮点型
struct Book
{
    char book_name[20];//书名
    char author[20];//作者
    float prince;//价格
    char id[18];//书号
 
}; b4, b5, b6;//结构体变量’
//这里的结构体变量个下面的本质是一样的
//但是这里的是全局变量,而下面的是局部变量
int main()
{
    //结构体需要用大括号进行初始化,因为结构体里面不只一个值
    //初始化的时候我们是根据成员进行初始化的
    //下面的初始化是按照成员顺序进行初始化的
    struct Book b1 = {"鹏哥c语言","鹏哥",38.8f,"PG20240520"};
    //如果不按照成员顺序进行初始化可以这么写
    struct Book b2 = {.id="DG20240520",.book_name="蛋哥Linux",.author="蛋哥",.prince=55.5f};
    //两个操作符.  ->
    printf("%s %s %f %s\n", b1.book_name, b1.author, b1.prince, b1.id);
    printf("%s %s %f %s\n", b2.book_name, b2.author, b2.prince, b2.id);
    return 0;
}
 
//鹏哥c语言 鹏哥 38.799999 PG20240520
//蛋哥Linux 蛋哥 55.500000 DG20240520
 
//为什么这个数据会和我们设置的有差异呢?
//
//因为浮点数在内存中 有可能是不能进行精确保存的
 
/*
判断浮点数是否相等的方法
if(fabs(f-3.45)<0.00000001)
{
    printf("相等");
}
else
{
    printf("不相等");
}
 
*/

结构体的声明

在声明结构体的时候,可以不完全的声明---把名字省略掉

struct //直接把结构体名字去掉
{
    char c;
    int i;
    double d;
}s1;//直接在这里进行结构体变量的创建
//匿名结构类型创建变量
//创建变量只能用一次
int main()
{
    //struct S s2;这种创建的方式就不行了
 
 
    return 0;
}
 
 
 
struct //直接把结构体名字去掉
{
    char c;
    int i;
    double d;
}* ps;//匿名结构类型的指针类型
//匿名结构体类型+ *就是匿名结构体类型指针
//这里的ps就是指针变量
int main()
{
    ps = &s1;
 
    return 0;
}
//两个类型虽然成员是一样的,但是编译器会认为这两个匿名结构体的类型是不一样的
//所以结构体指针也是不一样的
 
//编译器会认为一种匿名结构体类型是一种类型,而另一种就是另一种类型
//反正是没有相同的匿名结构体类型的
 
 
//我们只有在仅仅只使用一次的情况下才会使用匿名结构体类型
 
//编译器会把两个匿名结构体类型当成两个不同类型的匿名结构体类型的

数据结构---数据结构其实是数据在内存中的组织结构

//struct Node
//{
//    int data;//存放数据
//    struct Node next;//访问下一个节点---类似递归
//    //但这中写法是错误的
//};
//结构体能自己找到同类型的下个节点,实现自引用,但是上面的方式是不对的
 
 
//那么在一个结构体中寻找下一个同类型的结构体的变量的方法
struct Node
{
    int data;//存放数据----数据域
    struct Node* next;//---指针域
 
    //next存放的是下个节点的地址
    //这样我们不仅能存储这个节点的数据,还能存储下个节点的地址
    //这样我们就能使结构体能自己找到同类型的下个节点,实现自引用
 
 
    //存放这个节点的数据,还能找到下个节点的数据,那么我们添加一个结构体指针就行了
};
int main()
{
 
    return 0;
}
/*这里的是一个结构体类型的
struct Node
{
    int data;//存放数据----数据域
    struct Node* next;//---指针域
 
 
};*/
//那么我们对这个结构体类型进行重命名Node
typedef struct Node
{
    int data;//存放数据----数据域
    struct Node* next;//---指针域
    //错误写法:Node* next;//---指针域
    //我们是先创建这个结构体类型,再进行重名名的,所以在顺序上面,这个代码就是错的
 
    //重命名是后来的,所以不能将里面的代码进行改变
}Node;
 
 
int main()
{
 
    return 0;
}

2.结构体内存对齐

我们在涉及计算结构体的大小的问题的时候,就会面临结构体内存对其的问题了

offsetof-----宏--头文件stddef.h

计算结构体成员相较于结构体变量起始位置的偏移量

offsetof(type,member)

offsetof计算的是每个成员在内存中相较于起始位置的偏移量

//struct S1
//{
//    char c1;
//    char c2;
//    int n;
//};
//struct S2
//{
//    //顺序不一样
//    char c1;    
//    int n;
//    char c2;
//};
//int main()
//{
//    printf("%zd\n", sizeof(struct S1));//占8个字节
//    printf("%zd\n", sizeof(struct S2));//占12个字节
//    return 0;
//}
//为什么输出的大小一个是8一个是12呢?
//那么这里就涉及到了结构体的对齐问题了
 
//结构体的成员在内存中是存在对齐现象的
//结构体内对齐
 
//offsetof-----宏
 
//计算结构体成员相较于结构体变量起始位置的偏移量
 
struct S1
{
    char c1;
    char c2;
    int n;
};
struct S2
{
    //顺序不一样
    char c1;
    int n;
    char c2;
};
int main()
{
    //printf("%zd\n", sizeof(struct S1));//占8个字节
    //printf("%zd\n", sizeof(struct S2));//占12个字节
 
    struct S1 s1 = { 0 };
   //计算偏移量
    /*printf("%zd\n", offsetof(struct S1, c1));//0
    printf("%zd\n", offsetof(struct S1, c2));//1
    printf("%zd\n", offsetof(struct S1, n));*///4
 
 
 
    printf("%zd\n", offsetof(struct S2, c1));//0
    printf("%zd\n", offsetof(struct S2, n));//4
    printf("%zd\n", offsetof(struct S2, c2));//8
 
 
 
 
    return 0;
}
 
//第一个字节给c1,第二个字节给c2,后面的两个字节空着了,
// 因为n是从第4个字节开始的,占了4个字节
 
 
//offsetof计算的是每个成员在内存中相较于起始位置的偏移量
//画图:
/*
第一行是c1占的字节
第二行是c2占的字节
第二三行是空的
n是从第四行到第七行的
总共算下来就是8个字节
 
 
*/
 
 
//printf("%zd\n", offsetof(struct S2, c1));//0
//printf("%zd\n", offsetof(struct S2, n));//4
//printf("%zd\n", offsetof(struct S2, c2));//8
 
//对s2进行计算得到的就是0  4  8
 
/*
第0行是c1
1 2 3行是空的
 
4 5 6 7放的是n,因为n占4个字节,并且李起始点有4个字节
 
第8行方的是c2
 
*/
 
//但是为什么之前计算的是S2占12个字节呢?
 
//不管是S1还是S2,他们的成员在内存中不是一个放完就放另一个的
//其实是存在对齐现象的

C语言---自定义类型:结构体(2)https://developer.aliyun.com/article/1544451

相关文章
|
27天前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
123 14
|
1月前
|
存储 编译器 C语言
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
147 10
|
2月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
153 13
|
2月前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
2月前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
69 11
|
2月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
60 4
|
3月前
|
存储 C语言
如何在 C 语言中实现结构体的深拷贝
在C语言中实现结构体的深拷贝,需要手动分配内存并逐个复制成员变量,确保新结构体与原结构体完全独立,避免浅拷贝导致的数据共享问题。具体方法包括使用 `malloc` 分配内存和 `memcpy` 或手动赋值。
91 10
|
3月前
|
安全 编译器 Linux
【c语言】轻松拿捏自定义类型
本文介绍了C语言中的三种自定义类型:结构体、联合体和枚举类型。结构体可以包含多个不同类型的成员,支持自引用和内存对齐。联合体的所有成员共享同一块内存,适用于判断机器的大小端。枚举类型用于列举固定值,增加代码的可读性和安全性。文中详细讲解了每种类型的声明、特点和使用方法,并提供了示例代码。
31 3
|
3月前
|
存储 大数据 编译器
C语言:结构体对齐规则
C语言中,结构体对齐规则是指编译器为了提高数据访问效率,会根据成员变量的类型对结构体中的成员进行内存对齐。通常遵循编译器默认的对齐方式或使用特定的对齐指令来优化结构体布局,以减少内存浪费并提升性能。
|
3月前
|
编译器 C语言
共用体和结构体在 C 语言中的优先级是怎样的
在C语言中,共用体(union)和结构体(struct)的优先级相同,它们都是用户自定义的数据类型,用于组合不同类型的数据。但是,共用体中的所有成员共享同一段内存,而结构体中的成员各自占用独立的内存空间。