堆内存的范围

3
据我所知,堆(heap)的性质是全局的,对吗?因此,我们应该能够在任何需要的地方访问堆内存。那么为什么下面的代码会出现段错误(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;
}

A的_input_参数应该如何影响B - MSalters
4个回答

9

出现分段错误是因为指针 a 被按值传递,因此在 A() 中所做的更改对调用者不可见,导致在 B() 中解除引用了一个 NULL 指针。要纠正错误,请通过引用将指针传递给 A()

void A(int*& x)

2

问题: 据我所知,堆应该具有全局性质,对吗?

答案: 是的。

陈述: 所以我们应该能够在任何需要的函数中访问堆内存。

回应: 是的,只要我们知道堆内存的值,我们就可以在任何需要的函数中访问它。

问题: 那么为什么下面的代码会导致段错误(Segmentation Fault)?

答案: 在一个函数中分配堆内存并不能保证其他函数能够看到该内存值。由operator new返回的地址必须以某种方式可供其他函数使用。你可以通过以下几种方式实现:

  1. Change the argument type to int*& a, as suggested by Subhajit.

  2. Let A return the allocated memory address.

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

2
正如其他答案所示,问题确实在于在A()中分配的内存没有传递给B()
但值得注意的是,您可以使用免费提供的工具进行静态分析来检测此问题。
当我在您的示例上运行clang++版本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.

这太棒了!在这个独立的例子中,编译器评估路径所需的额外时间几乎可以忽略不计。对于“真实”的代码(而非像这些合成的例子),可能会有更多的开销。但对于大多数用户来说,这几乎肯定是值得的。


1

A(a) 和 B(a) 都是针对 a 的按值传递。因此,A() 或 B() 中的任何更改都不会影响调用者。

请按如下方式调用:

void A(int*& a);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接