声明两个大的2d阵列会产生分段错误

时间:2010-06-17 15:26:51

标签: c arrays

我正在尝试为两个2d阵列声明和分配内存。但是,当尝试为itemFeatureQ [39] [16816]分配值时,我得到了一个分段库。我无法理解,因为我有2GB的RAM并且堆上只使用了19MB。这是代码;

double** reserveMemory(int rows, int columns)
{
    double **array;
    int i;
    array = (double**) malloc(rows * sizeof(double *));
    if(array == NULL)
    {
        fprintf(stderr, "out of memory\n");
        return NULL;
    }
    for(i = 0; i < rows; i++)
    {
        array[i] = (double*) malloc(columns * sizeof(double *));
        if(array == NULL)
        {
            fprintf(stderr, "out of memory\n");
            return NULL;
        }
    }

    return array;

}

void populateUserFeatureP(double **userFeatureP)
{
    int x,y;

    for(x = 0; x < CUSTOMERS; x++)
    {
        for(y = 0; y < FEATURES; y++)
        {
            userFeatureP[x][y] = 0;
        }
    }
}

void populateItemFeatureQ(double **itemFeatureQ)
{
    int x,y;

    for(x = 0; x < FEATURES; x++)
    {
        for(y = 0; y < MOVIES; y++)
        {
            printf("(%d,%d)\n", x, y);
            itemFeatureQ[x][y] = 0;
        }
    }
}

int main(int argc, char *argv[]){

    double **userFeatureP = reserveMemory(480189, 40);
    double **itemFeatureQ = reserveMemory(40, 17770);

    populateItemFeatureQ(itemFeatureQ);
    populateUserFeatureP(userFeatureP);

    return 0;
}

3 个答案:

答案 0 :(得分:1)

你有一些错别字 - 改变:

    array[i] = (double*) malloc(columns * sizeof(double *));
    if(array == NULL)

为:

    array[i] = (double*) malloc(columns * sizeof(double));
    if(array[i] == NULL)

答案 1 :(得分:1)

处理2D内存的内存分配的更好方法是,如果它很大,就是这样做:

// small fix to this, added pointer de-reference
// if you iterate over x in your outer loop you should 
// change the index part to (a)->h*(x) + (y)
// but only do one or the other
#define IDX_DBL2D(a, x, y) (*((a)->d[(a)->w*(y) + (x)]))

struct dbl2d {int w,h; double[] d; };

struct dbl2d *alloc_2d_dbl(int w, int h) {
    struct dbl2d *r = malloc(sizeof(struct dbl2d) + sizeof(double)*w*h);
    r->w = w, r->h = h;
    return r;
}

这有点像编译器在声明一个二维数组时正在做的事情(但它会以另一种方式使用索引)但是

这将使用更少的内存(不需要存储所有那些行指针)并将所有内容保存在一起

当编译器创建一个固定大小的2d数组时,它知道每种方式有多大,所以如果你写bar = foo[x][y];而foo是nxm,那么编译器会把它变成bar = *(foo + x*m + y)但是这只适用于东西编译器知道你的数组是什么形状的,所以我上面定义的基本上是一个带有它的维度的数组。

索引计算有效,因为如果你认为foo是一个数组数组,每一行都有sizeof(*foo)*width的大小(取决于你把x或y作为第一个坐标的天气,这里我使用x,因为我是用于图像,这是在那里使用的惯例)所以如果你将你的y坐标乘以一行中的元素数量,你跳过'y'行,那么你可以通过添加x来获得行内的元素。

用法示例:

void populateUserFeatureP(struct dbl2d *userFeatureP)
{
    int x,y;

    for(x = 0; x < CUSTOMERS; x++)
    {
        for(y = 0; y < FEATURES; y++)
        {
            IDX_DBL2D(userFeatureP, x, y) = 0;
        }
    }
}

void populateItemFeatureQ(struct dbl2d *itemFeatureQ)
{
    int x,y;

    for(x = 0; x < FEATURES; x++)
    {
        for(y = 0; y < MOVIES; y++)
        {
            printf("(%d,%d)\n", x, y);
            IDX_DBL2D(itemFeatureQ, x, y) = 0;
        }
    }
}

int main(int argc, char *argv[]){

    struct dbl2d *userFeatureP = alloc_2d_dbl(480189, 40);
    struct dbl2d *itemFeatureQ = alloc_2d_dbl(40, 17770);

    populateItemFeatureQ(itemFeatureQ);
    populateUserFeatureP(userFeatureP);

    return 0;
}

答案 2 :(得分:0)

分配2d数组时,一个很好的技巧是你只能使用2个mallocs。

double** reserveMemory(int rows, int columns) {
    double **array, *data;
    int i;
    array = (double**) malloc(rows * sizeof(double *));
    data = (double*) malloc(rows * columns * sizeof(double));
    for(i = 0; i < rows; i++){
       array[i] = data + i * columns;
    }    
    return array;    
}

这也可用于将2d数组视为1d数组