混淆了结构和结构指针

Confused between structures and strucutre pointers

本文关键字:结构 指针      更新时间:2023-10-16

我想知道之间的区别

struct file_operations {
} a;

struct file_operations {
} *a;

它们在内存中是如何分配的?在第一种情况下,编译器如何知道"a"的内存位置?它来自符号表吗?如果是,如何找到地址到符号表(或任何其他表(?

在第二种情况下,我假设内存地址存储在一个大小为32位的变量中,这个变量的位置(第二个代码中"a"的地址(是如何计算出来的?

在第一种情况下,在内存中分配结构的实例,分配的字节数等于sizeof(a)返回的值。

在第二种情况下,分配指针,分配的字节数等于指针的大小,即sizeof(void *)

正如您可能猜测的那样,第二种情况不允许您访问结构的字段,因为指针指向的内存是无效的,直到您从堆中请求足够的内存,或者直到您使其指向像第一个示例中那样的实例。

假设我们有以下结构

struct Data {
    int    quantity;
    double value;
    char   name[100];
};

如果您执行以下

struct Data data;

然后分配struct Data的实例,您可以立即访问它的字段,例如

data.quantity = 1;
data.value = 3.0;
strcpy(data.name, "My Name Is ...");

如果你声明一个指针,比如

struct Data *pointer;

然后,在指针指向struct Data的有效实例之前,您不能访问字段,否则将发生未定义的行为,您可以通过获取上面已经初始化的struct Data data;的地址来创建这样的实例,就像这个

pointer = &data;

指针对象的生存期限制了指针的有效期,一旦超出声明data的范围,指针将指向垃圾,因为data将被释放。

另一种使指针有效的方法是使用malloc(),即通过从系统堆请求内存,这是通过请求sizeof(struct Data)字节来完成的,就像这里的1

pointer = malloc(sizeof(struct Data));

之后,您首先检查内存是否已分配,当出现问题时,malloc()保证返回一个特殊的poitner NULL,它是一个无效的poitn,可以帮助您检查poitner是否真的指向有效内存,

if (pointer != NULL) 
{
    pointer->quantity = 1;
    pointer->value = 3.0;
    strcpy(pointer->name, "My Name Is ...");
}

在这种情况下,指针是有效的,直到你决定它不是,当你这样做时,你必须像这个一样调用free()

free(pointer);

之后,如果您再次尝试访问指针,将发生未定义的行为。


1您还可以使用此语法pointer = malloc(sizeof(*pointer));使其独立于pointer的类型,因为sizeof(*pointer)等于sizeof(struct Data)

它们是如何在内存中分配的?

在这两种情况下,都取决于变量的定义位置。

在命名空间范围(C++(或文件范围(C(中,它是一个全局变量,在程序启动时分配一个地址。通常,正如您所说,这是由符号表指定的。

在块范围内,它是一个自动变量,通常在程序达到定义之前的一段时间,在函数的堆栈帧上分配内存。

在类范围内,它是包含它的类的一部分

在第二种情况下,我假设存储器地址存储在32位大小的变量中

不管指针有多大,在32位平台上,它都是32位。在这种情况下,没有file_operations对象,只有一个指针。

这两个语句都做两件事:(1(定义一个名为struct file_operations的结构,(2(声明该类型的未初始化变量。

第一个是在堆栈上(或者在静态存储中,如果在函数之外(分配结构大小的空间。然后可以像a.member1 = 1一样访问结构的数据成员。在函数内部时,a在堆栈上。它就像任何其他变量声明一样,例如int a。如果在函数外部,则声明一个全局变量。其成员地址可以使用&a找到。编译器在编译时使用一个符号表,该表指示每个令牌的类型、相对地址等。

当声明全局变量并编译到库中时,它还会在二进制文件的符号表中生成一个符号,以便链接器可以链接它。

第二种情况声明了一个指向struct file_operations的指针。指针是一个包含成员地址的变量,因此在您的情况下,它的大小为4字节。它的类型是struct file_operations *,这表示它所指向的数据的类型必须是struct file_operations。此处的变量未序列化。指针不包含有效的地址,取消对其的引用将失败。使用它:

struct file_operations a;
struct file_operations* pa = &a;

将使pa指向a。则a的成员可以通过pa经由pa->member1 = 1进行访问。指针本身的地址&pa也在堆栈上(或者在函数外部时在静态内存中(。&pa是指针的地址,也就是指向指针的指针。pa是指针指向的地址。