1. 结构体内存分配
结构体中的各个字段在内存中的出现的位置时随它们被声明的 顺序而依次递增的。并且第一个字段的首地址等于整个结构体实例的首地址。
说明 : 结构体类型是一个类型,就好比 int 是一个类型一样,它是一个构造类型,独立类型,这个类型的大小就是 sizeof(struct)
当一种类型作为实参传递后,那么它同一个内置类型传递是一样的( int 类型 ) 值传递
对于同种类型的struct , 同内置类型一样,可以进行赋值,两个int类型的可以赋值,两个struct同样可以。
期待实验 :综上,结构体变量名不能看作是内存的首地址(int a , 谁也没说 a 是变量的地址 ,而且感觉 &struct 是结构体内存的首地址 , 待实验 )
以上实验完成 : &(取地址符号) + 结构体名字, 就是结构体首地址, 就把结构体相成普通变量一样 , int a , &a 就是变量 a 的地址 .
综上, 已经做过实验, 确实如此.
#include<stdio.h>
struct stu {
char name;
int score;
};
int main()
{
struct stu *p;
struct stu student;
p = &student;
p->name = 'a';
p->score = 100;
printf("name = %c\n", student.name);
printf("score = %d\n", student.score);
getchar();
}
内存对齐 ( 使的成员变量不是连续排不,增添了一些多余的内存 )
例如有以下一个结构体
struct ex {
int i;
char t;
int n;
}
第1个成员偏移量为0,是int型成员大小4(假设这太机器的整型长度占4个字节)的整数倍。
第2个成员 t 为char型,他的大小为1,首先假设在成员i和t之间没有填充字节,由于i是整型,占4个字节那么在没有填充之前,第2个成员t相对于结构体的偏移量为4,他是t成员大小1的4倍,符合此条件,所以系统在给结构体第2个成员分配内存时,不会在i和t之间填充字节以到达对齐的目的。
当分配结构体第3个成员n时,首先发现是一个整型数据,大小为4,没有填充之前,n相对于结构体首地址偏移量为:前面2个成员+填充字节=5,所以当系统发现5不是4(成员大小)的整数倍时,会在成员t之后(或者说n之前)填充3个字节,以使n的偏移量到达8而成为4的整数倍。这样这个结构体占用内存情况暂时为4+1+3+4。
2.结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
上面的结构体内存分配以后还要看是否满足此条件,假设在最末一个成员之后不需填充字节数,那么这个结构体的大小为12。而ex结构体中最宽基本类型成员为int,大小为4,12为4的整数倍,所以无须再在最末一个成员之后加上填充字节了。所以sizeof(ex)=12;
如果一个结构体如下所示struct ex1{
int i;
char t;
int n;
char add;
}
那么sizeof(ex1) =16;原因就是在最后一个成员之后填充了3个字节。
3.还有一个额外的条件:结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
4.对于结构体成员属性中包含结构体变量的复合型结构体再确定最宽基本类型成员时,应当包括复合类型成员的子成员。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。
2.函数的参数传递
形参 : 只是在被调用时临时分配内存,调用结束后,释放内存,( 值传递 , 一般传递都属于这种 , 包括结构体 , 也只是临时分配了一块内存 )
实参 : 无论实参是什么类型 ( 包括指针类型 ) , 在进行调用时,它必须有确定的值( 如果使用指针,必须分配内存或者指向正确的内存地址 )
单向传递 :实参 -> 形参
函数的首地址 : 函数名
数组的首地址 : 数组名
结构体的首地址 : 不是结构体名,而是 &结构体名字 .
指针传递的是内存地址,例如将函数首地址传递,则就是指向这个函数,( 如果要想指向这个结构体,就必须找到结构体的首地址,如上待实验 )