0

i'm tryng to create a function which adds dynamically 1 row and 1 column to a square matrix everytime i need. I'm posting the code as an example, there i start with a "1x1 matrix" of integers and i try to add a row and a column 5 times to obtain a fianl 5x5 matrix, i don't understand why the OS stops immediately the execution. In the for cycle first i reallocate the "column" array of pointers adding a new one (so a new row) then for each block of it (so for each row) i reallocate others N blocks of memory. It seems that i try to access to a forbidden address of memory but i don't understand why, what's wrong? P.S: my ennglis could not be perfect so if you don't understand what i'm trying to say i will explaind better.

 #include <stdlib.h>
 #include <malloc.h>
 #include <stdbool.h>
 #include <stdio.h>


int **M,N;

int main(int argc, char** argv) {

 N = 1;
 M = (int**)malloc(sizeof(int*));
 M[0] = (int*)malloc(sizeof(int));

 for (int i = 0; i < 5; i++) {
     N++;
     M = (int**)realloc(M, N * sizeof(int*));
     for (int k=0; k<N; k++)
     M[k] = (int*)realloc(M[k], N * sizeof(int));
  }
}
Matteo Caruso
  • 37
  • 1
  • 7
  • There is no matrix (aka 2D array) in your code and nothing which can point to one. A pointer is not an array! If you need a matrix, use a 2D array. – too honest for this site Mar 12 '17 at 14:20
  • [casting malloc is bad](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – Ed Heal Mar 12 '17 at 14:20
  • @Olaf Just because a pointer is not an array doesn't mean it can't be used like one. A 2D array is clearly not going to work because the OP wants to be able to dynamically reallocate – Ben Wainwright Mar 12 '17 at 14:24
  • @EdHeal The OP has used a double pointer, which very clearly *can* be used like a 2D array/matrix – Ben Wainwright Mar 12 '17 at 14:26
  • @EdHeal That's not at all relevant to this question though since the OP specifies a square matrix and uses a single variable (N) to delimit the length of both sides – Ben Wainwright Mar 12 '17 at 14:31
  • @BenWainwright: Strictly speaking you **cannot** use a pointer like an array. But an array _decays_ for most opeartors to a pointer. This inlcudes the index-operator and the addition/subtraction operators. And a pointer to point cannot be used as a 2D array. Already the allocation is apparently very different. Just because the syntax for nested indexing is the same does not mean they have the same semantics. In fact, the semantics are very different. – too honest for this site Mar 12 '17 at 14:51
  • @Olaf that is a ridiculous statement. If you can use the index-operator with a pointer (you can) then it is reasonable to say that "it can be used like an array". You are arguing semantics now; to any reasonable person a pointer can be used like an array and therefore is a suitable option for this use case. A 2D array would *not* solve the OPs problem quite clearly – Ben Wainwright Mar 12 '17 at 14:53
  • @BenWainwright: Please read the standard! It clearly implies the index-operator is a **pointer** operator. See 6.3.2.1p3 and try understand the implications. One of them is that for the index-operator the array is converted to a pointer **before the operator is applied**! Wrt a two or higher dimension array, this is not only semantics, but has very practical implications as we see for allocation already (a single `malloc` vs. multiple, nested allocations). Wrt the code: it very well would, OP could copy the array on resizing; it is yet to be shown to be slower. – too honest for this site Mar 12 '17 at 14:58
  • @BenWainwright: Nevertheless, I did not say not to use a **jagged** array, but just that it is not a 2D array. Please don't put something in my words I did not state. – too honest for this site Mar 12 '17 at 14:59

2 Answers2

1

Before entering the loop, you have M pointing to a single int * and M[0] pointing to a single int.

On the first iteration of the loop, you use realloc to modify M to point to an array of 2 int *. The first one still points to a single int, but the second one is uninitialized. When you then try to call realloc on M[1], it reads an uninitialized pointer invoking undefined behavior. In this case it manifests in a crash.

You need to initialize the newly added element of M to NULL so that realloc will work properly.

M = realloc(M, N * sizeof(int*));
M[N-1] = NULL;
for (int k=0; k<N; k++) {
    M[k] = realloc(M[k], N * sizeof(int));
}

Also, don't cast the return value of malloc/realloc

Community
  • 1
  • 1
dbush
  • 205,898
  • 23
  • 218
  • 273
0

When you use realloc to expand an array, the new expanded elements in the array are not initialized. So when you realloc M, the additional pointers to memory are undefined, not NULL, so you cannot reference the expanded elements of M[] in the second realloc, until you initialize them to NULL.

 #include <stdlib.h>
 #include <malloc.h>
 #include <stdbool.h>
 #include <stdio.h>


int **M,N;

int main(int argc, char** argv) {

 N = 1;
 M = (int**)malloc(sizeof(int*));
 M[0] = (int*)malloc(sizeof(int));

 for (int i = 0; i < 5; i++) {
     N++;
     M = (int**)realloc(M, N * sizeof(int*));

      // Ensure the last M[] is NULL
     M[N-1] = NULL;

     for (int k=0; k<N; k++) 
         M[k] = (int*)realloc(M[k], N * sizeof(int));
  }
}
ScottK
  • 1,526
  • 1
  • 16
  • 23