Выделение памяти для матрицы в C - PullRequest
8 голосов
/ 15 апреля 2010

Почему следующий код приводит к ошибке сегментации? (Я пытаюсь создать две матрицы одинакового размера, одну со статическим, а другую с динамическим размещением)

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

//Segmentation fault!
int main(){
    #define X 5000
    #define Y 6000

    int i;
    int a[X][Y];

    int** b = (int**) malloc(sizeof(int*) * X);
    for(i=0; i<X; i++){
        b[i] = malloc (sizeof(int) * Y);
    }
}

Как ни странно, если я закомментирую одно из определений матрицы, код работает нормально. Как это:

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

//No Segmentation fault!
int main(){
    #define X 5000
    #define Y 6000

    int i;
    //int a[X][Y];

    int** b = (int**) malloc(sizeof(int*) * X);
    for(i=0; i<X; i++){
        b[i] = malloc (sizeof(int) * Y);
    }
}

или

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

//No Segmentation fault!
int main(){
    #define X 5000
    #define Y 6000

    int i;
    int a[X][Y];

    //int** b = (int**) malloc(sizeof(int*) * X);
    //for(i=0; i<X; i++){
    //  b[i] = malloc (sizeof(int) * Y);
    //}
}

Я использую gcc в Linux на 32-битной машине.

Редактировать: Проверка успешности malloc ():

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

//No Segmentation fault!
int main(){
    #define X 5000
    #define Y 6000

    int i;
    int a[X][Y];

    int* tmp;
    int** b = (int**) malloc(sizeof(int*) * X);
    if(!b){
        printf("Error on first malloc.\n");
    }
    else{
        for(i=0; i<X; i++){          
            tmp = malloc (sizeof(int) * Y);
            if(tmp)
               b[i] = tmp;
            else{
               printf("Error on second malloc, i=%d.\n", i);
               return;
            }
        }
    }    
}

Ничего не распечатывается, когда я запускаю его (конечно, ожидаю "Ошибка сегментации")

Ответы [ 8 ]

6 голосов
/ 15 апреля 2010

Ваша переменная a требует в 32-разрядной системе 5000 *6000* 4 = 120 МБ стекового пространства. Возможно, что это нарушает некоторый предел, что вызывает ошибку сегментации.

Кроме того, конечно, возможно, что в какой-то момент произойдет сбой malloc(), что может привести к разыменованию указателя NULL.

2 голосов
/ 15 апреля 2010

Вы получаете ошибку сегментации, которая означает, что ваша программа пытается получить доступ к адресу памяти, который не был присвоен ее процессу. Массив a является локальной переменной и, таким образом, выделяет память из стека. Как указано unwind, a требует 120 Мбайт памяти. Это почти наверняка больше, чем пространство стека, выделенное ОС для вашего процесса. Как только цикл for выходит из конца стека, вы получаете ошибку сегментации.

В Linux размер стека контролируется ОС, а не компилятором, поэтому попробуйте следующее: -

$ ulimit -a

В ответе вы должны увидеть строку примерно так: -

stack size (kbytes)            (-s)  10240

Это означает, что каждый процесс получает 10 Мбайт памяти, что недостаточно для вашего большого массива.

Вы можете настроить размер стека с помощью команды ulimit -s <stack size>, но я подозреваю, что он не позволит вам выбрать размер стека 120 Мбайт!

Самое простое решение - сделать a глобальной переменной вместо локальной.

2 голосов
/ 15 апреля 2010

Попробуйте увеличить ограничения кучи и стека в GCC:

gcc -Wl,--stack=xxxxx -Wl,--heap=yyyyy
1 голос
/ 15 апреля 2010

Возможно, компилятор просто изменяет указатель стека на какое-то большое значение, но никогда не использует его, и, следовательно, никогда не вызывает нарушения доступа к памяти.

Попробуйте инициализировать все элементы A в третьем примере? Ваш первый пример пытается выделить B после A в стеке, и доступ к стеку с таким высоким уровнем (при первом назначении для B) может быть причиной ошибки.

1 голос
/ 15 апреля 2010

Переполнение стека (насколько это уместно!) Может привести к ошибке сегментации, которая, как вам кажется, вы видите здесь.

В вашем третьем случае указатель стека перемещается на недопустимый адрес, но не используется ни для чего, поскольку программа затем завершается. Если вы ставите какую-либо операцию после выделения стека, вы должны получить ошибку сегмента.

1 голос
/ 15 апреля 2010

Это значительные ассигнования. Вы пробовали проверить, чтобы убедиться, что malloc () успешно?

Вы можете использовать malloc () для всех ваших массивов и проверять, чтобы каждый раз он выполнялся успешно.

0 голосов
/ 15 апреля 2010

Обе матрицы не вписываются в пределы вашей памяти. Вы можете выделить только один за раз.

Если вы определяете Y как 3000 вместо 6000, ваша программа не должна выпускать segfault.

0 голосов
/ 15 апреля 2010

Ваш третий код тоже не работает (по крайней мере, в моей системе).

Попробуйте выделить память для массива a в куче (когда размеры большие).

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