在3D阵列内存分配分段错误 [英] Segmentation Fault error in 3D array memory allocation

查看:136
本文介绍了在3D阵列内存分配分段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个指针变量 INT *** A 在C.我将它传递给函数,如&放大器;一个即参考。在功能我得到类型的指针变量 INT **** A
我分配内存是这样的。

  * A =(INT ***)的malloc(NO1 * sizeof的(INT **));
从0一些循环NO1
    (* a)个[++ 1] =(INT **)的malloc((NO1 + 1)* sizeof的为(int *));
从0一些循环NO1
    (* a)个[L] [H] =(INT *)malloc的(2 * sizeof的(INT));

这是我唯一的分配内存的时间。实际程序未给出;这里没有错误。
但是,当我要做到这一点:

 (*一)[L] [H] [0] = NO1;

它给了我一个段错误的错误,我不明白为什么。

更新:
我已经写了一个示例程序,这是只分配内存。这也让分段错误的错误。

 #包括LT&;&stdio.h中GT;
#包括LT&;&malloc.h所GT;
#包括LT&;&stdlib.h中GT;无效分配(INT ****一)
{
    INT I,J,K;
    如果(((* A)=(INT ***)的malloc(5 * sizeof的(INT **)))== NULL)
    {
        的printf(\\ n错误双指针数组的\\ n分配);
        出口(0);
    }
    对于(I = 0; I&小于5;我++)如果(((* a)个由[i] =(INT **)的malloc(4 * sizeof的为(int *)))== NULL)
    {
        的printf(\\ n错误单指针数组分配索引内容[%d] \\ n,I);
        出口(0);
    }
    对于(I = 0; I&小于5;我+ +)
        为(J = 0; J&下; 4;我+ +)
            如果(((*一)[I] [J] =(INT *)malloc的(3 * sizeof的(INT)))== NULL)
            {
                的printf(\\ n错误数组分配索引[%D]。[%D]。\\ n,I,J);
                出口(0);
            }
    对于(I = 0; I&小于5;我+ +)
        为(J = 0; J&下; 4;我+ +)
            为(K = 0; k 3;; k ++)
                (*一)[I] [J] [K] = K;
}主要()
{
    INT ***一;
    INT I,J,K;
    分配(安培; A);
    对于(I = 0; I&小于5;我+ +)
        为(J = 0; J&下; 4;我+ +)
            为(K = 0; k 3;; k ++)
                的printf(\\呐[%D]。[%D]。[%D]。=%d个,I,J,K,A [i] [j]的[K]);
}


解决方案

修订$ C $从问题ç

您code的:

 为(i = 0;我小于5;我++)
    为(J = 0; J&下; 4;我+ +)

数次。第二个循环应该是递增Ĵ,而不是我。要非常小心copy'n'paste。

这code不会崩溃(但不会泄漏)。

 的#include<&stdio.h中GT;
#包括LT&;&stdlib.h中GT;无效分配(INT ****一);无效分配(INT ****一)
{
    INT I,J,K;
    的printf(分配:1B \\ n);
    如果(((* A)=(INT ***)的malloc(5 * sizeof的(INT **)))== NULL)
    {
        的printf(\\ n错误双指针数组的\\ n分配);
        出口(0);
    }
    的printf(分配:1A \\ n);    的printf(分配:2B \\ n);
    对于(I = 0; I&小于5;我+ +)
        如果(((*一)[I] =(INT **)的malloc(4 * sizeof的为(int *)))== NULL)
        {
            的printf(\\ n错误单指针数组分配索引内容[%d] \\ n,I);
            出口(0);
        }
    的printf(分配:2A \\ n);
    的printf(分配:3B \\ n);
    对于(I = 0; I&小于5;我+ +)
        为(J = 0; J&下; 4; J ++)
            如果(((*一)[I] [J] =(INT *)malloc的(3 * sizeof的(INT)))== NULL)
            {
                的printf(\\ n错误数组分配索引[%D]。[%D]。\\ n,I,J);
                出口(0);
            }
    的printf(分配:3A \\ n);    的printf(分配:4B \\ n);
    对于(I = 0; I&小于5;我+ +)
        为(J = 0; J&下; 4; J ++)
            为(K = 0; k 3;; k ++)
                (*一)[I] [J] [K] = K;
    的printf(分配:4A \\ n);
}INT主要(无效)
{
    INT ***一;
    INT I,J,K;
    分配(安培; A);
    对于(I = 0; I&小于5;我+ +)
        为(J = 0; J&下; 4; J ++)
            为(K = 0; k 3;; k ++)
                的printf(一[%D]。[%D]。[%D]。=%d个\\ N,I,J,K,A [i] [j]的[K]);
}

