堆内存的范围

时间:2014-04-23 16:32:51

标签: c++ pointers memory memory-management

据我所知,堆本应该是全球性的,不是吗?所以我们应该能够在函数中的任何地方访问堆内存。那么为什么以下代码会出现段错误(Segmentation Fault)?

#include <stdio.h>
using namespace std;

void A(int* x)
{
  x = new int[10];
  for(int i = 0; i< 10; i++)
  {
    x[i] = i;
  }
}

void B(int *x)
{
  printf("%d", x[8]);
}

int main()
{
  int* a = NULL;
  A(a);
  B(a);
  return 0;
}

4 个答案:

答案 0 :(得分:9)

发生分段错误是因为指针a正在按值传递,因此A()内的更改对调用者不可见,导致NULL指针在B()内被解除引用{1}}。要更正,请通过引用传递指针A()

void A(int*& x)

答案 1 :(得分:2)

正如其他答案所示,问题确实是A()中分配的内存未传递给B()

但值得注意的是,您可以使用免费提供的工具使用静态分析来检测此问题。

当我在你的例子上运行clang++ version 3.4时,它会给出:

$ make
clang++ -Wall -Wextra --analyze   -c -o go.o go.cpp
go.cpp:16:16: warning: Array access (from variable 'x') results in a null pointer dereference
  printf("%d", x[8]);
               ^~~~
1 warning generated.

有多棒啊在这个特殊的独立示例中,编译器评估路径的额外时间可以忽略不计。 “真实”代码可能会有点开销(不是像这样的合成示例)。但对于大多数用户来说,这几乎肯定是值得的。

答案 2 :(得分:2)

问题:据我所知,堆本应该是全球性的,不是吗?

答案:是。

声明:因此我们应该能够在我们的函数中的任何地方访问堆内存。

责任:是的,只要我们知道堆内存值,我们就能够。

问题:那为什么以下代码会出现段错误(Segmentation Fault)?

答案:在一个函数中分配堆内存并不能保证内存值在其他函数中可见。 operator new返回的地址必须以某种方式提供给其他功能。您可以通过以下几种方式完成此操作:

  1. 根据Subhajit的建议将参数类型更改为int*& a

  2. A返回已分配的内存地址。

    int* A()
    {
      int* x = new int[10];
      for(int i = 0; i< 10; i++)
      {
        x[i] = i;
      }
      return x;
    }
    

答案 3 :(得分:1)

对于a,A(a)和B(a)呼叫都是按值。因此,A()或B()内的任何更改都不会影响调用者。

请致电,

void A(int*& a);