0

我只是想到一个关于指针的问题,指针 p 首先在 main 函数中初始并指向对象“a”
,然后调用函数 f ,并更改为指向对象“b”。
但“b”的范围仅在功能上。调用函数 f 后,为什么指针 p 仍然是指向“a”的指针。p 不应该是 NULL 还是别的什么?

 void f(int*p){
    int b = 10;
    p = &b;
}
int main(){

    int*p1 = NULL;
    int a=6;
    p1 = &a;
    f(p1);
    cout<<*p1<<endl;//output 6
    cout<<a<<endl;//output 6
    return 0;
}
4

4 回答 4

2

C++ 函数具有值语义,函数f复制指针p1,原始p1未修改。

f函数中,您试图将指针指向局部变量,这很危险。

如果您打算修改指针p指向,则需要传递指针的地址

void f(int*& p) // pass in reference to pointer
{
    static int b = 10;  // make it static, 
                        // so p won't become dangling pointer when f returns
    p = &b;
}
于 2013-11-05T10:34:49.230 回答
1

怎么了:

因为您按值传递指针,所以在函数中创建了一个本地副本f,然后您将另一个值(指向 b 的指针)分配给该副本并离开该函数。原始指针保持不变。

现在让我们假设,您通过以下方式修改函数:

void f(int * & p){
    int b = 10;
    p = &b;
}

不要在家里这样做!

现在,实际的指针被传递给函数,没有创建副本。然后将指向 b 的指针分配给它并返回函数。然后你尝试访问 - 一个值所指向p1的值,该值不再有效,因为b不再存在。你在这里得到一个未定义的行为:最好的情况是一切实际上都会像你想象的那样工作,最坏的情况是你会遇到访问冲突或更糟 - 你的程序的一些数据可能会被破坏(一切取决于在平台和编译器上)。

为什么 C++ 编译器不通知你呢?通常是因为 C++ 不应该照顾你,这样你就不会踢自己的脚(实际上,使用 C++ 有很多方法可以踢自己的脚,如果你堆叠包含这些的书籍,你会到达月球)。C++ 只是做你告诉它的事情。你想得到指针b吗?好的,没问题。你想从函数返回一个指针吗?为什么不呢,那只是一个 32 位整数值。

关键是,在用 C++ 编写时,你必须非常小心,不要编写这样的代码。


编辑:回应评论

想象一下,该数据是一座建筑物,而指针是一张带有该建筑物地址的纸。当您按值传递指针时:

void f(int * p)

就像您拿了另一张纸并复制了地址。如果您随后将其擦除并更改为另一张,则原始纸张上的原始地址将保持不变。

现在,如果您执行以下操作:

void f(int * p)
{
    *p = 4;
}

就像你真的去了纸上写的地址,改变了大楼里的东西。如果你然后去原始纸上存储的地址,建筑物将被改变。

最后,如果您执行以下操作:

void f(int * & p)
{
}

就像您将原始纸张传递给函数一样,因此如果您更改地址,它也会在函数之外更改。

希望这可以帮助您了解指针的工作原理。

于 2013-11-05T10:45:18.013 回答
0

当您的指针变得无效时,它不会神奇地采用不同的值或空值。它仍然指向同一个地方;只是那个地方不再有效。

于 2013-11-05T11:33:51.450 回答
0

这里指针是按值传递的,即函数 f 对其进行复制然后使用它,完成后将其销毁。初始指针 p1 不变。

于 2013-11-05T10:47:34.753 回答