堆内存的作用域

Scope of Heap Memory

本文关键字:作用域 内存      更新时间:2023-10-16

据我所知,堆在本质上应该是全局的,不是吗?因此,我们应该能够在函数中的任何位置访问堆内存。那么为什么下面的代码是segfault(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是按值传递的,因此调用方看不到在A()内所做的更改,从而导致NULL指针在B()内被取消引用,因此会发生分段错误。要更正,请通过引用A():传递指针

void A(int*& x)

正如其他答案所示,实际上问题是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.

在这个特殊的独立示例中,编译器评估路径的额外时间可以忽略不计,这真是太棒了。这可能会在"真实"代码(而不是像这样的合成示例)上增加一些开销。但对于大多数用户来说,这几乎是值得的。

问题:据我所知,堆在本质上应该是全局的,不是吗?

答案:是。

语句:因此,我们应该能够在函数中的任何位置访问堆内存。

响应:是的,只要我们知道堆内存值,我们就可以。

问题:那么为什么下面的代码是segfault(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;
    }
    

对于A,A(A)和B(A)调用都是按值。因此,A()或B()内部的任何更改都不会受到调用方的影响。

请致电,

void A(int*& a);