0

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.

Community
  • 1
  • 1
  • 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 Apr 08 '15 at 08:32
  • 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 Apr 08 '15 at 17:48

2 Answers2

2

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)
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Is there a need to check for NULL after calloc or malloc? Is it better to pass the array through the function call than through a return statement? Thanks – user4687194 Apr 09 '15 at 02:10
  • Yes, you **always** check for `NULL` after every allocation to make sure the allocation succeeded. In the first example I noted it was **without** error checking, but if you look at the actual function in my program example you see: `if (!array)...` which is a check for `NULL`. As for pass through or return, you can do **both**. However, passing as an argument when allocating a **double** pointer, would require passing the array as a **triple** pointer in order to alter the address of the `array pointer` itself. It's up to you. – David C. Rankin Apr 09 '15 at 02:40
  • Glad I could help. I remember scratching my head and cussing over the exact same issue until someone helped me as well... Good luck with C, there is no better language to learn. It takes paying attention to every detail, but well worth it. – David C. Rankin Apr 09 '15 at 03:58
  • Wow, that is strange. I just copied/pasted directly from the answer above to make sure, then compiled with `gcc -Wall -Wextra -o mtrx_simple_dyn mtrx_simple_dyn.c` and got no errors at all. This is using `C89`. I also compiled without error using `-std=c99` and `-std=c11`, so I'm not sure why you are getting errors. You are using `gcc` correct? Are you **sure** you copied the entire code, function prototypes and all? (hmmm, now the comment disappeared -- strange..) – David C. Rankin Apr 09 '15 at 05:21
  • Actually it is fine now - I accidentally put mtrx_free(m, n); instead of mtrx_free(m, matrix); and I put the function declaration in a different file. Now all is fine. Awesome. Appreciate it. – user4687194 Apr 09 '15 at 05:25
  • I figured it had to be something like that, I've made use of the matrix code often and if it had some hidden defect (like not compiling) I'm pretty sure I would have stumbled upon it by now `:p` – David C. Rankin Apr 09 '15 at 05:35
  • Of course your test code runs fine as you demonstrated. However, when this method is incorporated in my original code, I do have a run time segmentation fault on the same line of code (where matrix[][] is computed), like the second method I originally posted. It compiles fine without errors/warning. I have no clue. – user4687194 Apr 09 '15 at 05:41
  • In my case, n=10. As soon as it enters 9, ie i<10, the segmentation fault occurs. – user4687194 Apr 09 '15 at 05:44
  • Can you post a link to your code/data, like on pasebin.com? I'll run a couple tests. – David C. Rankin Apr 09 '15 at 05:44
  • @user4687194 Ahhh!, You are not using my `fill with misc values` routine are you? The values go wild after about 7. That was a quick hack just to fill the `3x4` with something more interesting than the loop values. That's the problem with larger array sizes... not the matrix code itself. – David C. Rankin Apr 09 '15 at 05:54
  • @user4687194 grab the new line `matrix [i][j] = (float)(i + j);`, then fill it wil `100x100` if you like `:p` – David C. Rankin Apr 09 '15 at 06:02
  • Actually the algorithm does interpolation. So when m x n is what needed, I instead used float **matrix = mtrx_calloc (m+1, n+1). No more segmentation fault either. Thanks for helping me. – user4687194 Apr 09 '15 at 06:06
0

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

Nikos M.
  • 8,033
  • 4
  • 36
  • 43
  • 1
    It is important to use `calloc` instead of `malloc` when allocating numerical arrays, especially 2D arrays because when you iterate over the array, any time you attempt to read from an uninitialized element, you cause **Undefined Behavior**. That can be anything from (gee, I didn't even notice) to (Segmentation Fault). If you use `malloc`, simply manually zero all values at the beginning. (since `calloc` does that for you, it doesn't make a lot of sense not to use it...) – David C. Rankin Apr 08 '15 at 08:27
  • The first method says A[r][c] is how it is accessed - I take r is row and c is column - but you are saying ccessed as a[i+j*r]? – user4687194 Apr 08 '15 at 17:53
  • @user4687194, yeap sorry misread, was refereing to a similar method that uses a 1-d arfray as a 2-d array, updating answer – Nikos M. Apr 08 '15 at 18:05
  • The first method runs till the beginning of the last value the indices take - ie say c < 10 - it causes as soon as it hits c=9. Program received signal SIGSEGV, Segmentation fault on the line where vxy[r][c] = ... is computed. – user4687194 Apr 08 '15 at 19:33
  • @user4687194, this seems to indicate index-out-of-bounds issue (check my last paragraph). Maybe you used rows instead of columns or vice-varse, in case number of rows are different from number of columns – Nikos M. Apr 09 '15 at 12:29
  • Yes it was, but nothing wrong with the code. My algo does interpolation and it goes over the limit. – user4687194 Apr 10 '15 at 15:45