我正在學習 C ,在解決 HackerRank 平臺上的挑戰時遇到了一些有趣的事情。代碼來自鏈表問題。display目標是用類中的方法顯示鏈表Solution。我注意到我必須在初始化類實體時使用 new 關鍵字才能使其正常作業,否則代碼不會檢測到串列的結尾。請參閱以下兩個代碼及其各自的輸出。
為什么在第二個代碼示例中未使用new關鍵字時未正確檢測到鏈表的末尾?我在互聯網上讀到不鼓勵使用new,因為之后需要明確洗掉指標以避免記憶體泄漏,所以我很困惑。
兩個代碼都使用相同的以下輸入:
輸入
4
2
3
4
1
代碼 1
#include <iostream>
#include <cstddef>
using namespace std;
class Node
{
public:
int data;
Node *next;
Node(int d){
data=d;
next=NULL;
}
};
class Solution{
public:
Node* insert(Node *head,int data)
{
//Complete this method
Node* new_node = new Node(data); //Check this line
if (head) {
Node *current = head;
while(current->next) {
current = current->next;
}
current->next = new_node;
}
else
{
head = new_node;
}
// Node** pp = &head;
// while (*pp) {
// pp = &((*pp)->next);
// }
// *pp = new Node(data);
return head;
}
void display(Node *head)
{
Node *start=head;
while(start)
{
cout<<start->data<<" ";
start=start->next;
}
}
};
int main()
{
Node* head=NULL;
Solution mylist;
int T,data;
cin>>T;
while(T-->0){
cin>>data;
head=mylist.insert(head,data);
}
mylist.display(head);
}
輸出 1(正確)
2 3 4 1
代碼 2
#include <iostream>
#include <cstddef>
using namespace std;
class Node
{
public:
int data;
Node *next;
Node(int d){
data=d;
next=NULL;
}
};
class Solution{
public:
Node* insert(Node *head,int data)
{
//Complete this method
Node new_node(data);
if (head) {
Node *current = head;
while(current->next) {
current = current->next;
}
current->next = &new_node;
}
else
{
head = &new_node;
}
// Node** pp = &head;
// while (*pp) {
// pp = &((*pp)->next);
// }
// *pp = new Node(data);
return head;
}
void display(Node *head)
{
Node *start=head;
while(start)
{
cout<<start->data<<" ";
start=start->next;
}
}
};
int main()
{
Node* head=NULL;
Solution mylist;
int T,data;
cin>>T;
while(T-->0){
cin>>data;
head=mylist.insert(head,data);
}
mylist.display(head);
}
輸出 2(不正確)
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1....
uj5u.com熱心網友回復:
雖然 using 確實new需要顯式解除分配,但這也意味著如果您不使用 using new,那么物件的生命周期已經以某種方式被隱式管理。
這是在您的第二種情況下發生的情況:
Node new_node(data);
head = &new_node;
在這里,您實際上是在獲取區域變數的地址并將其分配給全域變數。但是當函式回傳并且您存盤的地址不再有效時,區域變數本身不再存在。
相反,當您使用new時,物件的記憶體被分配在一個獨立的堆中,并且只要您不這樣做就一直存在delete。
PS。在 c 中,您可以(并且應該)nullptr使用NULL
uj5u.com熱心網友回復:
如前所述,當函式回傳時,您的資料結構指向一個已經超出范圍的本地物件。訪問不存在的物件會導致未定義的行為。
您似乎試圖避免使用new. 避免顯式使用的一種方法new是使用智能指標來表示您的Node.
基于的解決方案unique_ptr可能類似于:
struct Node;
using NodePtr = std::unique_ptr<Node>;
因此new,您可以使用而不是呼叫make_unique。
class Node {
friend class Solution;
int data_;
NodePtr next_;
static NodePtr make (int d) {
return std::make_unique<Node>(d);
}
public:
Node (int d) : data_(d) {}
};
為避免搜索最后一個元素,您可以在串列中始終保持對最后一個元素的參考。我實作了一個被呼叫的墊片NodeRef,std::reference_wrapper使它更像一個指標。
class Solution {
NodePtr head_;
NodeRef tail_;
public:
Solution () : tail_(head_) {}
void insert (int d) {
*tail_ = Node::make(d);
tail_ = tail_->next_;
}
void display () {
NodeRef p = head_;
while (p) {
std::cout << p->data_ << ' ';
p = p->next_;
}
}
};
在線嘗試!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/440917.html
上一篇:使用遞回函式傳遞結構的指標
下一篇:類構造中的C 指標
