C - преобразовать массив элементов в 2-ю матрицу - PullRequest
0 голосов
/ 21 января 2019

Это может быть глупый вопрос, но мне интересно, есть ли эффективный способ сделать это.

Ситуация:

int* array = malloc(n * m * sizeof(int));
//want to convert array into M[n][m]

что я делаю сейчас:

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

Я не думаю, что преобразование должно быть таким сложным. Существует ли простой синтаксис C? Могу ли я объявить extern M[n][m], а затем установить его адрес в массиве?

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

Ответы [ 4 ]

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

Сложная часть объявляет переменную для хранения указателя на выделенный массив;остальное просто - при условии, что у вас есть компилятор C99 или новее.

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

static void print_2dvla(int rows, int cols, int data[rows][cols])
{
    for (int i = 0; i < rows; i++)
    {
        printf("%2d: ", i);
        for (int j = 0; j < cols; j++)
            printf(" %4d", data[i][j]);
        putchar('\n');
    }
}

int main(void)
{
    int m = 10;
    int n = 12;

    int (*M)[m] = malloc(n * m * sizeof(M[0][0]));
    if (M == NULL)
    {
        fprintf(stderr, "Failed to allocate %zu bytes memory\n", n * m * sizeof(M[0][0]));
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
            M[i][j] = (i + 1) * 100 + (j + 1);
    }

    print_2dvla(n, m, M);

    free(M);
    return 0;
}

Пример вывода:

 0:   101  102  103  104  105  106  107  108  109  110
 1:   201  202  203  204  205  206  207  208  209  210
 2:   301  302  303  304  305  306  307  308  309  310
 3:   401  402  403  404  405  406  407  408  409  410
 4:   501  502  503  504  505  506  507  508  509  510
 5:   601  602  603  604  605  606  607  608  609  610
 6:   701  702  703  704  705  706  707  708  709  710
 7:   801  802  803  804  805  806  807  808  809  810
 8:   901  902  903  904  905  906  907  908  909  910
 9:  1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
10:  1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
11:  1201 1202 1203 1204 1205 1206 1207 1208 1209 1210

Строка ключа:

int (*M)[m] = malloc(n * m * sizeof(M[0][0]));

Это говорит о том, что M является указателем на массив int массивов, каждый из которых имеет размерность m.Остальная часть кода просто использует этот массив с обычной двухстрочной нотацией - M[i][j] и т. Д. Он может быть передан в функции.Я не показывал это здесь, но тривиально также поместить код инициализации в функцию, а затем иметь несколько разных размеров матрицы в одной функции.

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

Вы не можете объявить глобальные массивы в C, не указав им определенный числовой размер.Это потому, что глобальные переменные являются статическими, и компилятор не может выделять переменное количество памяти для глобального массива.

В C вы должны помнить, что массив на самом деле является просто указателем.Когда вы спрашиваете int *array = malloc(n * sizeof(int)), вы говорите компилятору, что вам нужно n много 4-байтовых блоков типа int, зарезервированных рядом в памяти, где значение array фактически является указателем напервый 4-байтовый блок.

Когда вы обращаетесь к элементам массива, вы фактически делаете арифметику указателя и разыменовываете указатель, но это скрыто в синтаксисе array[i].Таким образом, когда массив имеет тип int, array[2] переводится как переход в местоположение, указанное указателем массива (то есть головой), теперь перемещается на 2 * 4 байта в памяти и разыменовывает указатель для доступа к целому числу, хранящемуся там.

Так что, когда вы создаете двумерный массив, как вы уже обсуждали, лучшего способа сделать это не существует.Убедитесь, что у вас есть четкое представление о том, что на самом деле вы получаете от компилятора.Указатели (в любом случае на 64-битных машинах) - 8 байтов, а целые - 4 байта.Поэтому, когда вы вызываете int **M = malloc(sizeof(int*) * m, компилятор выделяет вам m блоков шириной 8 байтов каждый, каждый из которых имеет тип int *.

Из других языков программирования кажется очень сложным объявить ссылку на указатель на блок указателей, но получение более высокого уровня представления о массиве и рассмотрение их как набора указателей действительно поможет вамв долгосрочной перспективе.Когда вам нужно передать эти типы данных между функциями, вам нужно иметь четкое представление о том, чем вы на самом деле манипулируете;указатель, значение, указатель на указатель?Это очень поможет вам в отладке кода этих идей, так как очень легко попытаться выполнить вычисления на указателях, а не на значениях.

3 Полезных советов:

  • calloc(n, sizeof(int)) может быть лучше, чем вызов malloc, поскольку calloc автоматически инициализирует ваши записи в ноль, а malloc - нет.
  • при вызове calloc / malloc вы хотите убедиться, что динамическое выделение памяти прошло успешно;если это не удастся, то malloc вернет NULL.
  • Хорошее эмпирическое правило заключается в том, что каждый раз, когда вы вызываете malloc, вы хотите звонить бесплатно, как только закончите с памятью.Это может помочь предотвратить утечки памяти.
0 голосов
/ 21 января 2019

После того, как:

int* array = malloc(n * m * sizeof(int));

Вы можете сделать:

int (*M)[m] = (int(*)[m])array;

, а затем используйте M[1][2], например.

Вы могли бы сделать это в первую очередь:

int (*M)[m] = malloc( n * sizeof *M );
0 голосов
/ 21 января 2019

Использовать массив указателей.

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

int main() 
{ 
    int n = 3, m = 4, i, j, count=0;

    int *array[n];
    for(i=0; i<n; i++)
     array[i] = (int *)malloc(m * sizeof(int));
     if( array[i] == NULL)
     {
        perror("Unable to allocate array");
        exit(1);
     }

    // going to add number to your 2d array.

    for (i = 0; i < n; i++)
      for (j = 0; j < m; j++)
         array[i][j] = ++count;

    for (i=0; i < n; i++)
      for (j=0; j < m; j++)
         printf("%d ", array[i][j]);

      // free memory

      for(i=0; i<n; i++)
         free(array[i]);

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