【问题标题】:Access violation writing error on writing to a 2D array after initializing using memset使用 memset 初始化后写入二维数组时出现访问冲突写入错误
【发布时间】:2018-03-02 15:48:06
【问题描述】:

我正在使用 Visual Studio Community 2017。

按照下面的讨论:

Fastest way to zero out a 2d array in C?

我有一个使用memset 初始化的二维矩阵 (10 x 10)。这是选项 1。

选项 2 使用两个 for 循环初始化同一个矩阵,每个循环从 0 到 9。

然后,当我写入有效的矩阵位置时,使用选项 1 时会引发访问冲突写入错误。使用选项 2 时一切正常。

我拥有的用于复制它的最小工作代码如下:

#include <stdio.h>
#include <conio.h>
#include <time.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <stdlib.h>
#include <math.h>
#include <cmath>
#include <vector>
#include <string>
#include <limits.h>
#include <stdlib.h>
#include <array> 



int main(){
    double ** cmatrix = new double*[10];
    for (int i = 0; i < 10; i++)
        cmatrix[i] = new double[10];

    memset(cmatrix, 0, 10 * 10 * sizeof(double));//Option 1    

    //for (int i = 0; i < 10; i++)//Option 2
        //for (int j = 0; j < 10; j++)
            //cmatrix[i][j] = 0;

    cmatrix[0][1] = 5;//This step produces error on Option 1, but not on option 2

    return 0;
}

感谢任何帮助。

【问题讨论】:

  • memset 要求要填充的内存是一个连续区域,但您有 11 个单独的分配。
  • 不要在 C++ 中使用 C 问题的答案。它们是不同的语言;为此使用memset 既没有必要也不是一个好主意。
  • 顺便说一句,如果您只想将所有内容设置为零,您应该使用calloc。话虽如此,在 C++ 中使用 malloc/calloc 是总是不正确的做法,没有例外。

标签: c++ memset


【解决方案1】:

使用memset,您将覆盖内存分配返回的指针,因此当您稍后访问内存时,实际上是在延迟一个空指针。

您的 2D 数组实际上是一个指针数组,因此内存不是连续的,您不能通过 memset 将其设置为 0。从技术上讲,它只是一个指针,您可以动态地为另外 10 个指针分配空间,每个指针其中指向 10 个双打。

改为使用双循环(嵌套fors)来初始化它,或者每行只使用一个memset:

for (int i = 0; i < 10; ++i)
  for (int j = 0; j < 10; ++j)
    cmatrix[i][j] = 0.0;

// or

for (int i = 0; i < 10; ++i)
  memset(cmatrix[i], 0, 10 * sizeof(double));

此外,如果您的数组始终为 10x10,您可以将其声明为 double cmatrix[10][10]:该内存是连续的,您可以使用原始的 memset。

【讨论】:

  • 谢谢。是的,我能够验证它是否适用于一维数组的 memset。因此,对于二维数组,我将使用您的建议。
  • "你的二维数组实际上是数组的数组,所以内存不连续"这是不正确的。它实际上是一个指针数组。如果它是一个数组数组,内存会是连续的。
  • @Lundin 感谢您的更正,我会修复更具体的答案
  • 如果你有一个连续的数组,你可以做double cmatrix[10][10] = {};,编译器会为你清除它。不需要memset。
【解决方案2】:

cmatrix 是一个指针数组。 将memset 调用为零,实际上会将所有指针设置为 0(这不是您想要的),这会导致稍后的访问冲突。 对于这种初始化,我会选择选项 2(cmets 中的那个)

【讨论】:

  • 从您的帖子中,我了解到不能在二维数组上使用 memset。那正确吗?我很困惑,因为stackoverflow.com/questions/2516096/… 似乎暗示这是一种初始化二维数组的有效方法。
  • @Tryer。它适用于二维数组,但不适用于动态分配的数组。尝试使用 double cmatrix[10][10]
  • @Tryer 实际上那个问题的 OP 提到了一个二维数组,而不是一个指针数组(虽然没有显示代码),可能你的困惑来自那里
  • @Tryer 这不完全正确。事实上,在你提到的帖子中,我认为他们的二维数组是在堆栈上声明的(例如:double array[10][10],在这种情况下内存是连续的,memset 可以正常工作)。在您的情况下,您正在声明一个指针数组。所以存储指针的内存区域是连续的,但不是指向的数据。
【解决方案3】:

在这段代码中:

double ** cmatrix = new double*[10];
for (int i = 0; i < 10; i++)
    cmatrix[i] = new double[10];

您首先将一个包含 10 个指针 的数组分配给double (double*),然后,为该数组中的每个 元素(指针)分配新 10 个doubles 的数组。

图形化:

 array of 
 double*
   ||
   \/
+------+
|  x----------->   [0|1|... <10 doubles> ...|9]
+------+
|  x----------->   [0|1|... <10 doubles> ...|9]
+------+
| ...  |
+------+
|  x----------->   [0|1|... <10 doubles> ...|9]
+------+

您不能调用memset 来清零这个数据结构,因为您分配了分散 内存,而对memset 的单个调用需要连续 内存。

如果您线性化二维数组,您可以执行一个简单的memset 调用,即分配一个存储10*10 = 100 doubles 的内存块,只需调用一次@ 987654330@.

【讨论】:

  • 感谢图形描述。因此, [1][0] 不遵循 [0][9] 而像我一样动态分配。如果 cmatrix 被声明为 cmatrix[10][10],那就没问题了。对吗?
  • @Tryer:是的,使用double cmatrix[10][10] 你会得到一个连续的内存块。
猜你喜欢
  • 2023-03-27
  • 1970-01-01
  • 2020-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-04
  • 2013-10-04
相关资源
最近更新 更多