Thread: SegFault after I try to free my generic matrix structure

  1. #1
    Registered User
    Join Date
    May 2015
    Posts
    228

    SegFault after I try to free my generic matrix structure

    I've debugged my program and every time it reaches to free the memory blocks that I allocated, it crashes. I've made sure that I deallocated my memory the exact same way I allocated it but it still crashes(sometimes I'm lucky and it does not crash). I've made sure that I have correctly move each pointer to their correct during allocation but it still crashes.

    Here is my code.

    MatrixTest.c

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include "Matrix.h"
    
    
    int main()
    {
        matrix mat;
        int element;
        int i, j, errCheck; /*Change element to the appropriate data type you will be workng with.*/
        const int ROWS = 5;
        const int COL = 5;
    
    
        /*You can change sizeof() for any data type you want(integers, char arrays etc)*/
        errCheck = createMatrix(&mat, ROWS, COL, sizeof(int));
    
    
        /*If we were not able to successfully allocate memory*/
        if(errCheck == -1)
        {
            printf("Couldn't not allocate any more memory.");
            exit(EXIT_FAILURE);
        }
    
    
        for(i = 0; i < ROWS; i++)
        {
            for(j = 0; j < COL; j++)
            {
                /*
                   Note, when ever you decide to use scanf, make sure that first character you enter is a space else
                   a newline will be consumed in the process.
                 */
                errCheck = scanf(" %d", &element);
    
    
                /*Make sure that scanf did not fail. Scanf returns an integer based on the number of successful entries. */
                if(errCheck == 1)
                {
                  setElement(&mat, i, j, &element);
                }
            }
        }
    
    
        printf("\n");
    
    
        for(i = 0; i < ROWS; i++)
        {
            for(j = 0; j < COL; j++)
            {
                /*Returns void * so I must cast it to the appropriate type.*/
                element = *(int*)getElement(&mat, i, j);
    
    
                printf("%d ", element);
            }
            printf("\n");
        }
    
    
        freeMatrix(&mat);
    
    
        return 0;
    }
    Matrix.h

    Code:
    #ifndef MATRIX_H_INCLUDED
    #define MATRIX_H_INCLUDED
    
    
    typedef struct Matrix
    {
        void **data;
        size_t rows;
        size_t columns;
        size_t memSize;
    }matrix;
    
    
    int createMatrix(matrix *, const size_t, const size_t, const size_t);
    void *getElement(matrix *, const size_t, const size_t);
    void setElement(matrix *, const size_t, const size_t, const void *);
    void freeMatrix(matrix *);
    
    
    #endif /* MATRIX_H_INCLUDED */
    Matrix.c

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "Matrix.h"
    
    
    int createMatrix(matrix *mat, const size_t rows, const size_t columns, const size_t memSize)
    {
        void **data = malloc(sizeof(void *) * rows);
        data[0] = malloc(memSize * rows *  columns);
    
    
        if(data != NULL || data[0] != NULL)
        {
            size_t i;
    
    
            for (i = 1; i < rows; i++)
            {
               data[i] = (char *)data[0] + (i * columns * memSize);
            }
    
    
            mat->rows = rows;
            mat->columns = columns;
            mat->memSize = memSize;
            mat->data = data;
    
    
            return 1;
        }
        return -1;
    }
    
    
    void setElement(matrix *mat, const size_t x, const size_t y, const void *data)
    {
        /*
           Remember this formula. (i * numOfColumns) + j to traverse a 2D array in a 1D fashion(This formula only applies to Row Major Order Arrays).
        */
        size_t offset = ((x * mat->columns) + y) * mat->memSize;
        memcpy(mat->data + offset, data, mat->memSize);
    }
    
    
    void *getElement(matrix *mat, const size_t x, const size_t y)
    {
        size_t offset = ((x * mat->columns) + y) * mat->memSize;
        return mat->data + offset;
    }
    
    
    void freeMatrix(matrix *mat)
    {
        if(mat->data != NULL)
        {
            /*Set back every back to their default values to preserve invariants.*/
            free(mat->data[0]);
            free(mat->data);
            mat->data = NULL;
            mat->rows = 0;
            mat->columns = 0;
            mat->memSize = 0;
        }
    }

  2. #2
    Registered User
    Join Date
    May 2012
    Posts
    505
    Code:
     
    size_t offset = ((x * mat->columns) + y) * mat->memSize;
        memcpy(mat->data + offset, data, mat->memSize);


    This looks suspicious to me though I haven't actually checked the logic thoroughly.
    Firstly, the formula is usually y * columns + x. Secondly, C pointer arithmetic
    is already scaled by data item size.

    As a general rule, it's very common for programs to crash in free. Usually it means
    that memory has been corrupted somewhere. When the system attempts to free, the
    control block giving the position in the heap is damaged, and so you get a crash.

    A crash is lucky, a non crash is unlucky if a program has an error, by the way.
    An error message is correct results (as correct as can be given that the program
    is bad), and that is preferable to wrong results.

    I'm the author of MiniBasic: How to write a script interpreter and Basic Algorithms
    Visit my website for lots of associated C programming resources.
    https://github.com/MalcolmMcLean


  3. #3
    Registered User
    Join Date
    May 2015
    Posts
    228
    The formula is correct. Yours is almost correct; it's y * rows + x. That formula is only if you want your Matrix to be display in column major order not row major order which is what I'm doing(C is also by default row major order). I've have also noticed that the || should also be an && oops.
    Last edited by deathslice; 10-02-2016 at 10:35 PM.

  4. #4
    Registered User
    Join Date
    May 2015
    Posts
    228
    You have to remember that we are working with void pointers and so we must multiple the offset by the size of the data type which is not provide by the void type.

  5. #5
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Code:
    void setElement(matrix *mat, size_t x, size_t y, const void *data) {
        size_t offset = (y * mat->columns + x) * mat->memSize;
        memcpy((char*)mat->data[0] + offset, data, mat->memSize);
    }
     
    void *getElement(matrix *mat, size_t x, size_t y) {
        size_t offset = (y * mat->columns + x) * mat->memSize;
        return (char*)mat->data[0] + offset;
    }

  6. #6
    Registered User
    Join Date
    May 2015
    Posts
    228
    Algorism, Like I said it's y * rows + x if you are going to display the matrix in column major order and x * columns + y if you are going to display it in row major order(you can verify yourself with a 2 x 2 matrix). Anyway, would it not suffice to just mat->data[0] + offset instead of casting it? Why the cast? I'm assuming it is because I have a void ** and I need to bring it down to a void * so I can traverse it in a 1D fashion.

    Looks like you were right about casting it to a char * and accessing the 0th element and offsetting from there.
    Last edited by deathslice; 10-03-2016 at 05:28 AM.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Ask yourself why you're doing this
    > void **data = malloc(sizeof(void *) * rows);

    When you're also doing this
    > size_t offset = ((x * mat->columns) + y) * mat->memSize;

    If you're going to do the full subscripting yourself, then there is no need for the extra level of indirection which you never use.

    In fact, you weren't using the flat memory at all until algorism fixed it for you in post #5.

    You may as well simply declare this, if you're subscripting everything yourself.
    void *data = malloc(memSize * rows * columns);
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    May 2015
    Posts
    228
    True, I might as well do that since I can't do this a[1][1] with void **.
    Last edited by deathslice; 10-03-2016 at 06:10 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. license-free lock-free data structure library updated
    By Toby Douglass in forum Projects and Job Recruitment
    Replies: 0
    Last Post: 12-30-2015, 05:50 PM
  2. new license-free lock-free data structure library published
    By Toby Douglass in forum Projects and Job Recruitment
    Replies: 19
    Last Post: 12-22-2009, 02:33 AM
  3. segfault when allocating big matrix
    By lecter55 in forum C Programming
    Replies: 4
    Last Post: 06-16-2008, 12:54 AM
  4. Other programming questions: segfault in free
    By Neeharika in forum C Programming
    Replies: 2
    Last Post: 02-21-2006, 06:35 AM
  5. Segfault when trying to free a double linked list
    By Rpog in forum C Programming
    Replies: 1
    Last Post: 04-19-2005, 07:37 AM

Tags for this Thread