Вопрос о динамическом распределении памяти (на С) - PullRequest
3 голосов
/ 13 июня 2011

Рассмотрим следующие коды:

#include <stdio.h>
#include <malloc.h>

void allocateMatrix(int **m, int l, int c)
{
    int i;

    m = (int**) malloc( sizeof(int*) * l );
    for(i = 0; i < l; i++)
        m[i] = (int*) malloc( sizeof(int) * c );
}

int main()
{
    int **m;
    int l = 10, c = 10;
    allocateMatrix(m, l, c);
    m[0][0] = 9;
    printf("%d", m[0][0]);

    return 0;
}

Приведенный выше код вызовет ошибку выделения памяти и завершится сбоем.

Но приведенный ниже код будет работать правильно, вопрос: ПОЧЕМУ?

#include <stdio.h>
#include <malloc.h>

int** allocateMatrix(int l, int c)
{
    int i;

    int **m = (int**) malloc( sizeof(int*) * l );
    for(i = 0; i < l; i++)
        m[i] = (int*) malloc( sizeof(int) * c );
    return m;
}

int main()
{
    int **m;
    int l = 10, c = 10;
    m = allocateMatrix(l, c);
    m[0][0] = 9;
    printf("%d", m[0][0]);

    return 0;
}

Я не могу понять, почему происходит сбой первого кода, поскольку я просто передаю указатель-указатель m (переменная, которая содержит в памяти первый адрес памяти матрицы) в качестве аргумента.Я не вижу разницы между кодами (на практике).Буду признателен за любое четкое объяснение.

Спасибо, Рафаэль Андреатта

Ответы [ 4 ]

7 голосов
/ 13 июня 2011

В первом примере вы не инициализируете m. Вы просто меняете свою копию. Так что, иначе говоря, звонящий никогда не увидит, что вы сделали с m.

Во втором примере вы выделяете память, а затем возвращаете указатель на нее. Который действителен.

Возможно, вы сможете исправить свой первый пример следующим образом (не проверено, но должно работать):

void allocateMatrix(int ***m, int l, int c)
{
    int i;

    *m = malloc( sizeof(int*) * l );
    for(i = 0; i < l; i++)
        (*m)[i] = malloc( sizeof(int) * c );
}


/* ... */

allocateMatrix(&m, l, c);

EDIT

Мне понадобилось время, но я нашел это. Как обычно C FAQ есть что сказать по этому поводу.

1 голос
/ 13 июня 2011

Это сложный вопрос, и происходит потому, что с:

void allocateMatrix(int **m, int l, int c);

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

Чтобы исправить это, вы можете использовать либо второй случай, либо этот:

void allocateMatrix(int ***m, int l, int c)
{
    int i;
    *m = (int**) malloc( sizeof(int*) * l );
    for(i = 0; i < l; i++)
        (*m)[i] = (int*) malloc( sizeof(int) * c );
}

и передать с &m.

Я также хотел бы отметить, что в C вам, вероятно, лучше не приводить результат malloc, хотя это требуется в C ++. См. этот ответ .

1 голос
/ 13 июня 2011

Функция allocateMatrix получает копию переданной переменной m, а не переменную, которую вы передаете из главной.Таким образом, в первом примере m не инициализируется, и при попытке получить доступ вы получаете ошибку сегментации.

0 голосов
/ 13 июня 2011

Потому что в первом примере переменная m (в основном) не изменилась. Чтобы изменить его, вы должны передать его как ссылку (в C ++) или по указателю (в простом C).

...