C语言自定义数据类型(1)结构体

目录

一、结构体语法基础

1.1结构体的创建

1.2结构体变量的定义

1.3结构体变量的初始化

1.4特殊的结构体声明

1.4结构体的自引用(链表的创建)

1.5结构体成员的访问

1.6结构体传参

二、结构体的内存

2.1引入

2.2结构体内存对齐规则

2.3为什么要存在内存对齐?

2.4题目讲解

三、位段相关知识

3.1位段定义

3.3位段应用

3.4注意事项


一、结构体语法基础

1.1结构体的创建

struct 结构体名

{

        int a;             //成员变量名

        char b;

        ……

};

结尾的分号不能丢!!!

1.2结构体变量的定义

//法一:声明全局变量
struct Point
{
     int x;
     int y;
}p1; //声明类型的同时定义变量p1


//法二:声明全局变量
struct Point
{
     int x;
     int y;
}
int main()
{
    struct Point p2; //定义结构体变量p2
}

1.3结构体变量的初始化

struct Stu //类型声明
{
    char name[50];    //名字
    int age;         //年龄
};

struct Stu s1 = {"Lily", 18};//初始化
struct Stu s2 = {.age=18, .name="Lily"};//指定顺序初始化

1.4特殊的结构体声明

//匿名结构体
struct
{
    int a;
    char b;
    double c;
}x;

缺陷:匿名的结构体,如果没有对结构体类型重命名的话,只能使⽤⼀次。

1.4结构体的自引用(链表的创建)

//法一
struct Node
{
    int data;
    struct Node next;
};
//法二
struct Node
{
    int data;
    struct Node* next;
}

法一错误,法二正确

1.5结构体成员的访问

  • 直接访问:"  .  "操作符
#include <stdio.h>
struct example
{
    int x;
    int y;
}s = {1,2};

int main()
{
    printf("x: %d y: %d\n", s.x, s.y);
    return 0;
}
  • 间接访问:"->"操作符
#include <stdio.h>
struct example
{
    int x;
    int y;
};

int main()
{
    struct Point p = {1, 2};
    struct Point *ptr = &p;
    ptr->x = 10;
    ptr->y = 20;
    printf("x = %d y = %d\n", ptr->x, ptr->y);
    return 0;
}

1.6结构体传参

struct S
{
    int data[1000];
    int num;
}s = {{1,2,3,4}, 1000};

//法一:结构体传参
void print1(struct S s)
{
    printf("%d\n", s.num);
}

//法二:结构体地址传参
void print2(struct S* ps)
{
    printf("%d\n", ps->num);
}

 法二优于法一:只传一个指针的内存开销小于传结构体的内存开销

二、结构体的内存

2.1引入

#include<stdio.h>
struct s1
{
	char c1;    //1个字节
	int i;		//4个字节
	char c2;	//1个字节
};

int main()
{
	struct s1 s = { 1,2,3 };
	printf("%zd", sizeof(s));
	return 0;
}

按照正常理解,占用内存应该为6个字节。但是结果却为12个字节。

2.2结构体内存对齐规则

  1. 结构体的第⼀个成员要对⻬到和结构体变量起始位置偏移量为0的地址处。
  2. 其他成员变量要对⻬到对⻬数的整数倍的地址处。
  3. 对⻬数 = 编译器默认的⼀个对齐数 与 该成员变量大小的较⼩值。
  4. 结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对齐数中最⼤的)的整数倍
  5. 如果嵌套了结构体的情况,嵌套的结构体成员对齐到⾃⼰的成员中最⼤对齐数的整数倍处,结构体的整体大小就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。
  6. 注意:不同环境下不同编译器中默认的对齐数不同。VS编译器默认为8,Linux环境下gcc编译器无默认对齐数
  7. 如何修改默认对齐数?
    #pragma pack(1)    //设置默认对⻬数为1
    #pragma pack()     //取消设置的对⻬数,还原为默认对齐数

2.3为什么要存在内存对齐?

