【问题标题】:C - Convert array of elements into 2-d matrixC - 将元素数组转换为二维矩阵
【发布时间】:2019-01-21 02:11:09
【问题描述】:

这可能是一个愚蠢的问题,但我想知道是否有有效的方法来做到这一点。

情况:

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],然后将其地址设置为数组吗?

(为简单起见,省略了示例中的错误处理和内存管理。只需将其视为某个函数的一部分。)

【问题讨论】:

  • 来吧,这是 C,把指针指向你想要的东西
  • @smac89 由于其他原因,我想使用索引 M[a][b] 的语法。
  • @MadPhysicist,我正要发表与上述相同的评论。在这种情况下如何计算:coliru.stacked-crooked.com/a/39e6761edaccd062?这里的大小直到运行时才知道
  • @smac89 与您为任何其他变量计算 i + sp * j 的方式相同。当您说int (*p)[sp] 时,这意味着对于给定的ij,将j 乘以sp,然后再添加到i 并用作偏移量。编译器所做的只是将手动计算的线性偏移量转换为更易于阅读的精美语法。

标签: c arrays


【解决方案1】:

之后:

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

你可以这样做:

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

然后以M[1][2] 为例。

一开始你也可以这样做:

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

【讨论】:

    【解决方案2】:

    棘手的部分是声明变量来保存指向已分配数组的指针;其余的很简单——假设你有 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。其余代码仅使用带有通常的 2 下标表示法的数组 — M[i][j] 等。它可以传递给函数。我这里没有展示,但是也可以将初始化代码放入一个函数中,然后在一个函数中包含几个不同大小的矩阵。

    【讨论】:

      【解决方案3】:

      你不能在 C 中声明全局数组而不给它们一个特定的数字大小。这是因为全局变量是静态的,编译器无法为全局数组分配可变数量的内存。

      在 C 语言中,您必须记住,数组实际上只是一个指针。当您要求 int *array = malloc(n * sizeof(int)) 时,您告诉编译器的是您需要 n 大量的 int 类型的 4 字节块并排保留在内存中,其中 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 时,一旦内存处理完毕,就想调用 free。这有助于防止内存泄漏。

      【讨论】:

      • 我认为 extern 关键字会阻止变量在堆栈上分配内存。此外,如果我将它放在功能块中,它就不会在静态区域中。
      • 认为int *array = malloc(…); 不能是全局变量是可行的,因为在C 中你不能使用函数调用的结果来初始化全局(或静态)变量。
      【解决方案4】:

      使用指针数组。

      #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]);
      
           }
      

      【讨论】:

      • 考虑显示释放分配内存所需的代码。
      • 问题是我最初得到了一个数组(不是指针数组),这不是我想搞砸的。
      • 好的,我释放了内存。
      • 您可以只使用二维数组和元素,然后只需 array[m][n] 并使用 for 循环将元素放入数组中。不需要malloc
      • 虽然是一种很好的通用方法,但通常,根据我有限的经验,两层间接往往比计算线性索引慢一点。鉴于此评论,您不应该对语法有任何问题:*.com/questions/54282732/…