Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么对象在作为指针传递时超出范围,而在返回时却不超出范围_C++_Scope_Pass By Reference_Pass By Value - Fatal编程技术网

C++ 为什么对象在作为指针传递时超出范围,而在返回时却不超出范围

C++ 为什么对象在作为指针传递时超出范围,而在返回时却不超出范围,c++,scope,pass-by-reference,pass-by-value,C++,Scope,Pass By Reference,Pass By Value,制作一个非常简单的链表,我发现自己对什么可能是一个非常简单的范围界定概念感到困惑。第一个按预期工作。在第二个makeNode函数中,节点“n”似乎在终止时超出范围。我不明白为什么会这样 我很确定分配的内存仍然存在,并且两个方法都有一个指向该内存的指针。那为什么一个不起作用呢 该程序有两个生成节点功能 #include <iostream> using namespace std; struct Node { int value; Node* next; No

制作一个非常简单的链表,我发现自己对什么可能是一个非常简单的范围界定概念感到困惑。第一个按预期工作。在第二个makeNode函数中,节点“n”似乎在终止时超出范围。我不明白为什么会这样

我很确定分配的内存仍然存在,并且两个方法都有一个指向该内存的指针。那为什么一个不起作用呢

该程序有两个生成节点功能

#include <iostream>
using namespace std;

struct Node
{
    int value;
    Node* next;
    Node() : next(NULL){}
};

Node* makeNode1(int value)
{
    Node* n = new Node;
    n->value = value;
    return n;
}

void makeNode2(int value, Node* mountPt)
{
    Node* n = new Node;
    n->value = value;
    mountPt = n;
}

void destroyNode(Node* mountPt)
{
    if(mountPt->next != NULL)
    {
        destroyNode(mountPt->next);
        delete mountPt;
    }
}

int main() {
    Node* origin = NULL;

    // This works
    origin = makeNode1(4);

    // causes a runtime error when dereferenced
    makeNode2(4, origin);

    return 0;
}
#包括
使用名称空间std;
结构体类型
{
int值;
节点*下一步;
Node():下一个(NULL){}
};
节点*makeNode1(int值)
{
Node*n=新节点;
n->value=value;
返回n;
}
void makeNode2(int值,节点*mountPt)
{
Node*n=新节点;
n->value=value;
mountPt=n;
}
无效销毁节点(节点*mountPt)
{
如果(mountPt->next!=NULL)
{
销毁节点(mountPt->next);
删除mountp;
}
}
int main(){
Node*origin=NULL;
//这很有效
原点=makeNode1(4);
//取消引用时导致运行时错误
makeNode2(4,来源);
返回0;
}

对于
makeNode2
指针参数
mountPt
通过值本身传递,然后在函数内对指针本身进行任何修改,如
mountPt=n
与原始参数
origin
无关

您可以将其更改为通过引用传递,即

void makeNode2(int value, Node*& mountPt)

在第一个实例中,您正在创建一个新的内存段,其中包含指向该内存段(它只是一个地址)的指针,然后返回该地址。第二个示例传入指向内存中地址的指针,然后在函数范围内重新分配该地址(即更改该值)。但是,一旦函数退出,该指针的值(它引用的地址)将恢复到其以前的调用,因为指针在堆栈上已经有值。不同之处在于,在第一次调用中,您更改了存储在最终从函数中传递出去的地址中的值,而在第二次调用中,您更改了指针指向的地址,但一旦将作用域更改回主体,指针将返回到旧地址。

更改以下函数:

void makeNode2(int value, Node* mountPt)
{
    Node* n = new Node;
    n->value = value;
    if(mountPt) delete mountPt;
    mountPt = n;
}

如果已经分配了mountPt,它将被释放,然后
origin
可以指向分配
n
X-Y解决方案:通过扩展节点构造函数消除对
makeNode
函数的需要

struct Node
{
    int value;
    Node* next;
    Node(int val = 0) :value(val), next(NULL){}
};
用法

Node * origin = new Node(4);

尽管以上所有内容——包括公认的答案——都是相关的,但没有一个直接指向实际的逻辑缺陷。而不是
mountPt=n,您需要
mountPt->next=n > /p>打开C++书中的章节,解释通过函数传递函数参数的差异,而不是通过引用传递函数,并读取它。您通过值传递它,并且
makeNode2
泄漏内存。传递给的指针未初始化,并且在调用程序中保持未初始化状态,因为它是按值传递的。这就是C++的工作原理。在 MaKeODE2中存在漏洞,如果添加(unt)删除安装,则应该添加行<代码>;code>确保先删除以前的分配,然后分配
n
。Vuwox是正确的。@Amadeus是的,我理解上面的编译,但没有删除,此函数会造成内存泄漏。通过添加它,编译器将不会提供
参数'mountPt'集但未使用
将使用完整警告级别,并且运行时错误也不会追加。通过值传递指针仍将允许您永久更改存储在地址中的值,但不允许您更改指针指向的内容。“返回”这是一个糟糕的描述方式。源从未更改。请注意,这样做会导致内存泄漏;在
makeNode1
中分配的原始
origin
指针将被在
makeNode2
中分配的新指针替换,而不进行
delete
-ed。我知道。显然,只需要一个功能。我只是简单地展示了这两种配置。我同意这将是更好的内存管理,但这不会有相同的作用域问题吗?@mreff555是的,它会。它实际上没有。但是,如上所述,如果将引用操作符附加到Node*参数,则它可以工作