Как получить двумерный массив в качестве вывода пользовательской функции? - PullRequest
0 голосов
/ 09 января 2019

Я пытаюсь написать пользовательскую функцию, которая принимает некоторые матрицы и переменные в качестве входных данных и дает матрицу в качестве выходных данных. Так что-то вроде этого:

cofactor(int A[100][100], n, r, c){
int B[100][100]
//B becomes the cofactor matrix of A after some operations//
return B;
}

и в своей основной функции я просто хочу написать:

C=cofactor(D, n, r, c);

, чтобы превратить C в матрицу кофактора D.

Но по какой-то причине язык c не поддерживает использование целого 2D-массива в качестве вывода функции. Как я могу обойти это?

Я не хочу хранить весь мусор в основной функции. Я хочу написать отдельную функцию, которая дает мне матрицу в качестве вывода, и просто вызвать эту функцию в моей основной функции.

Ответы [ 2 ]

0 голосов
/ 09 января 2019

Вы правы в том, что C не позволяет нам возвращать массивы из функций. Это одна из областей, где С просто плох, и вы будете выбирать между различными пороками. Наиболее очевидные альтернативы - возвращать указатель массива или указатель void.

  • void следует избегать, поскольку они имеют несуществующий тип безопасности.

    // bad code
    void* cofactor (int A[100][100], int n, size_t r, size_t c)
    
  • Опция указателя массива довольно уродливая, трудно читаемая и обеспечивает размеры фиксированного размера:

    // bad code
    int ( *cofactor (int A[100][100], int n, size_t r, size_t c) )[100][100];
    
  • В качестве альтернативы, уродливой и плохой практикой, является скрытие типа массива за typedef:

    // bad code
    typedef int arr_t [100][100];
    
    arr_t* cofactor(int A[100][100], int n, size_t r, size_t c)
    

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

Здесь некоторые начинают использовать int** в замешательстве. Но int** нельзя использовать для указания на 2D-массив или на первый элемент 2D-массива. Его можно использовать для указания на первый элемент одномерного массива указателей int*, а затем эмулировать что-то, что выглядит как массив, но не ведет себя как один. Это не то, что вы хотите здесь, потому что это медленно и опасно. См. Правильное размещение многомерных массивов .

Вздох. Так что же использовать!


Если вы отбросите требование «function return ing array» (с акцентом на использование return), это станет проще и более гибким. Передача параметров в / из функций в C чаще всего осуществляется через параметры, и большинство надежных API-интерфейсов резервируют возвращаемое значение для типа ошибки, описывающего результат функции.

Большим преимуществом здесь является то, что при передаче массива в качестве параметра мы можем использовать переменные измерения:

void func (size_t r, size_t c, int A[r][c])

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

Самое чистое - это оставить выделение вызывающей стороне. Тогда вы получите

void func (size_t r, size_t c, int A[r][c], int B[r][c])

Из всех обсуждаемых вариантов это единственный симпатичный. Но это не сработает, если функция должна выполнить распределение. Затем мы должны вернуть массив через параметр. И к этому с этим синтаксисом, тоже немного уродливо:

void copy (size_t r, size_t c, int (**B)[r][c], int A[r][c])

Но если мы можем жить с этим странно выглядящим «указателем на массив указателем на массив int[r][c]», то это решает все проблемы. Он может вернуть массив переменной размера из функции вызывающей стороне.

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

void copy (size_t r, size_t c, int (**B)[r][c], int A[r][c])
{
  *B = malloc( sizeof(int[r][c]) );

  int (*b)[c] = **B; // pointer to the first row in an array int[r][c]
  for(size_t i=0; i<r; i++)
  {
    for(size_t j=0; j<c; j++)
    {
      b[i][j] = A[i][j];
    }
  }
}

Или, если хотите:

#include <string.h>

void copy (size_t r, size_t c, int (**B)[r][c], int A[r][c])
{
  *B = malloc( sizeof(int[r][c]) );
  memcpy( *B, A, sizeof(int[r][c]) );  
}

Полный пример:

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

void copy (size_t r, size_t c, int (**B)[r][c], int A[r][c])
{
  *B = malloc( sizeof(int[r][c]) );

  int (*b)[c] = **B; // pointer to the first row in an array int[r][c]
  for(size_t i=0; i<r; i++)
  {
    for(size_t j=0; j<c; j++)
    {
      b[i][j] = A[i][j];
    }
  }
}

int main (void)
{
  int array1[2][3] = { {1,2,3}, {4,5,6} };
  int (*array2)[2][3];

  copy(2, 3, &array2, array1);

  int (*arr)[3] = *array2;  
  for(size_t i=0; i<2; i++)
  {
    for(size_t j=0; j<3; j++)
    {
      printf("%d ", arr[i][j]);
    }
    printf("\n");
  }

  free(array2);
}
0 голосов
/ 09 января 2019

В настоящее время ваш код B выйдет из области видимости и будет уничтожен при выходе из управления cofactor.

Таким образом, используйте указатель на указатель, как показано ниже.

   int **cofactor(int A[100][100], int n, int r, int c){
        int **B = malloc(sizeof(int *)*r);

         for (int i =0;i<r;i++)
           B[i] = malloc(sizeof(int)*c);

          //B becomes the cofactor matrix of A after some operations//
          return B;
    }

И от main.

 int **C=cofactor(D, n, r, c);

Примечание :: NULL проверки не добавляются, и выделенная память должна быть освобождена после завершения обработки.

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