C++使用 .或 -> 表示链表
C++ what is the difference between using . or -> for linked list
假设我有一个结构。
struct node {
string info;
node link*;
}
有什么区别
node k;
node b;
k.info = "string";
b.info = "string";
k.link = &b;
和
node *k;
node *b;
k = new node;
b = new node;
k->info = "string";
b->info = "string";
k->link = b;
在内存分配方面?这两个例子是否正确,并创建了一个正确的链表添加:在大多数书中使用第二个例子,为什么?使用第一个例子有缺点吗?
是。两者在技术上都是正确的。
在第一个例子中,内存在堆栈上,在第二个例子中在堆上。
当内存在堆栈上时,"编译器"负责释放内存(当变量超出范围时)。由于您的链表可能比您显式创建的变量更长寿,因此这可能会导致各种问题。例如,在第一个示例中,如果b
超出范围,但k
没有,那么k
将有一个悬空指针,这将导致未定义的行为(也称为坏行为)。
当内存在堆上时,您必须管理内存,如果忘记释放内存,可能会导致问题。考虑到异常情况,这听起来更难。我建议你使用某种形式的智能指针。这是使用链表最常见、最安全的方法。
两者都是正确的,并将创建一个正确的链表,但第一个示例使用自动分配(全局或堆栈上,在范围内,取决于上下文),第二个示例使用动态分配(对于每个new
,您最终必须调用delete
)。
何时使用取决于程序的逻辑,但根据我的个人经验,通常链表是使用动态分配(第二个例子)完成的。
它与链表无关。
.
用于在结构对象已知时引用结构组件->
用于在结构对象的地址已知时引用结构组件
像
node k, *m, *n;
m = &k;
n = new node;
k.info = "Hello"; // k is a node type object so use directly . operator
m->info = "Hi"; // m is a pointer to an object to type node, so use -> operator
n->info = "Man"; // n is a pointer to an object to type node, so use -> operator
*(m).info = "This"; // *(m) refers to an object itself, we use . operator on it
*(n).info = "Is a test"; // *(n) refers to an object itself, we use . opeartor on it
所有这些都有有效的语法
- 在函数内部执行
node k;
时,它通常在堆栈上分配 - 当执行
static node k;
或将node k;
声明为全局时,它被分配在可执行文件的.data
或类似部分 - 当您使用
new
来分配一些内存时,它通常是从堆中分配的
在书中使用了第二个例子,因为您事先不知道会使用多少节点,所以将节点分配为具有大量变量定义的局部变量是不现实的。相反,指针用于临时分配内存,初始化它们,然后将其链接到列表的适当位置。将来,链表中指针链接的地址引用将允许我们按照链接的顺序访问链表的节点。通过这种方式,我们使用了node *k; k = new node;
,因此我们有一个类型为node
的对象的地址,因此使用k->info;
是很自然的,但您可以使用任何语法。您需要记住,->
的左手边应该是您想要访问的成员所属类/结构类型的地址,而.
运算符的左手边则应该是对象本身。
PS。使用完毕后,应通过delete
(使用new
分配的)释放内存。
不同之处在于删除节点的位置。
在第一个示例中,它们在从声明的函数返回时自动删除。您不能选择手动删除它们。
在第二个示例中,您需要使用"delete"关键字删除节点。这意味着它们不会被自动删除,但在节点停留的时间方面提供了更大的灵活性。
两者在技术上都是正确的。
差异:首先,内存将在堆栈上分配,您不需要负责释放内存等。编译器将负责所有事情。在第二种情况下,内存将在堆上分配,您需要注意释放内存。
为什么大多数书使用第二种方式:尽管您需要注意内存分配(使用new、malloc()等)和内存释放(delete、free()),但有几个优点:
-
很多时候,您需要访问变量范围之外的内存(例如:定义变量的外部函数)。如果不在堆上分配内存,就无法做到这一点。然而,如果你使用指针,你可以很容易地做到这一点。
-
您可以使用指针进行复杂而智能的操作。但是,这会使代码难以理解。
我建议你养成第二种方式的习惯,因为它是一种非常强大和聪明的方式(以代码复杂性为代价)。
正如已经指出的,这两种形式的区别在于第二个涉及动态分配,手动管理对象的生存期。由于第二个更复杂可能会问为什么会使用它。原因有两个:第一(已经提到)是对象的生存期对应于由编译器直接管理的生存期。第二就是你事先不知道元素的大小(或数量)。列表的大多数实现将动态分配的原因节点是因为您通常不知道确切的节点数量你需要提前。列表的全部意义在于它是一个动态结构,无固定尺寸。
此https://users.cs.jmu.edu/bernstdh/web/common/lectures/slides_cpp_dynamic-memory.php应清晰地解释动态内存分配
是。这两个例子都是正确的。指向对象的指针可以通过使用->
运算符访问结构和类中的函数。指针的内存将在堆上分配。对象使用.
运算符来访问函数。这些的内存将在堆栈上。
在处理动态分配的对象时,必须使用->运算符。例如:假设您有一个类List,它有一个返回Nodes的方法getRoot()。节点还具有getNext()方法,它为您提供列表中的下一个节点。
*List myList;
假设我们知道myList是一个有5个节点的列表。列表和5个节点位于堆中(动态分配)。现在,我们要访问最后一个节点。
myList->getRoot()->getNext()->getNext()->getNext()->getRoot();
(*(*(*(*(*myList).geRoot() ).getNext()).getNext()).getNext()).getNext();
这两个句子是等价的,将返回第五个也是最后一个节点。为了程序员的理智,使用第一个。
- 反向给定链表中的K节点
- 如果没有malloc,链表实现将失败
- 文本文件中的单词链表
- 努力将整数转换为链表。不知道我在这里做错了什么
- 链表,反向函数,数据结构
- 使用std::list创建循环链表
- 链表的泛型函数remove()与成员函数remove)
- 为什么不能修改对象中的值?另外,我如何改进此链表?
- 我们可以删除链表中静态内存中的节点吗
- C++,指针数组,指向双链表中的条目
- 链表中写入访问冲突的未知原因
- 如何修复链表类实现的未处理异常0xDDDDDDDD
- 打印所有链表的元素 (C++)
- 错误:需要类名(链表c++)
- 为什么C中的通用链表中存储的数据已损坏
- C++ 创建包含链表和字符串的对象的链接列表时出错
- 链表c++插入,所有情况都已检查,但没有任何工作
- 奇数链表表示形式
- C++:链表表示
- C++使用 .或 -> 表示链表