0
votes

I have a perfectly working code with 2D array of a float variable, vxy, in C language. The size of row (rrow) is being calculated inside the code - column (ccol) size is already known. So I tried converting using code fragments in this forum and both causes segmentation fault. The two codes are i) Bryan's method from how to allocate memory dynamically for a two dimensional array and ii) Using pointer to a pointer method from http://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/. I chose these methods as the code is already functional with a 2D array so the rest of the code will survive this change.

static float vxy[5000][ccol] ;
vxy[r][c] = ... 

The original 2D declaration and usage is above:

#include <stdlib.h>

int main(void)
{
        int num_row = 3, num_col = 2, r;
        int ** A;

        A = malloc(num_row*(sizeof(*A)+num_col*sizeof(**A)));

        for (r = 0; r < num_row; r++)
        {
                A[r] = (int*)(A+num_row)+r*num_col;
        }

        /* Accessing element at row r and column c is through:
         *
         *      A[r][c].
         */

        free(A);

        return 0;
}

My implementation based on the above is:

int r;
float ** vxy;

    vxy = malloc(rrow*(sizeof(*vxy)+ ccol*sizeof(**vxy)));

    for (r = 0; r < rrow; r++)  {
        vxy[r] = (float*)(vxy + rrow) + r*ccol;
    }

The second method is:

        float **vxy = (float **)malloc(rrow * sizeof(float *));
        for (i=0; i<rrow; i++)
             vxy[i] = (float *)malloc(ccol * sizeof(float));

I updated the above 2nd method with the following - I got "Program received signal SIGSEGV, Segmentation fault" on the line of vxy[i] = malloc(ccol * sizeof(float));

    float **vxy = malloc(rrow * sizeof(float *));
    if (vxy = NULL) {
          printf ("Memory allocation error.\n");
//        return NULL;
    }

    for (i = 0; i < rrow; i++)
        vxy[i] = malloc(ccol * sizeof(float)); 

What seems to going wrong with my implementation? Update: I updated the full code from the source for the method one. I also want to know how to free the allocation and address failed malloc situations.

2
As a note: never cast the return from malloc. (it is just an invitation for hard to debug errors). float **vxy = malloc (rrow * sizeof *vxy); and vxy[i] = malloc (ccol * sizeof **vxy); are fine. Also, since you want to initialize all elements of your array, consider calloc (e.g. vxy[i] = calloc (ccol, sizeof **vxy);) - David C. Rankin
I tried it with your suggestion for the 2nd method above and posted code and error that I received - also posted the original 2D array - what am I missing? Will do the calloc once malloc is working. Currently I have manually set vxy to zero. - user4687194

2 Answers

2
votes

I'm sorry you are having difficulty with your 2D allocation, it really isn't too difficult. To dynamically allocate and access your elements with array[x][y] notation, you need to allocate x pointers to an array of float's (your rows), then allocate an y arrays of float's (your elements/columns) for each row. (no different than allocating an array of pointers to strings to hold lines of text)

An example of a simple allocation/initialization function with calloc (with m rows and n columns) shown without error checking on allocation is:

float **mtrx_calloc (size_t m, size_t n)
{
    register size_t i;
    float **array = calloc (m, sizeof *array);

    for (i = 0; i < m; i++)
    {
        array [i] = calloc (n, sizeof **array);
    }
    return array;
}

To allocate a 3x4 matrix, you would use it like this:

float **matrix = mtrx_calloc (3, 4);

You can then manipulate the matrix as you like accessing all elements with matrix[x][y] notation. Also note the use of size_t instead of int. Your rows and columns and iterator will never be negative, so choosing size_t or unsigned type makes more sense.

Sometimes rather than looking at pieces of code, it is good to have a working example. I put together a short working example to help you along that includes all points we have discussed so far in the comments and above. It includes error checking on memory allocation omitted above. If you have any questions, just drop a comment.

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

float **mtrx_calloc (size_t m, size_t n);             /* initialize elements to 0  */
void mtrx_prn (size_t m, size_t n, float **matrix);   /* print matrix with/pad     */
void mtrx_free (size_t m, float **matrix);            /* free memory allocated     */

