【问题标题】:pointer to structures in C/C++指向 C/C++ 中的结构的指针
【发布时间】:2014-08-17 11:50:36
【问题描述】:
#include <iostream>
using namespace std;
typedef struct node NODE;

struct node{
    int value;
    NODE *next;
};



void addNode(NODE *prev)
{
    NODE* next=(NODE*)malloc(sizeof(NODE));
    int value;
    cin>>value;
    next->value=value;
    while(prev->next!=NULL)
    {
        prev=prev->next;
    }
    prev->next=next;
    next->next=NULL;
}


int main()
{
    int ch;
    NODE* curr=(NODE*)malloc(sizeof(NODE));
    NODE* trav;//=(NODE*)malloc(sizeof(NODE));
    trav=curr;
    curr->value=10;
    curr->next=NULL;
    while(true)
    {
        cin>>ch;
        switch(ch)
        {
            case 1:
            {
                addNode(trav);
                //trav=next;
                break;
            }
            case 2:
            {
                trav=curr;
                while(trav!=NULL)
                {

                    cout<<trav->value<<endl;
                    trav=trav->next;
                }
                break;
            }
            case -1:{break;}

        }
        if(ch==-1)break;
    }

    free(curr);
    free(trav);
}

我试图实现链表数据结构。上面的代码运行良好,但是,我不明白一件事。我什至没有创建结构节点的单个实例,它们都是简单的指针,我在堆上为这些指针分配内存。节点实际存储在哪里,因为根据我的说法,指针只存储地址而没有其他内容。就像我使用 next->value 时一样,该值存储在哪里? 通常我都是这样使用指针的。

int a; 
int *p;
p=&a;

现在,我知道在内存中的某个点有一个存储的并且 p 指向那个位置。然而,在这些节点结构中,没有真正的实例,只是在堆上分配内存。

它是如何工作的?

【问题讨论】:

  • 嗯?您在所有malloc 行上创建节点实例。节点的存储在您 malloc'd 的内存中。
  • 当它是 C++ 时为什么要标记 C?为什么在使用 C++ 时使用malloc
  • 在 C++ 中你可以避免 malloc 使用 new 和 free 和 delete。
  • @pqnet:其实是C++:这是一个需要被符合标准的C++编译器接受的程序。它肯定不是 C++。
  • 使用malloc/free 是它的问题之一,是的。这些函数是为了与 C 兼容,不应在纯 C++ 代码中使用。另一个问题是您在使用它们时没有包含适当的标头(iostream 不需要间接包含该标头;当我声称需要编译代码时,我没有注意到该问题,实际上是由于该问题't)。此外,typedef struct node NODE 在 C++ 中没有任何意义;由于定义为struct node 的类型可以引用为node,因此typedef 只是添加了一个多余的名称而不需要。

标签: c++ pointers data-structures struct


【解决方案1】:

通过您的第二个代码示例,通常您会用指针指向现有变量,这是可以理解的。

好吧,现在你自己创建它们(使用 malloc)。 它们是在称为的内存的不同部分中创建的,它们真实的实例。就像它们在堆栈上是真实的一样。 malloc 只是“找到”一个空间供您存储它们。

链表在堆上看起来像这样:

请注意,链表仅包含:head(8) -> 3(10) -> -7(2) -> 13(14) -> 5(0)。
此列表不使用堆的所有其他部分。

找到图片来源here

【讨论】:

  • 非常感谢,我现在很清楚了。我认为 malloc 只是返回一个指向内存位置的指针,不会导致任何实例的创建。
  • @chintanshah 我看不出这张(令人困惑的)图片比我的回答中所说的更清楚地说明了这一点(尤其是它如何显示为了解决任何问题应该做什么),但是当你希望:P ...
  • @πάνταῥεῖ,感谢您的回答。我的疑问是,当我使用指向结构的指针时,实际上没有指针指向的实例。这个答案让我明白 malloc 确实创建了一个实例,但是在堆上。我认为 malloc 返回结构的起始地址?
  • @chintanshah malloc() 将起始地址返回到堆上的一块内存,这至少保留了足够的空间来存储NODE 的有效实例,但与new() 不同的是没有该实例的初始化已完成。
  • @arnon-zilca 放图片看起来很性感,但并不能真正解释真正的问题/误解是什么:P ...
【解决方案2】:

诀窍在于malloc 只是分配内存,但不在那里构造对象,struct node 是所谓的 POD 类型(“POD”代表“Plain Old Data”),这意味着,除了其他属性,它的最小“构造”包括什么都不做。

当然,如果你省略了无所事事的步骤,那当然也没有什么坏处。也就是说,如果您为某个内存位置分配该类型的值,就会“神奇地”生成一个 POD 类型的对象。事实上,该标准明确允许 POD 类型这样做。

关于如何识别 POD 类型的问题:经验法则是 POD 类型是您也可以在 C 中使用的类型。

【讨论】:

    【解决方案3】:

    然后我将内存分配给堆上的这些指针。

    “当我使用 next->value 时,该值存储在哪里?”

    正如您所提到的,value 成员也存储在堆上。 sizeof(NODE) 语句将确保保留必要的内存。


    “没有真正的实例,只是在堆上分配内存。”

    就 c++ 而言,这句话几乎是正确的,至少这些 实例 没有正确初始化。尽管保留的内存被视为那里存储了通常的 c++ 实例。
    要实现标准c++ struct/class 初始化,你可以改变你的addNode()函数如下

    void addNode(NODE *prev) {
        NODE* next = new NODE(); // Use the new() operator for c++ struct/class
                  // ^^^^^^^^^^^ // initialization
        // ...
    }
    

    malloc() 仅提供堆上的内存分配,而 c++ new() 运算符将确保在内存分配发生后调用任何适当的构造函数(也包括编译器默认创建的构造函数)。对于 c++,编译器为结构/类成员提供标准初始化,除非定义了显式构造函数和成员初始化。

    注意:
    如果您使用new() 运算符,您必须使用delete 而不是free() 来释放分配的内存。与new() 保证调用构造函数类似,delete 保证正确调用析构函数。


    线条

    free(curr);
    free(trav);
    

    无论哪种方式都不会按照您的预期行事。你应该有某种LinkedList 结构/类,或者至少是一个固定的NODE* head 引用,它跟踪分配的内存/实例并在超出范围时删除它们。

    您将需要std::list&lt;T&gt; 类提供的某种内存管理。也许你可以直接使用它,而不是自己酿造。

    【讨论】:

      猜你喜欢
      • 2021-07-14
      • 2016-08-25
      • 1970-01-01
      • 2021-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多