企业网站开发公司,南充楼市,国产十大erp软件,包装设计效果图目录 前言
1、结构体声明
1.1 结构体基本概念
1.2 结构体声明
1.3 特殊的结构体声明
1.3.1 匿名结构体声明
1.4 结构体自引用
1.5 结构体变量的定义和初始化
1.6 结构体内存对齐
1.7 修改默认对齐数
1.8 结构体传参
总结 前言 C语言除了有其内置类型#xff0c;还有…目录 前言
1、结构体声明
1.1 结构体基本概念
1.2 结构体声明
1.3 特殊的结构体声明
1.3.1 匿名结构体声明
1.4 结构体自引用
1.5 结构体变量的定义和初始化
1.6 结构体内存对齐
1.7 修改默认对齐数
1.8 结构体传参
总结 前言 C语言除了有其内置类型还有自定义类型。因为在实际运用中我们可能会遇到一类数据它的内容是由多种数据组成的例如一个学生的个人信息它就包含了姓名、年龄、学号等等。这些数据并不是统一的类型因此不能用C语言本身的数组去定义那如果我们需要将其放在一个变量中时我们就可以运用到结构体了。结构体的出现就是用来处理这样的内容数据不统一的变量这给了编程者很大的操作空间使得编程更加灵活自由。 接下来我们就详细介绍一下结构体吧。
1、结构体声明
1.1 结构体基本概念 结构体是一些值得集合这些值称为成员变量。结构体的每个成员可以是不同类型的变量。类比数组数组的成员变量的类型必须相同而结构体没有要求。
1.2 结构体声明 举个例子 这是一个“学生”结构体的定义它的类型为struct stustruct是结构体声明的前缀stu是自己定义的类型名因为是包含“学生”信息的结构体因此我们用来stu。定义好类型名之后我们用一个大括号阔住接下来的内容并且在大括号后面加上“”。然后我们来看大括号里面的内容上面这个例子我大括号里面放了了四个变量分别用来存放姓名年龄性别学号。如果你想定义其他的也是可以的内容是可以自己灵活改变的。这样我们就算是定义好了一个结构体类型它可以用来表示学生的基本信息。 注意上面仅只是建立了一个类型还没有正真建立结构体变量。相当于我们只是建立了一个类似于intfloatdouble这样的东西后面还需要用具体的变量去承载。类比int我们定义int类型的变量还得想一个变量名比如“p”那我们定义方式就是int p0那这里p就是一个整型的变量。同理结构体也一样上面的操作只是相当于写了一个“int”还需要想一个变量名假如“p”定义时像这样struct stu p{ 0 }这样才算定义出了一个结构体变量p。 例如 这是两种声明方法可以在结构体建立时就声明变量p1也可先定义类型后再声明p2。这两种方法的区别是前者定了全局变量后者定义的是局部变量。 1.3 特殊的结构体声明
1.3.1 匿名结构体声明 例如 声明结构体类型时没有名字。这种类型的结构体只能用一次而且是马上建立马上用 像这样定义一个s1的结构体之后就再也无法使用这个匿名结构体。 匿名结构体特点对于不同的匿名结构体即使其内容一模一样计算机还是会认为他们不是一个类型如果用两个内容相同的匿名结构体一个定义变量一个定义指针当指针指向变量时计算机会报错。 1.4 结构体自引用 结构体内部包含自己。看一个例子 对于这个结构体第一个数据是一个整型第二个数据定义的居然是指向自己的指针类型这样的话我们去访问这个结构体时可以在它内部发现指向自己的指针这就是结构体的自引用。 想一个问题我们能不能在结构体里面直接定义一个本身类型的结构体变量呢我们为什么要定义指针呢 原因因为如果我们在一个结构体里面直接定义它本身类型的变量那我们将无法预估这个结构体的大小因为每次计算这个结构体第二个参数的大小时又会进入到一个结构体里面而那个结构体的第二个参数还是结构体是一个死循环。所以我们在结构体自引用时只定义自身类型 的指针就能避开这个问题。 为什么要这么用 这个用法很重要有了这样一个功能才能实现链表建立。是数据结构很重要的内容。 注意结构体的自定义是无法通过匿名结构体实现的。
1.5 结构体变量的定义和初始化 这个在前面其实已经讲到一部分下面看几种定义的例子 p1和p2定义时未初始化p3定义时进行了初始化。这三种方式都定义了结构体变量p3在定义时进行了初始化。 1.6 结构体内存对齐 先看一个例子思考如下结构体占用几个字节
#include stdio.h
struct S1
{char c1;int c2;char c3;
};
int main()
{printf(%d, sizeof(struct S1));return 0;
} 答案 答案是12。那么这是为什么呢为什么不是6这就涉及到我们揭晓来要讲的结构体内存对齐。 内存中如何开辟结构体空间 首先了解结构体的对其规则
1. 第一个成员在与结构体变量偏移量为0的地址处。 2. 其他成员变量要对齐到某个数字对齐数的整数倍的地址处。 对齐数 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8 3. 结构体总大小为最大对齐数每个成员变量都有一个对齐数的整数倍。4. 如果嵌套了结构体的情况嵌套的结构体对齐到自己的最大对齐数的整数倍 处结构体的整 体大小就是所有最大对齐数含嵌套结构体的对齐数的整数 倍。 就拿上面的结构体举例讲解其在内存中的存放情况
struct S1
{char c1;int c2;char c3;
}; 只有vs有默认对齐数其他平台是没有默认对齐数的其他平台对齐数就是数据本身的大小。 为什么存在内存对齐 1、平台原因 不是多有的硬件平台都能访问任意地址上的任意数据某些硬件平台只能在某些地址处取某些特定的数据类型否则抛出硬件异常。 2、性能原因 数据结构尤其是栈应尽可能地在自然边界上对齐。原因在于为了访问未对齐的内存处理器需要做两次访问而对齐的内存访问只需要访问一次。 总的来说 结构体的内存对齐是拿空间换取时间的做法。
在我们大致了解对齐规则后我们需要了解结构体定义的时候位置的不同会影响其空间的大小。让占用空间小的数据尽量放在一起这样可以减少结构体空间的浪费。 1.7 修改默认对齐数 在vs中默认对齐数是8但是它可以被修改。 使用#pragma 看例子
#include stdio.h
#pragma pack(4)
struct S
{int i;double d;
};
#pragma pack()int main()
{printf(%d\n, sizeof(struct S));return 0;
} 用#pragma pack4将默认对齐数改成了4结果从16变成了12。 后面的#pragma pack是用来恢复默认对齐数。 1.8 结构体传参 直接看例子
#include stdio.h
struct S
{int data[1000];int num;
};
struct S s { {1,2,3,4},1000 };
void print1(struct S s)
{printf(%d\n, s.num);
}
void print2(struct S* p)
{for(int i0;i10;i)printf(%d\n, p-data[i]);
}
int main()
{print1(s);print2(s);return 0;
} 结构体传参有两种方式第一种print1是直接将值传送过去传值调用第二种print2是传地址传址调用。我们认为第二种更好因为直接传值的话参数是需要压栈的会有时间和空间的系统开销如果传值一个过大的结构体会导致系统的性能下降。 总结 本篇详细讲解了结构体的定义希望对你有所帮助。