从问题修改代码
您的代码有:
for(i=0;i<5;i++)
for(j=0;j<4;i++)
几次。第二个循环应该递增 j,而不是 i。复制粘贴时要非常小心。
此代码不会崩溃(但会泄漏)。
#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]);
}
以前的答案
由于您没有向我们展示大部分代码,因此很难预测您如何处理不当,但同样,由于您正在获得核心转储,因此您一定是处理不当。
这里有一些工作代码——没有检查,valgrind
因为它不适用于 Mac OS X 10.8——似乎可以工作。分配失败的错误恢复不完整,销毁完全分配数组的功能也缺失。
#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;
}
样本输出:
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
将此与您所拥有的进行比较。您可以添加更多诊断打印消息。如果这没有足够的帮助,请创建一个与此类似的 SSCCE(简短、自包含、正确的示例),以在没有任何无关材料的情况下演示代码中的问题。
代码版本 2
这是一个更复杂的代码版本,它模拟 N 次分配后的内存分配失败(以及一个测试工具,它使用从 0 到 35 的每个 N 值运行它,其中实际上只有 30 个数组分配。它还包括释放数组的代码(类似于,但不同于harpun编辑到我的答案中的代码。最后与包含 PID 的行的交互意味着我可以ps
在另一个终端窗口中检查内存使用情况。(否则,我不喜欢做那种事情的程序——我想我应该ps
从我的程序中通过运行system()
,但我感觉很懒。)
#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;
}
注意记忆恢复是多么痛苦。和以前一样,没有用 进行测试valgrind
,但我从harpun对以前版本的测试中得到保证。
此代码与版本 2 中的测试非常相似。它修复了叶级分配中内存分配失败时清理中的内存泄漏。程序不再提示输入(更可取);它需要一个可选的单个参数,即失败后的分配次数。测试valgrind
表明,参数 0-6 没有泄漏,但参数 7 有泄漏。很快就发现了问题并加以解决。(当机器valgrind
可用时更容易运行——它在长周末断电以进行一般现场供电升级。)
#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;
}
版本 4 — 更少的内存分配
2014-12-20 更新
上面的代码进行了大量的内存分配,这使得释放和错误恢复变得复杂。这是一个替代版本,它只进行 3 次分配,一个用于指向指针的指针向量,一个用于指针数组,一个用于整数数组。然后它将指针设置为指向内存中的正确位置。
#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;
}
这与 Mac OS X 10.10.1 上的 GCC 4.9.1 有一个干净的健康状况,检查valgrind
版本 valgrind-3.11.0.SVN(从 SVN 树构建,对 Mac OS X 进行了一些必要的修复,但没有足够的抑制) .
在我开发答案时触发了诊断打印(以“糟糕”开头);当时我的指针计算错误。