在结构和结构指针之间混淆

时间:2015-05-19 12:49:09

标签: c++ c pointers structure

我想知道

之间的区别
struct file_operations {

} a;

struct file_operations {

} *a;

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

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

3 个答案:

答案 0 :(得分:5)

在第一种情况下,结构的实例在内存中分配,分配的字节数等于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的有效实例之前无法访问这些字段,否则会发生未定义的行为,您可以通过获取{{1}的地址来创建此类实例我们已经在上面初始化了,就像这个

struct Data data;

指针对象的生命周期限制了指针的有效生命周期,一旦你离开声明pointer = &data; 的范围,那么指针将指向垃圾,因为data将被释放

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

sizeof(struct Data)

之后,首先检查内存是否已分配,当出现问题pointer = malloc(sizeof(struct Data)); 保证返回特殊的poitner malloc()时,它是一个无效的poitner,可帮助您检查是否{{1}实际上是指向有效的内存,

NULL

在这种情况下,指针有效,直到你决定它为止,当你这样做时,你必须像这样调用poitner

if (pointer != NULL) 
{
    pointer->quantity = 1;
    pointer->value = 3.0;

    strcpy(pointer->name, "My Name Is ...");
}

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

1 您也可以使用此语法free()使其独立于free(pointer); 的类型,因为pointer等于{{ 1}}。

答案 1 :(得分:2)

  

它们如何在内存中分配?

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

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

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

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

  

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

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

答案 2 :(得分:1)

两个语句都做两件事:(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是指针指向的地址。