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

相关文章
|
26天前
|
存储 C语言
如何在 C 语言中实现结构体的深拷贝
在C语言中实现结构体的深拷贝,需要手动分配内存并逐个复制成员变量,确保新结构体与原结构体完全独立,避免浅拷贝导致的数据共享问题。具体方法包括使用 `malloc` 分配内存和 `memcpy` 或手动赋值。
34 10
|
26天前
|
安全 编译器 Linux
【c语言】轻松拿捏自定义类型
本文介绍了C语言中的三种自定义类型:结构体、联合体和枚举类型。结构体可以包含多个不同类型的成员,支持自引用和内存对齐。联合体的所有成员共享同一块内存,适用于判断机器的大小端。枚举类型用于列举固定值,增加代码的可读性和安全性。文中详细讲解了每种类型的声明、特点和使用方法,并提供了示例代码。
24 3
|
26天前
|
存储 大数据 编译器
C语言:结构体对齐规则
C语言中,结构体对齐规则是指编译器为了提高数据访问效率,会根据成员变量的类型对结构体中的成员进行内存对齐。通常遵循编译器默认的对齐方式或使用特定的对齐指令来优化结构体布局,以减少内存浪费并提升性能。
|
30天前
|
编译器 C语言
共用体和结构体在 C 语言中的优先级是怎样的
在C语言中,共用体(union)和结构体(struct)的优先级相同,它们都是用户自定义的数据类型,用于组合不同类型的数据。但是,共用体中的所有成员共享同一段内存,而结构体中的成员各自占用独立的内存空间。
|
30天前
|
存储 C语言
C语言:结构体与共用体的区别
C语言中,结构体(struct)和共用体(union)都用于组合不同类型的数据,但使用方式不同。结构体为每个成员分配独立的内存空间,而共用体的所有成员共享同一段内存,节省空间但需谨慎使用。
|
1月前
|
编译器 C语言 C++
C语言结构体
C语言结构体
28 5
|
1月前
|
编译器 Linux C语言
C语言 之 结构体超详细总结
C语言 之 结构体超详细总结
20 0
|
1月前
|
存储 编译器 Linux
深入C语言:探索结构体的奥秘
深入C语言:探索结构体的奥秘
|
1月前
|
存储 编译器 C语言
c语言回顾-结构体(2)(下)
c语言回顾-结构体(2)(下)
30 0
|
1月前
|
存储 编译器 程序员
c语言回顾-结构体(2)(上)
c语言回顾-结构体(2)(上)
29 0