0

I try to understand the malloc and dynamic allocation with c, but when I compile the program everything is ok, but if I run it the terminal tells me Segmentation fault (core dumped) and exits

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

int main(){
    int **matrice;
    int righe, colonne;
    int r, c;

    printf("Quante RIGHE deve avere la matrice? ");
    scanf("%d", &righe);

    printf("Quante COLONNE deve avere la matrice? ");
    scanf("%d", &colonne);

    matrice = (int**) malloc(righe*colonne*sizeof(int));

    for(r=0; r<righe; r++){
        matrice[r] = (int*) malloc(colonne*sizeof(int));

        for(r=0; r<righe; r++){
            for(c=0; c<colonne; c++){
                printf("Elemento[%d][%d]: ",r, c);
                scanf("%d", &matrice[r][c]);
            }

            // print out
            for(r=0; r<righe; r++){
                for(c=0; c<colonne; c++){
                    printf ("%d\n", matrice[r][c]);
                }
            }
        }
    }
}
Pankaspe
  • 91
  • 1
  • 7
  • You should not cast `malloc` - it is bad practice – Ed Heal Jan 09 '18 at 18:56
  • Why are you using a variable with the same name inside a loop that is using the same name – Ed Heal Jan 09 '18 at 18:57
  • 2
    `matrice = malloc (nrows * sizeof *matrice)` (that's `sizeof (int*)`). Then it's `matrice[r] = malloc (ncols * sizeof *matrice[r]);` (that's `sizeof (int)`). Note: you must validate each allocation succeeds, e.g. `if (!matrice[r]) { /* handle error */ }` – David C. Rankin Jan 09 '18 at 19:01
  • 1
    You are on the right track and finding root cause and solving the following is part of learning, understanding, and using dynamic memory allocation: "when I compile the program everything is ok, but if I run it the terminal tells me Segmentation fault (core dumped) and exits". – Vikas Yadav Jan 09 '18 at 19:08
  • 1
    You also need to have a clear understanding and mental picture of how your two dimensional matrix lays out in the memory, In your case, your two dim matrix consists of a block a memory containing an array of pointers, one pointer for one column. The number of such pointers is same as number of rows (and thus first malloc should be for the size=number of rows times size of (int *), This is the first thing you need to fix in your code as already pointed by @David C Rankin – Vikas Yadav Jan 09 '18 at 19:18
  • If you are not limited to C89, using variable length arrays would make your example a lot cleaner – ptb Jan 09 '18 at 23:26

4 Answers4

5

You have a number of steps out of order, and your ordering of you for loops to fill your matrice is incorrect. You also lack validation for all input and all allocation. To correct the problems you can do something like the following:

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

int main(){
    int **matrice;
    int righe, colonne;
    int r, c;

    printf("Quante RIGHE deve avere la matrice? ");
    if (scanf("%d", &righe) != 1) {
        fprintf (stderr, "error: invalid input - righe.\n");
        return 1;
    }

    printf("Quante COLONNE deve avere la matrice? ");
    if (scanf("%d", &colonne) != 1) {
        fprintf (stderr, "error: invalid input - colonne.\n");
        return 1;
    }

    matrice = malloc (righe * sizeof *matrice);
    if (!matrice) {
        perror ("matrice");
        return 1;
    }

    for (r = 0; r < righe; r++){
        matrice[r] = malloc (colonne * sizeof *matrice[r]);
        if (!matrice[r]) {
            perror ("matrice[r]");
            return 1;
        }

        for (c = 0; c < colonne; c++){
            printf ("Elemento[%d][%d]: ",r, c);
            if (scanf ("%d", &matrice[r][c]) != 1) {
                fprintf (stderr, "error: matrice[r][c].\n");
                return 1;
            }
        }
    }

    // print out
    for (r = 0; r < righe; r++){
        for (c = 0; c < colonne; c++)
            printf (" %3d", matrice[r][c]);
        putchar ('\n');
        free (matrice[r]);
    }
    free (matrice);
}

note don't forget to free the memory you allocate.

Example Use/Output

$ ./bin/arrmatrice
Quante RIGHE deve avere la matrice? 3
Quante COLONNE deve avere la matrice? 3
Elemento[0][0]: 1
Elemento[0][1]: 2
Elemento[0][2]: 3
Elemento[1][0]: 4
Elemento[1][1]: 5
Elemento[1][2]: 6
Elemento[2][0]: 7
Elemento[2][1]: 8
Elemento[2][2]: 9
   1   2   3
   4   5   6
   7   8   9

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
1

The exact issue in your post has been answered in the comments (and now in the accepted answer), but one other suggestion would be to consolidate the allocation of the 2D matrix into a function, such as:

int ** Create2D(int c, int r)
{   
    int **arr;
    int    y;

    arr   = calloc(c, sizeof(int *));
    for(y=0;y<c;y++)
    {
        arr[y] = calloc(r, sizeof(int));    
    }
    return arr;
}

This would require some architectural changes to the loops in your code (which, by the way are part of your problem), and simplify things overall.

After using the array this code produces, as always it should be freed. This can be done in similar fashion by creating a single function to do it:

void free2D(ssize_t **arr, ssize_t c)
{
    int i;
    if(!arr) return;
    for(i=0;i<c;i++)
    {
        free(arr[i]);
        arr[i] = NULL;
    }
    free(arr);
    arr = NULL;
}

Usage, for example would be similar to:

... 
int ** twoDArray = Create2D(colonne, righe);
if(twoDArray)
{ 
   // use array 
   //...
   free2D(twoDArray, colonne);
}
...
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • what's the point in doing `arr = NULL`? in the `free2D` function? – Pablo Jan 09 '18 at 19:17
  • 1
    Freeing alone does not set the variable to `NULL`, and It helps when using dynamic memory, in say an array of struct in large projects, where topology includes several places that may, or may not, need to use the struct array, to test its current condition for `NULL`, i.e. whether it has already be allocated, or needs to be. If NULL, allocate, else do not. – ryyker Jan 09 '18 at 19:20
  • but in this case, it's only setting the local variable `arr` to `NULL` at the end of the function, it has no meaning for the caller of `free2D`. If it were something like `*arr = NULL` (I know it doesn't fit to the signature) I could understand. – Pablo Jan 09 '18 at 19:22
  • @Pablo I consider it good practice for the reasons ryyker stated. For a program this short there's really no point in `free`ing either since the OS will reclaim the memory when the process exits. – yano Jan 09 '18 at 19:25
  • Yes, in the way the example code illustrates you are correct. Normally though, I would create a typedef struct object with global scope, then from that `typedef`, create a pointer with `extern` scope so it is visible in multiple modules. – ryyker Jan 09 '18 at 19:26
  • @ryyker I get the point, when there the pointers are part of something larger. I was only talking about the last line. It doesn't harm and it isn't wrong either. – Pablo Jan 09 '18 at 19:36
1

You missed a "*" and nested wrong the two last loops. I believe this is what you want:

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

int main()
{
    int **matrice;
    int righe, colonne;
    int r, c;

    printf("Quante RIGHE deve avere la matrice? ");
    scanf("%d", &righe);

    printf("Quante COLONNE deve avere la matrice? ");
    scanf("%d", &colonne);

    matrice = (int **) malloc(righe * sizeof(int *)); //<<< here

    for(r=0; r<righe; r++)
    {
        matrice[r] = (int *) malloc(colonne * sizeof(int));

        for(c = 0; c < colonne; ++c) //<<< here
        {
            printf("Elemento[%d][%d]: ", r, c);
            scanf("%d", &matrice[r][c]);
        }
    }

    for(r = 0; r < righe; ++r) //<<< here
        for(c = 0; c < colonne; ++c)
            printf ("%d\n", matrice[r][c]);
}
Jango
  • 378
  • 4
  • 8
  • When dynamically allocating memory to `righe` x `colonne` 2D array, do you think this is correct -> `matrice = (int **) malloc(righe * colonne * sizeof(int *));`? – H.S. Jan 09 '18 at 19:20
  • `malloc(righe * colonne * sizeof(int *));` is going to give you a dimension more `int*`s than you want. OP needs to pick either `righe` or `colonne` and `malloc` that many `int*`s, iterate over it and `malloc` the other number of `int`s for each iteration. Also, casting the result of `malloc` in `c` is [frowned upon](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – yano Jan 09 '18 at 19:22
  • You are right, guys! Since there is one allocation per row, the initial allocation should be based only on the number of rows. I fixed it in the answer. – Jango Jan 09 '18 at 19:26
1

The malloc calls are the problem, you are allocating the wrong number of bytes.

The matrix is created by having a pointer to an array that holds pointers to arrays of int.

int **matrix = calloc(rows, sizeof(*matrix));
if(matrix == NULL)
    // handle the error

Now you have to initialize the columns:

for(int i = 0; i < rows; ++i)
    matrix[i] = calloc(cols, sizeof *matrix[i]);
    if(matrix[i] == NULL)
        // handle the error

Now you can access every cell by matrix[i][j].

Freeing the matrix is also easy:

for(int i = 0; i < rows; ++i)
    free(matrix[i]);
free(matrix);

Note that I used calloc instead of malloc. The difference (other than using 2 parameters instead of one) is that calloc sets the allocated memory to 0. This is a huge help when you are doing error handling and want to free the memory. free(NULL) is not forbidden.

It's a good practice to create dedicated functions like create_matrix and free_matrix. There having everything set to 0 is really handy.

Last thing: I recommend not using sizeof(<data type>) when calling malloc and calloc. It's easy to miss the correct type, miss a * or make mistakes in general. sizeof *var however returns always the correct number of bytes.

Pablo
  • 13,271
  • 4
  • 39
  • 59