栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言学习记录——사십일 自定义数据类型结构体(1)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言学习记录——사십일 自定义数据类型结构体(1)

结构体声明
#include

struct Stu//结构体关键字,标签(名字)
    char name[20];
    char tele[12];
    char sex[10];
    int age;
}s4, s5, s6;//全局变量

struct Stu s3;//全局变量

int main()
{
    struct Stu s1;//局部
    struct Stu s2;//变量
    return 0;
}

一些特殊声明

struct
{
    char name[20];
    char tele[12];
    char sex[10];
    int age;
}x;

没有了名字,是一种匿名类型。如果不在下面紧接着声明x这个变量,那么就没有别的方法去声明变量

struct
{
    char name[20];
    char tele[12];
    char sex[10];
    int age;
}sa;


struct
{
    char name[20];
    char tele[12];
    char sex[10];
    int age;
}*psa;

完全一样,如果这时候psa = &sa,编译器会报错。因为编译器会把他们当成两个独立的个体,不合法。

匿名结构体不要用。

自引用

参考数据结构中的链表类型,12345五个数字,都是结点,通过1能连接到2,2连到3,依次类推。结构体中也可以实现

struct Node
{
    int data;
    struct Node n;
};

这样的代码,data代表着1,n就是下一个结构体。但是结构体就太大了,Node n里面还放着一个数据,一个结构体,这一个结构体还放着一个数据,一个结构体,所以说无法计算大小。既然目的是通过一个结点找到另一个结点,那么只要存放地址即可,所以:

struct Node
{
    int data;
    struct Node* next;
};
 

可以用typedf来重命名

typedf struct Node
{
    int data;
    struct Node* next;
}Node;
但是必须原本就有结构体的名字,不能去重命名匿名结构体

定义和初始化

之前也写过,里面也可以嵌套初始化,比如初始化一个结构体

内存对齐

规则:

第一个成员在与结构体变量偏移量为0的地址处存放

其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数=编译器默认的一个对齐数 与 该成员大小的较小值。

结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍

 gcc编译器没有默认对齐数,所以对齐数就是成员大小

如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

#include

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

struct S2
{
    char c1;
    char c2;
    int a;
};

int main()
{
    struct S1 s1 = { 0 };
    printf("%dn", sizeof(s1));
    struct S2 s2 = { 0 };
    printf("%dn", sizeof(s2));
    return 0;
}

需要写的好多解释,实在是懒得打这么多字,反正也有好多同样内容的。哈哈哈。

嵌套

struct S3
{
    double d;
    char c;
    int i;
};

struct S4
{
    char c1;
    struct S3 s3;
    double d;
};


为什么要存在内存对齐?

没有官方原因,很多资料是这样的:

平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。(有些平台,访问int类型的数据,只能去访问4的整数倍的地址处取得)

性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要做两次内存访问;而对齐的内存访问仅需要一次访问。

总结:结构体的内存对齐是拿空间换时间的做法

假设一个32位的机器,每次读取都是4个字节。如果不对齐,对于一个char和int类型的数据,想要读取完全这个int类型的数据,那么第一次读取4个字节,读到了char数据和部分int数据的空间,需要第二次读取才能读到完整的int数据。如果对齐了,char后面空3个字节再放上int数据,也需要读两次,但是对于int数据,第二次读就可以读完。

在设计结构体的时候,我们既要满足对齐,又要节省空间,那么:

让占用空间小的成员尽量集中在一起。
修改默认对齐数

#pragma预处理指令可以改变

#pragma pack(4)//设置默认对齐数为4
struct S
{
    char c1;
    double d1;
};
#pragma pack()//取消设置的默认对齐数

另外一个关键字offsetof(structName, memberName)

offset就是计算偏移量,of就是指哪个元素

#include

void Init(struct S* ps)
{
    ps->a = 100;
    ps->c = 'w';
    ps->d = 3.14;
}

void Print1(struct S tmp)
{
    printf("%d %c %lfn", tmp.a, tmp.c, tmp.d);
}

void Print2(const struct S* ps)
{
    printf("%d %c %lfn", ps->a, ps->c, ps->d);
}
int main()
{
    struct S s = { 0 };
    Init(&s);
    Print1(s);
    Print(&s);
    return 0;
}

传值和传址调用。

如果传过去的参数过大,那么就会出问题,压栈。

之前写过

第二篇写位段

结束。


 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/862658.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号