3

I am using Visual Studio Community 2017.

Following the discussion below:

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

I have a 2 D matrix (10 x 10) that I initialize using memset. This is option 1.

Option 2 is initializing the same matrix using two for loops, each looping from 0 through 9.

Then, when I write to a valid matrix location, an access violation writing error is thrown when Option 1 was used. Everything works fine when Option 2 is used.

The minimal working code I have that replicates this is given below:

#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;
}

Any help is appreciated.

BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
Tryer
  • 3,580
  • 1
  • 26
  • 49
  • 2
    `memset` requires that the memory to fill is one contiguous area, but you have 11 separate allocations. – Bo Persson Sep 21 '17 at 10:29
  • Don't use answers to C questions in C++. They are different languages; the use of `memset` for this is neither necessary nor a good idea. – Baum mit Augen Sep 21 '17 at 10:41
  • 1
    [Correctly allocating multi-dimensional arrays](https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays) – Lundin Sep 21 '17 at 10:44
  • 1
    Btw if you just wished to set everything to zero you should have used `calloc`. That being said, using `malloc`/`calloc` in C++ is _always_ incorrect practice, no exceptions. – Lundin Sep 21 '17 at 10:47

3 Answers3

3

With the memset you're overriding the pointers returned by your memory allocations, therefore when you access the memory later you're actually deferring a null pointer.

Your 2D array is actually an array of pointers, so memory is not contiguous and you cannot do a memset to set it to 0. Technically, it is just a pointer and dynamically you allocate space for another 10 pointers, each of them pointing to 10 doubles.

Instead, use a double loop (nested-fors) to initialize it, or just one memset for each row:

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));

Also, if your array will always be 10x10 you can declare it instead as double cmatrix[10][10]: that memory is contiguous and you can do your original memset.

cbuchart
  • 10,847
  • 9
  • 53
  • 93
  • Thanks. Yes, I was able to verify that it works with a 1 D array's memset. So, for a 2d array, I will use your suggestioin. – Tryer Sep 21 '17 at 10:33
  • "Your 2D array is actually an array of arrays, so memory is not contiguous" This is incorrect. It is actually an array of _pointers_. Had it been an array of arrays, memory _would_ have been contiguous. – Lundin Sep 21 '17 at 10:45
  • @Lundin thanks for the correction, I'll fix the answer to be more specific – cbuchart Sep 21 '17 at 10:49
  • 1
    If you have a contiguous array you can do `double cmatrix[10][10] = {};` and the compiler will clear it for you. No need for `memset`. – Bo Persson Sep 21 '17 at 11:20
2

cmatrix is a array of pointers. A call of memset to zero on it, will in fact be setting all pointers to 0 (which is not what you want), which leads to the access violation later. For this kind of initialization I would choose the option 2 (the one in comments)

M. Yousfi
  • 578
  • 5
  • 24
  • From your post, I understand that one cannot use memset on 2d arrays. Is that right? I am confused because https://stackoverflow.com/questions/2516096/fastest-way-to-zero-out-a-2d-array-in-c seems to suggest that as a valid way to initialize 2d arrays. – Tryer Sep 21 '17 at 10:35
  • 1
    @Tryer. It works for 2d arrays, but not for those which are dynamically allocated.Try the same with `double cmatrix[10][10]` – Gaurav Sehgal Sep 21 '17 at 10:37
  • 1
    @Tryer actually the OP of that question mentioned a 2D array, not an array of pointers (although didn't showed the code), probably your confusion came from there – cbuchart Sep 21 '17 at 10:37
  • 1
    @Tryer It's not exactly true. In fact in the post you mentionned I supposed their 2d array was declared on the stack (for ex : double array[10][10], in which case the memory is contiguous and the memset will work fine). In your case you are declaring a array of pointers. So memory zone on which the pointers are stored is contiguous but not the pointed data. – M. Yousfi Sep 21 '17 at 10:39
2

In this code:

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

you first allocate an array of 10 pointers to double (double*), and then, for each element (pointer) in this array, you allocate a new array of 10 doubles.

Graphically:

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

You can't call memset to zero out this data structure, as you allocated scattered memory, instead a single call to memset requires contiguous memory.

You can do a simple memset invocation if you linearize the 2D array, i.e. allocating a single chunk of memory storing 10*10 = 100 doubles, with a single call to new[].

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • Thanks for the graphical depiction. So, [1][0] does not follow [0][9] while dynamically allocated as I had. Had cmatrix been declared as cmatrix[10][10], it would have been fine. Is that right? – Tryer Sep 21 '17 at 10:50
  • 1
    @Tryer: Yes, with `double cmatrix[10][10]` you get a contiguous memory block. – Mr.C64 Sep 21 '17 at 10:52