int main (void)
{
    /* allocate the 3x4 matrix */
    float **matrix = mtrx_calloc (3, 4);

    /* fill with misc values */
    register size_t i = 0, j = 0;
    for (i = 0; i < 3; i++)
    {
        for (j = 0; j < 4; j++)
            matrix [i][j] = (float)(i + j);
    }

    /* print matrix */
    printf ("\nThe dynamically allocated 3x4 matrix is:\n\n");
    mtrx_prn (3, 4, matrix);

    /* free memory alocated */
    mtrx_free (3, matrix);

    /* just to make it look pretty */
    printf ("\n");

    return 0;
}

/* allocate/initialize mxn matrix */
float **mtrx_calloc (size_t m, size_t n)
{
    register size_t i;
    float **array = calloc (m, sizeof *array);

    if (!array) {   /* validate allocation  */
        fprintf (stderr, "%s() error: memory allocation failed.\n", __func__);
        exit (EXIT_FAILURE);
    }

    for (i = 0; i < m; i++)
    {
        array[i] = calloc (n, sizeof **array);

        if (!array[i]) {   /* validate allocation  */
            fprintf (stderr, "%s() error: memory allocation failed.\n", __func__);
            exit (EXIT_FAILURE);
        }
    }
    return array;
}

/* print a (m x n) matrix (check pad alloc) */
void mtrx_prn (size_t m, size_t n, float **matrix)
{
    register size_t i, j;

    for (i = 0; i < m; i++)
    {
        char *pad = "[ ";
        for (j = 0; j < n; j++)
        {
            printf ("%s%6.3f", pad, matrix [i][j]);
            pad = ", ";
        }
        printf ("%s", " ]\n");
    }
}

void mtrx_free (size_t m, float **matrix)
{
    register size_t i;

    for (i = 0; i < m; i++)
    {
        free (matrix [i]);
    }
    free (matrix);
}

Output

(note: the fill with misc values equation was changed to prevent overflow on entry of large m x n, so output values will differ from below)

$ ./bin/mtrx_dyn_example

The dynamically allocated 3x4 matrix is:

[  1.900,  2.800,  3.700,  4.600 ]
[  2.800,  3.700,  4.600,  5.500 ]
[  3.700,  4.600,  5.500,  6.400 ]

Leak Check with valgrind

When you are creating/allocating blocks of memory dynamically, you are responsible to tracking what you have allocated, preserving the starting address for the block of memory, and freeing the block of memory when you no longer need it. A great tool to help you check your memory use is a memory checker such as valgrind. (similar tools are available for all platforms). Simple to use, just valgrind ./progname. It will confirm for you whether any blocks remain unfreed and whether there are any access errors regarding your allocated blocks:

$ valgrind ./bin/mtrx_dyn_example
==15800== Memcheck, a memory error detector
==15800== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==15800== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==15800== Command: ./bin/mtrx_dyn_example
==15800==

The dynamically allocated 3x4 matrix is:

[  1.900,  2.800,  3.700,  4.600 ]
[  2.800,  3.700,  4.600,  5.500 ]
[  3.700,  4.600,  5.500,  6.400 ]

==15800==
==15800== HEAP SUMMARY:
==15800==     in use at exit: 0 bytes in 0 blocks
==15800==   total heap usage: 4 allocs, 4 frees, 72 bytes allocated
==15800==
==15800== All heap blocks were freed -- no leaks are possible
==15800==
==15800== For counts of detected and suppressed errors, rerun with: -v
==15800== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
0
votes

The problem is with the interplay between pointer to floats and actual floats, as mentioned in referenced answers, try to remove the type-casting and see what you get.

Both methods are valid (but accessed in different ways), there is also a first method which creates a 1-d array which represents a 2d array (thus accessed as a[i+j*r]), while the (first and) second methods actually allocates a 2-d array (accessed as a[i][j]).

try to use calloc as well if this helps, although malloc should be fine

Also try to fix your indices correctly (in the loops) when using either method to make sure you dont access memory out-of-bounds in the allocated array