【问题标题】:Segmentation fault on using memset instead of for loops to initialize int**使用 memset 而不是 for 循环初始化 int 时出现分段错误**
【发布时间】:2013-03-12 18:08:38
【问题描述】:

这是我的 C++ 代码

int** a;
try{
  a = new int*[m];
  for(int i = 0; i<m;i++)
    a[i] = new int[n];
}

... 现在我正在使用 for 循环初始化上述内容,如下所示:

for(int i = 0; i<m; i++)
  for(int j = 0; i<n; j++)
      a[i][j] = 0;

我正在努力提高性能,因此认为使用 memset 是个好主意。所以修改了我的代码以使用 memset 而不是 for 循环,如下所示:

memset(a, 0, sizeof(a[0][0]) * m * n);

但是我在执行这个时遇到了分段错误。谁能帮我弄清楚我做错了什么?

【问题讨论】:

  • 您是否在代码中的任何位置为“a”分配内存?
  • 对不起,我错过了添加内存分配。 a = new int*[m]; for(int i =0; i&lt;m ;i++) a[i] = new int[n];
  • 好的,现在问题很清楚了 - 添加了一个答案。

标签: c++ linux arrays pointers multidimensional-array


【解决方案1】:
int** a;

这只是给你一个对象。 int** 对象。它根本没有指向任何地方。没有要分配给的 ints。当您开始分配给ints,就好像它们存在一样,您会得到未定义的行为。

此外,指向ints 的“二维数组”的int** 的内存布局如下:int** 指向int*s 数组中的第一个元素,而int*s 指向ints 数组中的第一个元素。该内存不是连续的,因为它需要间接跳转内存,即它不是单个内存块。您不能只使用memset 给它写信。

如果您只想要一个ints 的固定编译时大小的二维数组,请执行以下操作:

int a[N][M];

其中NM 是常量表达式。这个连续存储的,但我还是不推荐使用memset

或者使用标准容器,如:

std::array<std::array<int, M>, N> a;

如果您需要动态大小,请尝试:

std::vector<std::vector<int>> a(M, std::vector<int>(N));

或者,您可以坚持使用int**,并确保动态分配int*s 和ints:

int** a = new int*[M];
for (i = 0; i < N; i++) {
  a[i] = new int[N];
}

但这很丑!

【讨论】:

  • int a[N][M]; - 作为 C99 的一部分,也可作为 GCC 的扩展,可变长度数组不是 C++ 标准的一部分。
  • @LihO 其中NM 是常量表达式。
  • 你现在正在使用你刚刚描述的丑陋部分。所以会改进它
【解决方案2】:

使用int **,您通常不会拥有一个连续的内存块。假设您正确使用它,您将拥有一个指针数组。然后,这些指针中的每一个都将分别为其分配一个数组。

在这种情况下,您无法将循环转换为单个 memset(并且仍然获得定义的行为)。

【讨论】:

    【解决方案3】:

    我认为问题在于未分配用于实际存储的内存。变量 a 只是指针(此外未初始化)。它指向什么地方?

    【讨论】:

      【解决方案4】:
      int** a;
      

      只是一个指向int的指针的声明。

      “现在我正在使用 for 循环初始化上述内容”

      您没有在 for 循环中对其进行初始化,您只是试图将 0 分配给不存在的元素,这会产生 未定义的行为。您需要为这些元素动态分配内存,甚至更好:改用std::vector

      std::vector< std::vector<int> > a(m, std::vector<int>(n, 0));
      

      “我正在努力提高性能”

      除非必要,否则不要这样做。 不要过早优化。


      编辑:在您提到您已经面临性能问题之后,您可以这样做:代替这个二维 C 样式数组:

      int** a = new int*[m];      // m = number of rows
      for(int i = 0; i < m; i++)
          a[i] = new int[n];      // n = number of columns
      

      你可以使用一维std::vector:

      std::vector<int> vec(rows * cols, 0);
      ...
      vec[i * cols + j] = 7;   // equivalent of vec[i][j]
      
      这将有更多的优势:
      • 您的二维数组将存储在连续的内存块中
      • 这块内存会被一次性分配,不会分成很多小块
      • 由于空间局部性,元素的频繁访问会更快
        (“附近”的元素将在缓存内存中可用,因此您的
        程序不必从主内存中加载它们)
      • 并且您将不负责内存管理
        (一旦vector对象被销毁,内存会自动清理)

      【讨论】:

      • 我试图优化它的主要原因是使用 for 循环需要很长时间,我必须减少它
      • 您确定for 循环需要很长时间吗?您是否使用最近的编译器进行编译(例如 GCC 4.7 或 4.8 中的 g++)并启用了优化(例如 -O2-O3)?
      • 我现在看到了不同之处。我使用 g++ 编译并启用了优化,而且速度更快。但是我试图优化的实际代码确实使用了这些选项。谢谢
      • @user2175966:现在看我的答案,行下的部分:)
      【解决方案5】:

      你说你是这样分配的:

      a = new int*[m]; 
      for(int i =0; i<m ;i++) a[i] = new int[n];
      

      就像 Jerry Conffin 所说的那样——这不会给你一个单一的、连续的内存块。 每个新数组 (new int[n]) 将被分配在一个可能完全不同的位置,并且 memset 仅适用于连续块,因此您必须“手动”重置它们中的每一个 顺便说一句 - 我很确定你不会看到在循环上使用 memset 带来的任何性能改进(我认为 memset 本身使用循环实现)。

      【讨论】:

        猜你喜欢
        • 2016-06-03
        • 2011-10-29
        • 2020-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-20
        • 1970-01-01
        相关资源
        最近更新 更多