How do I correctly access elements of a dynamic array via pointer?

4

As many know (I believe) a multidimensional array is stored in memory in a linear fashion, ie each row of the array goes into memory one after the other. For example, I created the following image:

Soyoucanmanipulateamultidimensionalarrayasifitwereavectorusingapointer:

#include<stdio.h>#defineROWS4#defineCOLUMNS4intmain(void){intmatrix[ROWS][COLUMNS]={{17,10,14,78},{4,14,15,10},{14,45,56,70},{47,15,49,10}};int*ptr=matrix[0];for(unsignedinti=0;i<(ROWS*COLUMNS);i++){printf("[%d] ", ptr[i]);
    }

    printf("\n\n\n");

    ptr=NULL;

    return 0;
}

Knowing this, I tried to apply this same concept to a two-dimensional array that was dynamically allocated, but at the time of accessing the elements via the for command (as in the example above) I ended up receiving garbage on output, which were not in the womb. Here is the code for the "program":

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

#define ROWS 4
#define COLUMNS 4

int main(void){

    int **matrix=(int**)malloc(ROWS*sizeof(int*)); //Alocando as linhas da matriz

    for(unsigned int i=0; i<ROWS; i++){

        matrix[i]=(int*)malloc(COLUMNS*sizeof(int)); //Alocando as colunas
    }

    //Preenchendo a matriz
    for(unsigned int row=0; row<ROWS; row++){

        for(unsigned int column=0; column<COLUMNS; column++){

             matrix[row][column]=42; //42? Seria isso a resposta para "tudo"?
        }
    }

    int *ptr=matrix[0];

    //Exibindo valores
    for(unsigned int i=0; i<(ROWS*COLUMNS); i++){

        printf("[%d] ", ptr[i]);
    }

    printf("\n\n\n");

    for(unsigned int column=0; column<COLUMNS; column++){

        free(matrix[column]); //Desalocando as colunas da matriz
    }

    free(matrix); //Desalocando as linhas da matriz
    ptr=NULL;

    return 0;
}

When I run the code:

[42] [42] [42] [42] [-2074264339] [134268537] [42] [42] [42] [42] [-2074264339] [134268537] [42] [42] [42] [42]

Why does not the result displayed look like the first code? What's wrong?

    
asked by anonymous 08.06.2018 / 03:27

2 answers

2

There is nothing "wrong", only that in dynamic allocation, the data is stored differently (non-linear).

In your example, instead of a ROWS*COLUMNS size block, 4 pointers of type int are allocated, pointing to 4 integer vectors.

Here, you allocate the 4 pointers:

int **matrix = (int**)malloc(ROWS*sizeof(int*));

And here, you allocate the 4 vectors:

for(unsigned int i=0; i<ROWS; i++){
    matrix[i] = (int*)malloc(COLUMNS*sizeof(int));
}

The memory layout looks like this:

  ptr
   |
   V
+-------+     +---------+---------+---------+--------+
| *ROW0 |---->| COLUMN0 | COLUMN1 | COLUMN2 |COLUMN3 |
+-------+     +---------+---------+---------+--------+ 
| *ROW1 |---->| COLUMN0 | COLUMN1 | COLUMN2 |COLUMN3 |
+-------+     +---------+---------+---------+--------+ 
| *ROW2 |---->| COLUMN0 | COLUMN1 | COLUMN2 |COLUMN3 |
+-------+     +---------+---------+---------+--------+ 
| *ROW3 |---->| COLUMN0 | COLUMN1 | COLUMN2 |COLUMN3 |
+-------+     +---------+---------+---------+--------+ 

As ptr points to the first vector, the first 4 elements are 42, but soon after, what is printed is a memory address (2 positions of 32 bits) followed by the next 4 elements and another address and so on.

Therefore, it is not possible to traverse the matrix in the same way (linear).

In addition, there is no guarantee that the data will be allocated in the form of the example block above, since malloc can allocate the blocks in different positions of the heap as needed (ex: if the memory is fragmented).

Fragmentation Reference: Dynamic Memory Allocation and Fragmentation in C and C ++

    
08.06.2018 / 04:00
1

I made a few minor changes to your code, I do not know exactly whether it's right or not, but the result hit with what you wanted.

What I did was, in the ptr variable declaration, add another asterisk and turn it into a pointer pointer, such as its array variable, and assign it with the variable itself, not with the first line or with the first element. I also modified the for printing, using two variables i and j to select the desired array element.

The altered part thus became:

int **ptr = matrix;

//Exibindo valores
for(unsigned int i=0; i<(ROWS); i++){
    for (unsigned int j = 0; j < COLUMNS; j++){
        printf("[%d] ", ptr[i][j]);
    }
}

I'm learning too, so anything, I'm happy to be corrected or supplemented.

    
08.06.2018 / 04:00