previous答案

既然你没有告诉我们大部分的code,它是很难predict你是如何处理不当,但同样的,因为你得到一个核心转储,你必须处理不当的东西。

下面是一些工作code - 不与的valgrind 检查,因为这是不适用于Mac OS X 10.8 - 这似乎工作。用于分配失败的错误还没有完全恢复,而函数来销毁完全分配的数组也不翼而飞。

 的#include<&ASSERT.H GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;静态INT *** allocate_3d_array(INT NO1,诠释一个****)
{
    * A =(INT ***)的malloc(NO1 * sizeof的(INT **));
    如果(*一== 0)
        返回0;    对于(int类型l = 0; L< NO1,L ++)
    {
        如果(((* a)个[1] =(INT **)的malloc((NO1 + 1)* sizeof的为(int *)))== 0)
        {
            而(L&0)
                免费((*一)[ - L]);
            返回0;
        }
    }    对于(int类型l = 0; L< NO1,L ++)
    {
        对于(INT H = 0; H< NO1; H ++)
        {
            如果(((* a)个[L] [H] =(INT *)malloc的(2 * sizeof的(INT)))== 0)
            {
                /* 泄漏! * /
                返回0;
            }
        }
    }    对于(int类型l = 0; L< NO1,L ++)
        对于(INT H = 0; H< NO1; H ++)
            为(中间体K = 0; K&2; k ++)
                (*一)[L] [H] [K] = 10000 * L + 100 * H + K;    返回*一个;
}INT主要(无效)
{
    INT NO1 = 5;
    INT ***一个= 0;
    INT *** B = allocate_3d_array(NO1,&放大器;一个);
    为const char *垫[] = {,\\ n};
    断言(二==一);    如果(一个!= 0)
    {
        对于(int类型l = 0; L< NO1,L ++)
            对于(INT H = 0; H< NO1; H ++)
                为(中间体K = 0; K&2; k ++)
                    输出(一个[%d个] [%d个] [%d个] =%.6d%的,L,H,K,A [L] [H] [k]的,垫[K]);        //释放内存 - 由harpun增加;由乔纳森莱弗勒格式化
        //将是一个功能正常 - 见第2版code。
        对于(int类型l = 0; L< NO1,L ++)
        {
            对于(INT H = 0; H< NO1; H ++)
                免费(一[L] [H]);
            免费(一[L]);
        }
        自由(一);
    }    返回0;
}

示例输出:

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

与你有什么比较一下。你可以添加更多的诊断打印消息。如果没有充分的帮助,创建一个SSCCE(短的,独立的,正确的示例)类似于此演示在code中的问题,没有任何多余的材料。

的code第2版

这是code是n分配后模拟内存分配失败的一个较为复杂的版本(这与从0到35,其中居然还有只有30分配N个每个值运行它测试工具为阵,还包括code释放数组(类似,但不同的是,code,是由的 harpun 。在与包含PID行末的互动意味着我可以在另一个终端窗口中检查与 PS 。(否则,我不喜欢做那种事情的程序 - 我想我应该运行 PS 从我的程序通过系统(),但我感觉懒洋洋的。)

 的#include<&ASSERT.H GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&unistd.h中GT;静态INT fail_after = 0;
静态INT num_allocs = 0;静态无效*的xmalloc(为size_t大小)
{
    如果(fail_after大于0&放大器;&放大器; num_allocs ++盐= fail_after)
    {
        的fputs(内存不足的\\ n,标准输出);
        返回0;
    }
    返回的malloc(大小);
}静态INT *** allocate_3d_array(INT NO1,诠释一个****)
{
    * A =(INT ***)的xmalloc(NO1 * sizeof的(INT **));
    如果(*一== 0)
        返回0;    对于(int类型l = 0; L< NO1,L ++)
    {
        如果(((* a)个[1] =(INT **)的xmalloc((NO1 + 1)* sizeof的为(int *)))== 0)
        {
            为(中间体L1 = 0; L1&所述; l;和L1 +)
                免费((*一)[L1]);
            免费(*一);
            *一个= 0;
            返回0;
        }
    }    对于(int类型l = 0; L< NO1,L ++)
    {
        对于(INT H = 0; H< NO1; H ++)
        {
            如果(((* a)个[L] [H] =(INT *)的xmalloc(2 * sizeof的(INT)))== 0)
            {
                / *当前行中发布之前的项目* /
                为(中间体H1 = 0; H1&下; H; H1 +)
                    免费((*一)[L] [H1]);
                免费((*一)[L]);
                / *在前面的行发行项目* /
                为(中间体L1 = 0; L1&所述; l;和L1 +)
                {
                    为(中间体H1 = 0; H1&下; NO1; H1 +)
                        免费((*一)[L1] [H1]);
                    免费((*一)[L1]);
                }
                免费(*一);
                *一个= 0;
                返回0;
            }
        }
    }    对于(int类型l = 0; L< NO1,L ++)
        对于(INT H = 0; H< NO1; H ++)
            为(中间体K = 0; K&2; k ++)
                (*一)[L] [H] [K] = 10000 * L + 100 * H + K;    返回*一个;
}静态无效destroy_3d_array(INT NO1,诠释一个***)
{
    如果(一个!= 0)
    {
        对于(int类型l = 0; L< NO1,L ++)
        {
            对于(INT H = 0; H< NO1; H ++)
                免费(一[L] [H]);
            免费(一[L]);
        }
        自由(一);
    }
}静态无效test_allocation(INT NO1)
{
    INT ***一个= 0;
    INT *** B = allocate_3d_array(NO1,&放大器;一个);
    为const char *垫[] = {,\\ n};
    断言(二==一);    如果(一个!= 0)
    {
        对于(int类型l = 0; L< NO1,L ++)
        {
            对于(INT H = 0; H< NO1; H ++)
            {
                为(中间体K = 0; K&2; k ++)
                {
                    如果(一个[L] [H] [k]的!= L * 10000 + H * 100 + K)
                        输出(一个[%d个] [%d个] [%d个] =%.6d%的,L,H,K,A [L] [H] [k]的,垫[K]);
                }
            }
        }
    }    destroy_3d_array(NO1,一);
}INT主要(无效)
{
    INT NO1 = 5;    为(fail_after = 0; fail_afterγ-33; fail_after ++)
    {
        的printf(失败之后数:%d \\ n,fail_after);
        num_allocs = 0;
        test_allocation(NO1);
    }    输出(PID%d个 - 等待某些数据退出,(int)的GETPID());
    fflush(0);
    的getchar();    返回0;
}

请注意内存的恢复是多么痛苦的。和以前一样,不与的valgrind 测试过,但我需要安心从 harpun 的在previous版本测试。

3版 - 从健康证明书 的valgrind

这code非常相似,在第2版的测试时,内存分配的叶级分配失败,它修复了清理内存泄漏。该程序不再提示您输入(多preferable);它需要一个可选的一个参数就是失败后分配数。与的valgrind 测试表明,与参数0-6,没有泄漏,但论据7出现了泄漏。它没有多久就发现问题并解决它。 (它更容易在机器运行时,的valgrind 可用 - 这是在长周末一般现场供电升级断电)

 的#include<&ASSERT.H GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;静态INT fail_after = 0;
静态INT num_allocs = 0;静态无效*的xmalloc(为size_t大小)
{
    如果(fail_after大于0&放大器;&放大器; num_allocs ++盐= fail_after)
    {
        的fputs(内存不足的\\ n,标准输出);
        返回0;
    }
    返回的malloc(大小);
}静态INT *** allocate_3d_array(INT NO1,诠释一个****)
{
    * A =(INT ***)的xmalloc(NO1 * sizeof的(INT **));
    如果(*一== 0)
        返回0;    对于(int类型l = 0; L< NO1,L ++)
    {
        如果(((* a)个[1] =(INT **)的xmalloc((NO1 + 1)* sizeof的为(int *)))== 0)
        {
            为(中间体L1 = 0; L1&所述; l;和L1 +)
                免费((*一)[L1]);
            免费(*一);
            *一个= 0;
            返回0;
        }
    }    对于(int类型l = 0; L< NO1,L ++)
    {
        对于(INT H = 0; H< NO1; H ++)
        {
            如果(((* a)个[L] [H] =(INT *)的xmalloc(2 * sizeof的(INT)))== 0)
            {
                / *当前(部分)行发行之前的项目* /
                为(中间体H1 = 0; H1&下; H; H1 +)
                    免费((*一)[L] [H1]);
                / *在之前(完成)行发布项目* /
                为(中间体L1 = 0; L1&所述; l;和L1 +)
                {
                    为(中间体H1 = 0; H1&下; NO1; H1 +)
                        免费((*一)[L1] [H1]);
                }
                / *数组的第一个(完整)级版本项* /
                为(中间体L1 = 0; L1&下; NO1; L1 +)
                    免费((*一)[L1]);
                免费(*一);
                *一个= 0;
                返回0;
            }
        }
    }    对于(int类型l = 0; L< NO1,L ++)
        对于(INT H = 0; H< NO1; H ++)
            为(中间体K = 0; K&2; k ++)
                (*一)[L] [H] [K] = 10000 * L + 100 * H + K;    返回*一个;
}静态无效destroy_3d_array(INT NO1,诠释一个***)
{
    如果(一个!= 0)
    {
        对于(int类型l = 0; L< NO1,L ++)
        {
            对于(INT H = 0; H< NO1; H ++)
                免费(一[L] [H]);
            免费(一[L]);
        }
        自由(一);
    }
}静态无效test_allocation(INT NO1)
{
    INT ***一个= 0;
    INT *** B = allocate_3d_array(NO1,&放大器;一个);
    为const char *垫[] = {,\\ n};
    断言(二==一);    如果(一个!= 0)
    {
        对于(int类型l = 0; L< NO1,L ++)
        {
            对于(INT H = 0; H< NO1; H ++)
            {
                为(中间体K = 0; K&2; k ++)
                {
                    如果(一个[L] [H] [k]的!= L * 10000 + H * 100 + K)
                        输出(一个[%d个] [%d个] [%d个] =%.6d%的,L,H,K,A [L] [H] [k]的,垫[K]);
                }
            }
        }
    }    destroy_3d_array(NO1,一);
}INT主(INT ARGC,字符** argv的)
{
    INT NO1 = 5;
    INT fail_limit = 33;    如果(的argc == 2)
        fail_limit =的atoi(ARGV [1]);    为(fail_after = 0; fail_after&下; fail_limit; fail_after ++)
    {
        的printf(失败之后数:%d \\ n,fail_after);
        num_allocs = 0;
        test_allocation(NO1);
    }    返回0;
}

第4版 - 更少的内存分配

更新2014年12月20日

上面的code使得很多内存分配,这复杂的释放和错误恢复。这里是一个替代版本,使得仅有3分配,一个用于指针的指针向量,一个用于指针数组,以及一个整数数组。然后设置指针指向内存中正确的位置。

 的#include<&ASSERT.H GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;静态INT fail_after = 0;
静态INT num_allocs = 0;静态无效*的xmalloc(为size_t大小)
{
    如果(fail_after大于0&放大器;&放大器; num_allocs ++盐= fail_after)
    {
        的fputs(内存不足的\\ n,标准输出);
        返回0;
    }
    返回的malloc(大小);
}静态INT *** allocate_3d_array(INT NO1,诠释一个****)
{
    INT *** D0 =(INT ***)的xmalloc(NO1 * sizeof的(INT **));
    INT ** D1 =(INT **)的xmalloc(NO1 * NO1 * sizeof的为(int *));
    为int * D2 =(INT *)的xmalloc(NO1 * NO1 * 2 * sizeof的(INT));    如果(D0 == 0 || D1 == 0 || D2 == 0)
    {
        免费(D0);
        自由(D1);
        免费(D2);
        *一个= 0;
        返回0;
    }    对于(int类型l = 0; L< NO1,L ++)
    {
        D0 [1] =&放大器; D1 [L * NO1]。
        对于(INT H = 0; H< NO1; H ++)
        {
            D0 [L] [H] =安培; D2 [(1- * NO1 + H)* 2];
            为(中间体K = 0; K&2; k ++)
                D0 [L] [H] [K] = L * 10000 + H * 100 + K;
        }
    }    * A = D0;
    返回*一个;
}静态无效destroy_3d_array(INT ***一)
{
    如果(一个!= 0)
    {
        自由(一个[0] [0]);
        自由(一个[0]);
        自由(一);
    }
}静态无效test_allocation(INT NO1)
{
    INT ***一个= 0;
    INT *** B = allocate_3d_array(NO1,&放大器;一个);
    为const char *垫[] = {,\\ n};
    断言(二==一);    如果(一个!= 0)
    {
        对于(int类型l = 0; L< NO1,L ++)
        {
            对于(INT H = 0; H< NO1; H ++)
            {
                为(中间体K = 0; K&2; k ++)
                {
                    如果(一个[L] [H] [k]的!= L * 10000 + H * 100 + K)
                        输出(糟糕:一个[%d个] [%d个] [%d个] =%.6d%的,L,H,K,A [L] [H] [k]的,垫[K]);
                }
            }
        }
    }    destroy_3d_array(一);
}INT主(INT ARGC,字符** argv的)
{
    INT NO1 = 5;
    INT fail_limit = 4;    如果(的argc == 2)
        fail_limit =的atoi(ARGV [1]);    为(fail_after = 0; fail_after&下; fail_limit; fail_after ++)
    {
        的printf(失败之后数:%d \\ n,fail_after);
        num_allocs = 0;
        test_allocation(NO1);
    }    返回0;
}

这有一个健康清洁法案使用GCC 4.9.1在Mac OS X 10.10.1,与 的valgrind 版本的valgrind-3.11.0.SVN(从SVN树内置了针对Mac OS X的一些必要的修复,但没有足够的SUP pressions)。

诊断打印(使用哎呀开始)被触发,而我公司开发的答案;我有我的指针算盘打错了的时候。

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("\nError in allocation of double pointer array\n");
        exit(0);
    }
    for(i=0;i<5;i++)if(((*a)[i]=(int**)malloc(4*sizeof(int*)))==NULL)
    {
        printf("\nError in allocation of single pointer array on index [%d]\n",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("\nError in allocation of array on index [%d][%d]\n",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("\na[%d][%d][%d]  = %d ",i,j,k,a[i][j][k]);
}

解决方案

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\n");
    if(((*a)=(int***)malloc(5*sizeof(int**)))==NULL)
    {
        printf("\nError in allocation of double pointer array\n");
        exit(0);
    }
    printf("allocate: 1A\n");

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

    printf("allocate: 4B\n");
    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\n");
}

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\n",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[] = { "  ", "\n" };
    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\n", 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[] = { "  ", "\n" };
    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\n", 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\n", 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] = 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[] = { "  ", "\n" };
    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(int argc, char **argv)
{
    int no1 = 5;
    int fail_limit = 33;

    if (argc == 2)
        fail_limit = atoi(argv[1]);

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

    return 0;
}

Version 4 — Fewer memory allocations

Update 2014-12-20

The code above makes a lot of memory allocations, which complicates the release and error recovery. Here is an alternative version that makes just 3 allocations, one for the vector of pointers to pointers, one for the array of pointers, and one for the array of integers. It then sets the pointers to point to the correct places in memory.

#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\n", stdout);
        return 0;
    }
    return malloc(size);
}

static int ***allocate_3d_array(int no1, int ****a)
{
    int ***d0 = (int***)xmalloc(no1 * sizeof(int**));
    int **d1 = (int **)xmalloc(no1 * no1 * sizeof(int *));
    int *d2 = (int *)xmalloc(no1 * no1  * 2 * sizeof(int));

    if (d0 == 0 || d1 == 0 || d2 == 0)
    {
        free(d0);
        free(d1);
        free(d2);
        *a = 0;
        return 0;
    }

    for (int l = 0; l < no1; l++)
    {
        d0[l] = &d1[l * no1];
        for (int h = 0; h < no1; h++)
        {
            d0[l][h] = &d2[(l * no1 + h) * 2];
            for (int k = 0; k < 2; k++)
                d0[l][h][k] = l * 10000 + h * 100 + k;
        }
    }

    *a = d0;
    return *a;
}

static void destroy_3d_array(int ***a)
{
    if (a != 0)
    {
        free(a[0][0]);
        free(a[0]);
        free(a);
    }
}

static void test_allocation(int no1)
{
    int ***a = 0;
    int ***b = allocate_3d_array(no1, &a);
    const char *pad[] = { "  ", "\n" };
    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("Oops: a[%d][%d][%d] = %.6d%s", l, h, k, a[l][h][k], pad[k]);
                }
            }
        }
    }

    destroy_3d_array(a);
}

int main(int argc, char **argv)
{
    int no1 = 5;
    int fail_limit = 4;

    if (argc == 2)
        fail_limit = atoi(argv[1]);

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

    return 0;
}

This has a clean bill of health with GCC 4.9.1 on Mac OS X 10.10.1, checked with valgrind version valgrind-3.11.0.SVN (built from an SVN tree with some necessary fixes for Mac OS X, but not enough suppressions).

The diagnostic print (starting with 'Oops') was triggered while I developed the answer; I had my pointer calculations wrong at the time.

这篇关于在3D阵列内存分配分段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