在C语言中,在默认情况下,编译器规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节的倍数。
例如:
struct MyStruct {
double ddal;
char dda;
int type;
};
得到的结果为:16
所以,在计算结构体变量的大小时:
①上面的所有字节数的总和,必须是下一个类型的整数倍数。
②总字节数一定是最大类型的整数倍。
例题:
char a;
double b;
int e;
得:20
C语言定义了一个结构体怎么分配内存?C\C++中结构体变量与结构体指针内存分配问题?
问题1:结构体指针最开始怎么分配内存?用sizeof()是不能确定大小的。
问题2:给结构体变量分配之后,是否还要给每个成员分配,还是只给不能确定大小的成员分配?
问题3:如果是要每个成员分配内存,那么释放的时候是不是每个成员都要单独释放?指针加一之后,又怎么做?
C\C++中结构体变量与结构体指针内存分配问题?
(1)声明一个结构体变量,无论是否初始化,都开辟内存,声明一个结构体指针变量,对其初始化的时候才会开辟内存。
(2)结构体变量分配结构体本身大小的空间,结构体指针分配4个字节,其实任何类型的指针都是分配四个字节的指针空间。
(3)所以:
A a[3]; //a里面是三个A变量,所以分配三个结构体大小
A *a; //a是一个指针,分配4个字节,就算A再大,a也只是4个字节,因为任何类型的指针都是4个字节。要使用a,必须先要对指针初始化,也即分配空间了。
如:
A *a;
a = (A*)malloc(sizeof(A));
(4)我们完全可以撇开结构体,把问题简单化成int类型来说明这个指针问题:
int a1[10];
int *a2;
1)a1是包含10个int的数组,大小也就是10*sizeof(int)。直接使用a1不要在进行什么初始化或者分配空间的游戏,因为数组a1里面本身存放的就是int变量本身了。
2)a2是一个int*的东西,也就是整型指针,a2不能存放int变量,它只能存放一个int变量的地址。如果要使用a2,必须首先对a2初始化,即将它指向一个int变量的地址,如:a2 = (int*)malloc(sizeof(int));
或者
int i = 10;
a2 = &i;
所以,malloc函数的作用是首先声明一个变量,然后返回该变量的地址。
所以:a2 = (int*)malloc(sizeof(int)) 的含义就是把该变量的地址赋值给a2,和a = &i 本质上并没有什么不同,只是一个变量是栈上,一个是堆上,都是一个地址赋值。
(5)所以,所谓的分配空间,就是对指针赋值,把一个变量的地址赋值给一个指针。
一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来指向结构体数组中的元素。
声明一个结构体变量,无论是否初始化,都开辟内存,声明一个结构体指针变量,对其初始化的时候才会开辟内存。
A a[3]; a是A型的,有3个,当然分配A乘3大小的空间
A* a; a是A*型的,当然只分配A*大小的空间,而不会分配A大小的空间结构体变量分配结构体本身大小的空间,结构体指针分配4个字节,其实任何类型的指针都是分配四个字节的指针空间。
所以:
A a[3]; //a里面是三个A变量,所以分配三个结构体大小
A *a; //a是一个指针,分配4个字节,就算A再大,a也只是4个字节,因为任何类型的指针都是4个字节。要使用a,必须先要对指针初始化,也即分配空间了。
如:
A *a;
a = (A*)malloc(sizeof(A));
我们完全可以撇开结构体,把问题简单化成int类型来说明这个指针问题:
int a1[10];
int *a2;
很容易知道,a1是包含10个int的数组,大小也就是10*sizeof(int)。我们可以直接使用a1不用再进行什么初始化或者分配空间,因为数组a1里面本身存放的就是int变量本身了。
然后a2,是一个int*的东西,也就是整型指针,a2不能存放int变量,它只能存放地址,一个int变量的地址。如果要使用a2,必须首先对a2初始化,即将它指向一个int变量的地址,如:
a2 = (int*)malloc(sizeof(int));
或者
int i = 10;
a2 = &i;
所以,malloc函数的作用是首先声明一个变量,然后返回该变量的地址。
所以:a2 = (int*)malloc(sizeof(int)) 的含义就是把该变量的地址赋值给a2,和a = &i 本质上并没有什么不同,只是一个变量是栈上,一个是堆上,都是一个地址赋值。
【例7.3】指向结构体变量的指针的应用。程序运行结果如下:
- #include <iostream>
- #include <string>
- using namespace std;
- int main( )
- {
- struct Student//声明结构体类型student
- {
- int num;
- string name;
- char sex;
- float score;
- };
- Student stu;//定义Student类型的变量stu
- Student *p=&stu;//定义p为指向Student类型数据的指针变量并指向stu
- stu.num=10301;//对stu中的成员赋值
- stu.name="Wang Fun";//对string变量可以直接赋值
- stu.sex='f';
- stu.score=89.5;
- cout<<stu. num<<" "<<stu.name<<" "<<stu.sex<<" "<<
- stu.score<<endl;
- cout<<p -> num<<" "<<(*p).name<<" "<<(*p).sex<<" "<<(*p).score<<endl;
- return 0;
- }
10301 Wang Fun f 89.5 (通过结构体变量名引用成员)
10301 Wang Fun f 89.5 (通过指针引用结构体变量中的成员)
两个cout语句输出的结果是相同的。
为了使用方便和使之直观,C++提供了指向结构体变量的运算符->,例如p->num表示指针p当前指向的结构体变量中的成员num。
p->num 和(*p).num等价。
同样
p->name等价于(*p).name。
也就是说,以下3种形式等价:
用户栈是(运行时创建)是用户存放程序临时创建的局部变量,不包括静态变量,除此之外,在函数调用时,其参数也会被压入栈,并且带导函数调用结束后,函数的返回值也会存放到栈中。
堆是用于存放程序进程中被动态分配的内存段,它的大小不固定,可动态扩展,结束后必须free掉。
今天做到一道题目,题目是这样的:
这里考察了两个知识点:uinon结构体内存大小
union变量所占的大小为成员中最大的那一个
关于struct结构体的对齐问题
参考了这篇博客struct结构体对齐问题
我们知道,struct结构体中可以有不同的数据类型变量,成员定义时依次存储在内存连续的空间,struct结构体变量的首地址就是第一个成员的地址,那么内存偏移量就是各个成员相对于结构体变量地址的差(即相对于第一个成员地址的差),对于某个成员的内存偏移量,就为上一个成员的内存偏移量+上一个内存成员的大小那么另外我们需要了解的是对齐参数,系统默认的对齐参数由pack决定,每个成员的对齐参数为min(pack,成员类型大小),那么求出每个成员各自的对齐参数之后,那么结构体的对齐参数就为各个成员函数的对齐参数的最大值(也就是说,一个结构体的对齐参数最大也就为8),对齐参数的作用就是:对于每个成员的偏移量,需要能够被该成员的对齐参数整除,否则需要把该偏移量补齐到离他最近的对齐参数的倍数(对于偏移量为0,那么也是补齐为0)
那么我们如何计算出一个结构体的实际大小呢,(1)从第一个成员出发,计算出该成员的内存偏移量(2)按照对齐参数来计算该成员的实际内存偏移量(3)依次按照上面的步骤计算出各个成员的实际内存偏移量(4)结构体的大小就为最后一个成员的大小+实际内存偏移量(5)结构体的实际大小就为按照对齐参数补齐得出的大小
拿我们上面这个例子来说:(1)id的偏移量为0,按照它的对齐参数min(1,8)=0来补齐,所得的实际偏移量也是0 (2)crc的偏移量0+1=1,按照它的对齐参数min(4,8)=4来补齐,那么它的实际偏移量就为4 (3)pack的偏移量为1+4=5,按照它的对齐参数min(4,8)=4来补齐,那么它的实际偏移量就为8 (4)结构体的大小为4+8=12 (5)结构体的对齐参数为max(1,4,4)=4,按照结构体的对齐参数来补齐得到结构体的实际大小,那么也就是12(因为12能被4整除,所以不用补齐了)
在C语言中,在默认情况下,编译器规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节的倍数。
例如:
struct MyStruct {
double ddal;
char dda;
int type;
};
得到的结果为:16
所以,在计算结构体变量的大小时:
①上面的所有字节数的总和,必须是下一个类型的整数倍数。
②总字节数一定是最大类型的整数倍。
例题:
char a;
double b;
int e;
得:20
转载于:https://www.cnblogs.com/LisaY/p/4665364.html