Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
537 views
in Technique[技术] by (71.8m points)

c - Segmentation Fault error in 3D array memory allocation

I have a pointer variable int ***a in C. I'm passing it to a function as &a i.e reference. In the function I'm getting a pointer variable of type int ****a. I'm allocating memory like this.

*a=(int***)malloc(no1*sizeof(int**));
some loop from 0 to no1
    (*a)[++l]=(int**)malloc((no1+1)*sizeof(int*));
some loop from 0 to no1
    (*a)[l][h]=(int*)malloc(2*sizeof(int));

This is only the time I allocated memory. The actual program is not given; no error here. But when I'm going to do this:

(*a)[l][h][0]=no1;

It's giving me a "Segmentation Fault" error and I can't understand why.

UPDATE: I have wrote a sample program which is to allocate the memory only. This is also giving "segmentation fault" error.

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

void allocate(int ****a)
{
    int i,j,k;
    if(((*a)=(int***)malloc(5*sizeof(int**)))==NULL)
    {
        printf("
Error in allocation of double pointer array
");
        exit(0);
    }
    for(i=0;i<5;i++)if(((*a)[i]=(int**)malloc(4*sizeof(int*)))==NULL)
    {
        printf("
Error in allocation of single pointer array on index [%d]
",i);
        exit(0);
    }
    for(i=0;i<5;i++)
        for(j=0;j<4;i++)
            if(((*a)[i][j]=(int*)malloc(3*sizeof(int)))==NULL)
            {
                printf("
Error in allocation of array on index [%d][%d]
",i,j);
                exit(0);
            }
    for(i=0;i<5;i++)
        for(j=0;j<4;i++)
            for(k=0;k<3;k++)
                (*a)[i][j][k]=k;
}

main()
{
    int ***a;
    int i,j,k;
    allocate(&a);
    for(i=0;i<5;i++)
        for(j=0;j<4;i++)
            for(k=0;k<3;k++)
                printf("
a[%d][%d][%d]  = %d ",i,j,k,a[i][j][k]);
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Revised code from question

Your code has:

for(i=0;i<5;i++)
    for(j=0;j<4;i++)

several times. The second loop should be incrementing j, not i. Be very careful with copy'n'paste.

This code does not crash (but does leak).

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

void allocate(int ****a);

void allocate(int ****a)
{
    int i,j,k;
    printf("allocate: 1B
");
    if(((*a)=(int***)malloc(5*sizeof(int**)))==NULL)
    {
        printf("
Error in allocation of double pointer array
");
        exit(0);
    }
    printf("allocate: 1A
");

    printf("allocate: 2B
");
    for(i=0;i<5;i++)
        if(((*a)[i]=(int**)malloc(4*sizeof(int*)))==NULL)
        {
            printf("
Error in allocation of single pointer array on index [%d]
",i);
            exit(0);
        }
    printf("allocate: 2A
");
    printf("allocate: 3B
");
    for(i=0;i<5;i++)
        for(j=0;j<4;j++)
            if(((*a)[i][j]=(int*)malloc(3*sizeof(int)))==NULL)
            {
                printf("
Error in allocation of array on index [%d][%d]
",i,j);
                exit(0);
            }
    printf("allocate: 3A
");

    printf("allocate: 4B
");
    for(i=0;i<5;i++)
        for(j=0;j<4;j++)
            for(k=0;k<3;k++)
                (*a)[i][j][k]=k;
    printf("allocate: 4A
");
}

int main(void)
{
    int ***a;
    int i,j,k;
    allocate(&a);
    for(i=0;i<5;i++)
        for(j=0;j<4;j++)
            for(k=0;k<3;k++)
                printf("a[%d][%d][%d]  = %d
",i,j,k,a[i][j][k]);
}

Previous answers

Since you've not shown us most of the code, it is hard to predict how you're mishandling it, but equally, since you are getting a core dump, you must be mishandling something.

Here is some working code — not checked with valgrind since that is not available for Mac OS X 10.8 — that seems to work. The error recovery for allocation failure is not complete, and the function to destroy the fully allocated array is also missing.

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

static int ***allocate_3d_array(int no1, int ****a)
{
    *a = (int***)malloc(no1 * sizeof(int**));
    if (*a == 0)
        return 0;

    for (int l = 0; l < no1; l++)
    {
        if (((*a)[l]=(int**)malloc((no1+1)*sizeof(int*))) == 0)
        {
            while (l > 0)
                free((*a)[--l]);
            return 0;
        }
    }

    for (int l = 0; l < no1; l++)
    {
        for (int h = 0; h < no1; h++)
        {
            if (((*a)[l][h]=(int*)malloc(2*sizeof(int))) == 0)
            {
                /* Leak! */
                return 0;
            }
        }
    }

    for (int l = 0; l < no1; l++)
        for (int h = 0; h < no1; h++)
            for (int k = 0; k < 2; k++)
                (*a)[l][h][k] = 10000 * l + 100 * h + k;

    return *a;
}

int main(void)
{
    int no1 = 5;
    int ***a = 0;
    int ***b = allocate_3d_array(no1, &a);
    const char *pad[] = { "  ", "
" };
    assert(b == a);

    if (a != 0)
    {
        for (int l = 0; l < no1; l++)
            for (int h = 0; h < no1; h++)
                for (int k = 0; k < 2; k++)
                    printf("a[%d][%d][%d] = %.6d%s", l, h, k, a[l][h][k], pad[k]);

        // free memory - added by harpun; reformatted by Jonathan Leffler
        // Would be a function normally — see version 2 code.
        for (int l = 0; l < no1; l++)
        {
            for (int h = 0; h < no1; h++)
                free(a[l][h]);
            free(a[l]);
        }
        free(a);
    }

    return 0;
}

Sample output:

a[0][0][0] = 000000  a[0][0][1] = 000001
a[0][1][0] = 000100  a[0][1][1] = 000101
a[0][2][0] = 000200  a[0][2][1] = 000201
a[0][3][0] = 000300  a[0][3][1] = 000301
a[0][4][0] = 000400  a[0][4][1] = 000401
a[1][0][0] = 010000  a[1][0][1] = 010001
a[1][1][0] = 010100  a[1][1][1] = 010101
a[1][2][0] = 010200  a[1][2][1] = 010201
a[1][3][0] = 010300  a[1][3][1] = 010301
a[1][4][0] = 010400  a[1][4][1] = 010401
a[2][0][0] = 020000  a[2][0][1] = 020001
a[2][1][0] = 020100  a[2][1][1] = 020101
a[2][2][0] = 020200  a[2][2][1] = 020201
a[2][3][0] = 020300  a[2][3][1] = 020301
a[2][4][0] = 020400  a[2][4][1] = 020401
a[3][0][0] = 030000  a[3][0][1] = 030001
a[3][1][0] = 030100  a[3][1][1] = 030101
a[3][2][0] = 030200  a[3][2][1] = 030201
a[3][3][0] = 030300  a[3][3][1] = 030301
a[3][4][0] = 030400  a[3][4][1] = 030401
a[4][0][0] = 040000  a[4][0][1] = 040001
a[4][1][0] = 040100  a[4][1][1] = 040101
a[4][2][0] = 040200  a[4][2][1] = 040201
a[4][3][0] = 040300  a[4][3][1] = 040301
a[4][4][0] = 040400  a[4][4][1] = 040401

Compare this with what you've got. You could add many more diagnostic print messages. If this doesn't help sufficiently, create an SSCCE (Short, Self-Contained, Correct Example) analogous to this that demonstrates the problem in your code without any extraneous material.

Version 2 of the code

This is a somewhat more complex version of the code that simulates memory allocation failures after N allocations (and a test harness that runs it with every value of N from 0 up to 35, where there are actually only 30 allocations for the array. It also includes code to release the array (similar to, but different from, the code that was edited into my answer by harpun. The interaction at the end with the line containing the PID means that I can check memory usage with ps in another terminal window. (Otherwise, I don't like programs that do that sort of thing —?I suppose I should run the ps from my program via system(), but I'm feeling lazy.)

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

static int fail_after = 0;
static int num_allocs = 0;

static void *xmalloc(size_t size)
{
    if (fail_after > 0 && num_allocs++ >= fail_after)
    {
        fputs("Out of memory
", stdout);
        return 0;
    }
    return malloc(size);
}

static int ***allocate_3d_array(int no1, int ****a)
{
    *a = (int***)xmalloc(no1 * sizeof(int**));
    if (*a == 0)
        return 0;

    for (int l = 0; l < no1; l++)
    {
        if (((*a)[l]=(int**)xmalloc((no1+1)*sizeof(int*))) == 0)
        {
            for (int l1 = 0; l1 < l; l1++)
                free((*a)[l1]);
            free(*a);
            *a = 0;
            return 0;
        }
    }

    for (int l = 0; l < no1; l++)
    {
        for (int h = 0; h < no1; h++)
        {
            if (((*a)[l][h]=(int*)xmalloc(2*sizeof(int))) == 0)
            {
                /* Release prior items in current row */
                for (int h1 = 0; h1 < h; h1++)
                    free((*a)[l][h1]);
                free((*a)[l]);
                /* Release items in prior rows */
                for (int l1 = 0; l1 < l; l1++)
                {
                    for (int h1 = 0; h1 < no1; h1++)
                        free((*a)[l1][h1]);
                    free((*a)[l1]);
                }
                free(*a);
                *a = 0;
                return 0;
            }
        }
    }

    for (int l = 0; l < no1; l++)
        for (int h = 0; h < no1; h++)
            for (int k = 0; k < 2; k++)
                (*a)[l][h][k] = 10000 * l + 100 * h + k;

    return *a;
}

static void destroy_3d_array(int no1, int ***a)
{
    if (a != 0)
    {
        for (int l = 0; l < no1; l++)
        {
            for (int h = 0; h < no1; h++)
                free(a[l][h]);
            free(a[l]);
        }
        free(a);
    }
}

static void test_allocation(int no1)
{
    int ***a = 0;
    int ***b = allocate_3d_array(no1, &a);
    const char *pad[] = { "  ", "
" };
    assert(b == a);

    if (a != 0)
    {
        for (int l = 0; l < no1; l++)
        {
            for (int h = 0; h < no1; h++)
            {
                for (int k = 0; k < 2; k++)
                {
                    if (a[l][h][k] != l * 10000 + h * 100 + k)
                        printf("a[%d][%d][%d] = %.6d%s", l, h, k, a[l][h][k], pad[k]);
                }
            }
        }
    }

    destroy_3d_array(no1, a);
}

int main(void)
{
    int no1 = 5;

    for (fail_after = 0; fail_after < 33; fail_after++)
    {
        printf("Fail after: %d
", fail_after);
        num_allocs = 0;
        test_allocation(no1);
    }

    printf("PID %d - waiting for some data to exit:", (int)getpid());
    fflush(0);
    getchar();

    return 0;
}

Note how painful the memory recovery is. As before, not tested with valgrind, but I take reassurance from harpun's test on the previous version.

Version 3 — Clean bill of health from valgrind

This code is very similar to the test in version 2. It fixes a memory leak in the clean-up when a memory allocation fails in the leaf level allocations. The program no longer prompts for inputs (much preferable); it takes an optional single argument that is the number of allocations to fail after. Testing with valgrind showed that with an argument 0-6, there were no leaks, but with argument 7 there was a leak. It didn't take long to spot the problem and fix it. (It's easier when the machine running valgrind is available — it was powered down over the long weekend for general site electrical supply upgrade.)

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

static int fail_after = 0;
static int num_allocs = 0;

static void *xmalloc(size_t size)
{
    if (fail_after > 0 && num_allocs++ >= fail_after)
    {
        fputs("Out of memory
", stdout);
        return 0;
    }
    return malloc(size);
}

static int ***allocate_3d_array(int no1, int ****a)
{
    *a = (int***)xmalloc(no1 * sizeof(int**));
    if (*a == 0)
        return 0;

    for (int l = 0; l < no1; l++)
    {
        if (((*a)[l]=(int**)xmalloc((no1+1)*sizeof(int*))) == 0)
        {
            for (int l1 = 0; l1 < l; l1++)
                free((*a)[l1]);
            free(*a);
            *a = 0;
            return 0;
        }
    }

    for (int l = 0; l < no1; l++)
    {
        for (int h = 0; h < no1; h++)
        {
            if (((*a)[l][h]=(int*)xmalloc(2*sizeof(int))) == 0)
            {
                /* Release prior items in current (partial) row */
                for (int h1 = 0; h1 < h; h1++)
                    free((*a)[l][h1]);
                /* Release items in prior (complete) rows */
                for (int l1 = 0; l1 < l; l1++)
                {
                    for (int h1 = 0; h1 < no1; h1++)
                        free((*a)[l1][h1]);
                }
                /* Release entries in first (complete) level of array */
                for (int l1 = 0; l1 < no1; l1++)
                    free((*a)[l1]);
                free(*a);
                *a = 0;
                return 0;
            }
        }
    }

    for (int l = 0; l < no1; l++)
        for (int h = 0; h < no1; h++)
            for (int k = 0; k < 2; k++)
                (*a)[l][h][k] = 1000

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...