Может кто-нибудь объяснить мне, что происходит в этом заявлении? - PullRequest
0 голосов
/ 14 января 2020

В основном я понимаю указатели. Но когда дело доходит до динамического выделения 1010 * для матриц, которые также включают указатели, я теряюсь в процессе. Я хочу знать, как я могу перевести этот сегмент кода, чтобы понять его.

(*a)[i] = (int*)malloc((*m) * sizeof(int));

Функция для чтения матрицы выглядит следующим образом:

void reading(int *n, int *m, int ***a) {
    int i, j;
    printf("n=");
    scanf("%d", &*n);
    printf("m=");
    scanf("%d", &*m);
    (*a) = (int**)malloc((*n) * sizeof(int*));   
    for (i = 0; i < *n; i++)                     
        (*a)[i] = (int*)malloc((*m) * sizeof(int)); 
    for (i = 0; i < *n; i++) {
        for (j = 0; j < *m; j++) {
            printf("a[%d][%d]=", i, j);
            scanf("%d", &(*a)[i][j]);
        }
    }
}

А также что такое значение ***a в декларации. В колледже мне сказали, что первая звездочка обозначает динамическое распределение c, а две другие - из-за того, что используется матрица. Для векторов динамическое c распределение - **v и так далее ... но я не могу объяснить это в своем уме, чтобы понять, что в нем происходит.

Ответы [ 4 ]

1 голос
/ 14 января 2020

Сначала позвольте мне ответить на ваш вопрос об этой строке c:

(*a)[i] = (int*)malloc((*m) * sizeof(int));

Что он делает, так это выделяет массив из ровно *m целых чисел и сохраняет указатель на него в массив *a указателей на int, который ранее был выделен как:

(*a) = (int**)malloc((*n) * sizeof(int*));

Теперь, если все еще неясно, что происходит, переписывание кода более осмысленным образом поможет , Чтобы упростить задачу, вы можете использовать временные переменные для работы и назначать значения указателям, передаваемым в качестве аргументов только в конце функции. Использование более значимых имен также очень помогает.

void read_matrix(int *rows, int *columns, int ***matrix) {
    int i, j, r, c;
    int **mat;

    printf("n = ");
    scanf("%d", &r);

    printf("m = ");
    scanf("%d", &c);

    // Allocate space for a matrix (i.e. an array of r integer pointers).
    mat = malloc(r * sizeof(int*));

    // Allocate space for each row of the matrix (i.e. r arrays of c integers).
    for (i = 0; i < r; i++)
        mat[i] = malloc(c * sizeof(int));

    for (i = 0; i < r; i++) {
        for (j = 0; j < c; j++) {
            printf("a[%d][%d] = ", i, j);
            scanf("%d", &mat[i][j]);
        }
    }

    *rows = r;
    *columns = c;
    *matrix = mat;
}

Поскольку мы теперь перенесли присвоение значений аргументам в конце функции, мы избавились от всех раздражающих операторов разыменования указателя (*), и код выглядит чище.

Вы можете видеть, что то, что раньше было:

(*a)[i] = (int*)malloc((*m) * sizeof(int));

, теперь стало:

mat[i] = malloc(c * sizeof(int));

Что гораздо проще Понимаю. Это место для массива (строки матрицы), содержащего c целых чисел.

То, что раньше было:

(*a) = (int**)malloc((*n) * sizeof(int*));

, теперь стало:

mat = malloc(r * sizeof(int*));

Это выделяет массив из r целочисленных указателей (что означает матрицу из r строк, если каждый указатель указывает на строку).

0 голосов
/ 14 января 2020

int ***a объявляет a указателем на указатель на int. Вызывающий должен иметь свой собственный int ** и передать свой адрес этой функции. Например, вызывающая сторона может определить int **x; и передать &x этой функции для параметра a. Я буду использовать x для ссылки на int **.

(*a) = (int**)malloc((*n) * sizeof(int*));, чтобы указатель вызывающего абонента (x) указывал на пробел для *n указателей на int. Это подготовка к изготовлению матрицы из *n строк - для каждой строки будет выделена память, и у нас будет указатель на эту память, поэтому нам понадобятся n указатели.

Затем эти строки:

for (i = 0; i < *n; i++)                     
    (*a)[i] = (int*)malloc((*m) * sizeof(int));

выделить память для *n строк. Вторая строка выделяет память для массива m int и устанавливает x[i] для указания на первый элемент этой памяти. Обратите внимание, что поскольку a является int ***, *a является int **, а (*a)[i] является int *. Таким образом, *a указывает на массив int * элементов.

Наконец, эти строки:

for (i = 0; i < *n; i++) {
    for (j = 0; j < *m; j++) {
        printf("a[%d][%d]=", i, j);
        scanf("%d", &(*a)[i][j]);
    }
}

устанавливают каждый элемент массива *n на *m: для каждый элемент x[i][j] (именуемый (*a)[i][j], передает адрес элемента (&(*a)[i][j]) - scanf, который должен быть установлен из входного потока.

0 голосов
/ 14 января 2020

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

void get_size(int *n, int *m) {
    printf("n=");
    scanf("%d", n);
    printf("m=");
    scanf("%d", m);
}

int **create_matrix(int n, int m) {
    int **matrix = malloc(n * sizeof(int*));   
    for (int i = 0; i < n; i++)                     
        matrix[i] = malloc(m * sizeof(int)); 
    return matrix;
}

void fill_matrix(int **matrix, int n, int m) {
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            printf("a[%d][%d]=", i, j);
            scanf("%d", [i][j]);
        }
    }
}

Отсюда намного проще увидеть, что происходит, с меньшим количеством * с и & с.

Ваша матрица реализована в виде массива массивов, поэтому int **matrix = malloc(n * sizeof(int*)); выделяет память для внешнего массива, а matrix[i] = malloc(m * sizeof(int)); выделяет память для каждого из внутренних массивы.

0 голосов
/ 14 января 2020

Вы не показываете, как вызывается эта функция, но, вероятно, она выглядит примерно так:

int n, m;
int **matrix;
reading(&n, &m, &matrix);

Так что в этот контекст, matrix определяется как указатель -в-указатель. Он может содержать адрес первого элемента массива int *, каждый из которых может содержать адрес первого элемента массива int.

Когда &matrix затем передается в эта функция, у вас есть указатель на указатель на указатель, который является аргументом a из reading. В этом контексте a содержит указатель на один int **, в частности matrix в вызывающей функции. Разыменовывая a в reading, вы фактически получаете доступ к matrix в вызывающей функции.

Так что теперь перейдем к этой строке:

(*a) = (int**)malloc((*n) * sizeof(int*));

Это выделяет место для массив *n int * и присваивает его *a, (т.е. matrix в вызывающей функции. Итак, теперь у вас есть массив int *. Теперь для этого:

for (i = 0; i < *n; i++)                     
    (*a)[i] = (int*)malloc((*m) * sizeof(int)); 

Это перебирает элементы массива int * и присваивает каждому указатель на блок памяти, достаточно большой для *m int.

Так что теперь у вас фактически есть двумерный массив int Однако обратите внимание, что это не то же самое, что фактический двумерный массив int, который будет объявлен как int arr[n][m].

...