解释仅作参考:内存对齐是为了提高计算机系统的访问效率。当数据结构或变量按照规定的边界对齐存放在内存中时,CPU可以更高效地访问这些数据,避免因访问未对齐的数据而产生额外的开销。此外,一些体系结构要求数据的地址必须是某种特定大小的倍数,否则可能导致错误或者性能下降。因此,通过内存对齐可以确保数据存储和访问的正确性和效率。

2.4题目讲解

回到开始的题目

struct S1
{
 char c1;
 int i;
 char c2;
};

三、位段相关知识

3.1位段定义

  • 位段的成员必须是 int、unsigned/signed int 、char等类型 。C99中位段成员的类型也可以选择其他类型
  • 位段的成员名后边有⼀个冒号和⼀个数字。
  • 数字代表指定一个结构体成员占用的位数。
struct A
{
    int _a:1;
    int _b:2;
    int _c:3;
    int _d:10;
};

3.3位段应用

位段通常用于需要精细控制数据存储方式的场景,例如硬件寄存器的位域定义、节省内存空间等。在定义位段时,可以指定成员名字、位宽以及可选的符号性质(有符号或无符号)。

3.4注意事项

  1. 不同机器的最大位数不同,C语言标准未规定位段中的成员在内存中从左向右分配,还是从右向左分配。因此位段存在移植性低的问题,跨平台使用会出现问题
  2. 位段的⼏个成员共有同⼀个字节,意味着有些成员的起始位置并不是某个字节的起始位置,那么这些位置处是没有地址的。所以不能对位段的成员使⽤&操作符!!
struct A
{
    int _a:1;
    int _b:2;
    int _c:3;
    int _d:10;
};

int main()
{
    struct A s = {0};
    //错误
    scanf("%d", &s._b); 
    //正确
    int b = 0;
    scanf("%d", &b);
    s._b = b;
    return 0;
}

  • 43
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
C语言中,结构体是一种自定义数据类型,可以将不同类型的变量组合在一起,形成一个新的数据类型结构体定义的基本形式如下: ```c struct 结构体名 { 数据类型 成员名1; 数据类型 成员名2; // ... }; ``` 其中,结构体名是用户自定义的名称,成员名是结构体中每个成员的名称,数据类型可以是任意C语言数据类型,包括基本数据类型自定义数据类型结构体变量的定义方式如下: ```c struct 结构体名 变量名; ``` 读取结构体中的成员变量可以通过“.”运算符来实现,例如: ```c #include <stdio.h> struct Person { char name[20]; int age; }; int main() { struct Person p; printf("请输入姓名:"); scanf("%s", p.name); printf("请输入年龄:"); scanf("%d", &p.age); printf("姓名:%s,年龄:%d\n", p.name, p.age); return 0; } ``` 枚举是一种特殊的数据类型,用于定义一组常量。枚举的定义方式如下: ```c enum 枚举名 { 常量名1, 常量名2, // ... }; ``` 其中,枚举名是用户自定义的名称,常量名是枚举中每个常量的名称。枚举常量的值默认是从0开始自动递增的,也可以手动指定值。例如: ```c #include <stdio.h> enum Weekday { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }; int main() { enum Weekday today = Tuesday; printf("今天是星期%d\n", today + 1); return 0; } ``` 联合是一种特殊的数据类型,它的成员变量共享同一块内存空间。联合的定义方式如下: ```c union 联合名 { 数据类型 成员名1; 数据类型 成员名2; // ... }; ``` 其中,联合名是用户自定义的名称,成员名是联合中每个成员的名称,数据类型可以是任意C语言数据类型,但所有成员的大小不能超过联合的大小。例如: ```c #include <stdio.h> union Number { int i; float f; }; int main() { union Number n; n.i = 123; printf("int: %d, float: %.2f\n", n.i, n.f); n.f = 3.14; printf("int: %d, float: %.2f\n", n.i, n.f); return 0; } ``` 以上就是C语言自定义数据类型中的结构体、枚举、联合的基本用法和注意事项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值