Объявление двух больших 2-мерных массивов дает ошибку сегментации - PullRequest
0 голосов
/ 17 июня 2010

Я пытаюсь объявить и выделить память для двух 2-мерных массивов. Однако при попытке присвоить значения itemFeatureQ [39] [16816] я получаю хранилище сегментации. Я не могу этого понять, так как у меня 2 ГБ оперативной памяти и только 19 МБ в куче. Вот код:

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 ]

1 голос
/ 17 июня 2010

Лучший способ справиться с распределением памяти для 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-массив (но он будет иметь индексы наоборот)

Это будет использовать меньше памяти (не нужно хранить все эти указатели строк) и хранить все вместе

Когда компилятор создает 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;
}
1 голос
/ 17 июня 2010

У вас есть несколько опечаток - изменить:

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

до:

    array[i] = (double*) malloc(columns * sizeof(double));
    if(array[i] == NULL)
0 голосов
/ 21 апреля 2013

При выделении 2d массивов, хороший трюк в том, что вы можете использовать только 2 malloc.

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 массива

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...