当您在 C 中创建结构时,例如:
typedef struct student
{
int roll_no;
char* name;
int* pointer;
}student;
我注意到 roll_no 和 name 没有连续存储在内存中。这是如何运作的?如果目标是封装这些数据,那么将它们连续存储不是更好吗?编译器如何知道这些数据属于一起?
当您在 C 中创建结构时,例如:
typedef struct student
{
int roll_no;
char* name;
int* pointer;
}student;
我注意到 roll_no 和 name 没有连续存储在内存中。这是如何运作的?如果目标是封装这些数据,那么将它们连续存储不是更好吗?编译器如何知道这些数据属于一起?
编译器对齐结构的每个元素的开头以匹配体系结构的要求。这通常意味着对齐在单词边界上,但没有硬性规定。
typedef 对对齐没有影响——它只是为某个对象创建一个“速记引用”,可能就像一个结构。您可以将 typedef 视为同义词。
name
确实没有与struct
: 一起存储,只存储了一个指向它的指针。数据通常在其struct
自身之外的区域中动态分配。
要将名称与您一起存储,struct
您需要将其设为数组。这种方法的缺点是字符串必须是固定长度的(即所有struct
s 将分配足够的内存量以用于name
最大长度的 a ,或者您需要通过name[]
在struct
.最后一种方法的缺点是(1)分配变得更加复杂,(2)你不能制作这样的数组struct
,以及(3)你可以在一个结构中只有一个灵活的数组。
它们是连续存储的。只是 char *name 中包含的地址在其他地方。要在内存中连续存储,请使用数组而不是指针。
这就是它在内存中的存储方式,例如,struct 的地址从 1000(十进制)开始。
1000 roll_no
1004 name
1008 pointer
name 和 pointer 是指针,因此它们将保存 malloc 分配的值(地址)。
s->name = malloc(100);
s->pointer = malloc(4);
在这种情况下,没有结构填充,因为所有都是整数(甚至指针也是),这意味着它们是体系结构寄存器大小的大小(通常是 32 或 64 位)。
数据是连续存储的,但是由于优化和对齐字边界,可能存在整体。对齐方式取决于您运行的处理器和选择的编译器选项。(包装)
编译器将计算结构的偏移量,因此它可以查找内存以获取结构的元素。
实际上在结构中
struct student
{
int roll_no;
char* name;
int* pointer;
}
C 完全符合您的要求(除了“结构填充”,但这是另一回事)。假设gcc
在英特尔处理器上,结构由
int
,后跟char *
指向name的指针,后跟int *
指针指针name成员是指向 char(s)的指针,通常是指向内存某处的字符串的指针。例如
char *string = "John Doe";
int value = 255;
struct student me;
me.roll_no = 15;
me.name = string;
me.pointer = &value;
这里的字符串在内存中的某个地方——正如你注意到的,它是在结构之前声明的。假设它的内存位置是0x12345678
,值是在0x20000000
,结构是在 0x22222222 所以我们有
0x12345678 : John Doe\0
...
0x20000000 : FF000000 // 255
...
0x22222222 : 0F0000001234567820000000
您会看到结构是0F000000
for 15
,12345678
用于字符串地址和20000000
用于值地址。